linux源代码剖析之三fs

fs
bitmap.c
/* bitmap.c contains the code that handles the inode and block bitmaps */
#include <string.h>

#include <linux/sched.h>
#include <linux/kernel.h>

#define clear_block(addr)
asm(“cld\n\t”
“rep\n\t”
“stosl”
::“a” (0),“c” (BLOCK_SIZE/4),“D” ((long) (addr)):“cx”,“di”)

#define set_bit(nr,addr) ({
register int res asm(“ax”);
asm(“btsl %2,%3\n\tsetb %%al”:"=a" (res):“0” (0),“r” (nr),“m” (*(addr)));
res;})

#define clear_bit(nr,addr) ({
register int res asm(“ax”);
asm(“btrl %2,%3\n\tsetnb %%al”:"=a" (res):“0” (0),“r” (nr),“m” (*(addr)));
res;})

#define find_first_zero(addr) ({
int __res;
asm(“cld\n”
“1:\tlodsl\n\t”
“notl %%eax\n\t”
“bsfl %%eax,%%edx\n\t”
“je 2f\n\t”
“addl %%edx,%%ecx\n\t”
“jmp 3f\n”
“2:\taddl $32,%%ecx\n\t”
“cmpl $8192,%%ecx\n\t”
“jl 1b\n”
“3:”
:"=c" (__res):“c” (0),“S” (addr):“ax”,“dx”,“si”);
__res;})

void free_block(int dev, int block)
{
struct super_block * sb;
struct buffer_head * bh;

if (!(sb = get_super(dev)))
	panic("trying to free block on nonexistent device");
if (block < sb->s_firstdatazone || block >= sb->s_nzones)
	panic("trying to free block not in datazone");
bh = get_hash_table(dev,block);
if (bh) {
	if (bh->b_count != 1) {
		printk("trying to free block (%04x:%d), count=%d\n",
			dev,block,bh->b_count);
		return;
	}
	bh->b_dirt=0;
	bh->b_uptodate=0;
	brelse(bh);
}
block -= sb->s_firstdatazone - 1 ;
if (clear_bit(block&8191,sb->s_zmap[block/8192]->b_data)) {
	printk("block (%04x:%d) ",dev,block+sb->s_firstdatazone-1);
	panic("free_block: bit already cleared");
}
sb->s_zmap[block/8192]->b_dirt = 1;

}

int new_block(int dev)
{
struct buffer_head * bh;
struct super_block * sb;
int i,j;

if (!(sb = get_super(dev)))
	panic("trying to get new block from nonexistant device");
j = 8192;
for (i=0 ; i<8 ; i++)
	if (bh=sb->s_zmap[i])
		if ((j=find_first_zero(bh->b_data))<8192)
			break;
if (i>=8 || !bh || j>=8192)
	return 0;
if (set_bit(j,bh->b_data))
	panic("new_block: bit already set");
bh->b_dirt = 1;
j += i*8192 + sb->s_firstdatazone-1;
if (j >= sb->s_nzones)
	return 0;
if (!(bh=getblk(dev,j)))
	panic("new_block: cannot get block");
if (bh->b_count != 1)
	panic("new block: count is != 1");
clear_block(bh->b_data);
bh->b_uptodate = 1;
bh->b_dirt = 1;
brelse(bh);
return j;

}

void free_inode(struct m_inode * inode)
{
struct super_block * sb;
struct buffer_head * bh;

if (!inode)
	return;
if (!inode->i_dev) {
	memset(inode,0,sizeof(*inode));
	return;
}
if (inode->i_count>1) {
	printk("trying to free inode with count=%d\n",inode->i_count);
	panic("free_inode");
}
if (inode->i_nlinks)
	panic("trying to free inode with links");
if (!(sb = get_super(inode->i_dev)))
	panic("trying to free inode on nonexistent device");
if (inode->i_num < 1 || inode->i_num > sb->s_ninodes)
	panic("trying to free inode 0 or nonexistant inode");
if (!(bh=sb->s_imap[inode->i_num>>13]))
	panic("nonexistent imap in superblock");
if (clear_bit(inode->i_num&8191,bh->b_data))
	panic("free_inode: bit already cleared");
bh->b_dirt = 1;
memset(inode,0,sizeof(*inode));

}

struct m_inode * new_inode(int dev)
{
struct m_inode * inode;
struct super_block * sb;
struct buffer_head * bh;
int i,j;

if (!(inode=get_empty_inode()))
	return NULL;
if (!(sb = get_super(dev)))
	panic("new_inode with unknown device");
j = 8192;
for (i=0 ; i<8 ; i++)
	if (bh=sb->s_imap[i])
		if ((j=find_first_zero(bh->b_data))<8192)
			break;
if (!bh || j >= 8192 || j+i*8192 > sb->s_ninodes) {
	iput(inode);
	return NULL;
}
if (set_bit(j,bh->b_data))
	panic("new_inode: bit already set");
bh->b_dirt = 1;
inode->i_count=1;
inode->i_nlinks=1;
inode->i_dev=dev;
inode->i_dirt=1;
inode->i_num = j + i*8192;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
return inode;

}



block_dev.c
#include <errno.h>

#include <linux/fs.h>
#include <linux/kernel.h>
#include <asm/segment.h>

#define NR_BLK_DEV ((sizeof (rd_blk))/(sizeof (rd_blk[0])))

int block_write(int dev, long * pos, char * buf, int count)
{
int block = *pos / BLOCK_SIZE;
int offset = *pos % BLOCK_SIZE;
int chars;
int written = 0;
struct buffer_head * bh;
register char * p;

while (count>0) {
	bh = bread(dev,block);
	if (!bh)
		return written?written:-EIO;
	chars = (count<BLOCK_SIZE) ? count : BLOCK_SIZE;
	p = offset + bh->b_data;
	offset = 0;
	block++;
	*pos += chars;
	written += chars;
	count -= chars;
	while (chars-->0)
		*(p++) = get_fs_byte(buf++);
	bh->b_dirt = 1;
	brelse(bh);
}
return written;

}

int block_read(int dev, unsigned long * pos, char * buf, int count)
{
int block = *pos / BLOCK_SIZE;
int offset = *pos % BLOCK_SIZE;
int chars;
int read = 0;
struct buffer_head * bh;
register char * p;

while (count>0) {
	bh = bread(dev,block);
	if (!bh)
		return read?read:-EIO;
	chars = (count<BLOCK_SIZE) ? count : BLOCK_SIZE;
	p = offset + bh->b_data;
	offset = 0;
	block++;
	*pos += chars;
	read += chars;
	count -= chars;
	while (chars-->0)
		put_fs_byte(*(p++),buf++);
	bh->b_dirt = 1;
	brelse(bh);
}
return read;

}

extern void rw_hd(int rw, struct buffer_head * bh);

typedef void (*blk_fn)(int rw, struct buffer_head * bh);

static blk_fn rd_blk[]={
NULL, /* nodev /
NULL, /
dev mem /
NULL, /
dev fd /
rw_hd, /
dev hd /
NULL, /
dev ttyx /
NULL, /
dev tty /
NULL}; /
dev lp */

void ll_rw_block(int rw, struct buffer_head * bh)
{
blk_fn blk_addr;
unsigned int major;

if ((major=MAJOR(bh->b_dev)) >= NR_BLK_DEV || !(blk_addr=rd_blk[major]))
	panic("Trying to read nonexistent block-device");
blk_addr(rw, bh);

}



buffer.c
/*

  • ‘buffer.c’ implements the buffer-cache functions. Race-conditions have
  • been avoided by NEVER letting a interrupt change a buffer (except for the
  • data, of course), but instead letting the caller do it. NOTE! As interrupts
  • can wake up a caller, some cli-sti sequences are needed to check for
  • sleep-on-calls. These should be extremely quick, though (I hope).
    */

#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/system.h>

#if (BUFFER_END & 0xfff)
#error “Bad BUFFER_END value”
#endif

#if (BUFFER_END > 0xA0000 && BUFFER_END <= 0x100000)
#error “Bad BUFFER_END value”
#endif

extern int end;
struct buffer_head * start_buffer = (struct buffer_head *) &end;
struct buffer_head * hash_table[NR_HASH];
static struct buffer_head * free_list;
static struct task_struct * buffer_wait = NULL;
int NR_BUFFERS = 0;

static inline void wait_on_buffer(struct buffer_head * bh)
{
cli();
while (bh->b_lock)
sleep_on(&bh->b_wait);
sti();
}

int sys_sync(void)
{
int i;
struct buffer_head * bh;

sync_inodes();		/* write out inodes into buffers */
bh = start_buffer;
for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
	wait_on_buffer(bh);
	if (bh->b_dirt)
		ll_rw_block(WRITE,bh);
}
return 0;

}

static int sync_dev(int dev)
{
int i;
struct buffer_head * bh;

bh = start_buffer;
for (i=0 ; i<NR_BUFFERS ; i++,bh++) {
	if (bh->b_dev != dev)
		continue;
	wait_on_buffer(bh);
	if (bh->b_dirt)
		ll_rw_block(WRITE,bh);
}
return 0;

}

#define _hashfn(dev,block) (((unsigned)(dev^block))%NR_HASH)
#define hash(dev,block) hash_table[_hashfn(dev,block)]

static inline void remove_from_queues(struct buffer_head * bh)
{
/* remove from hash-queue /
if (bh->b_next)
bh->b_next->b_prev = bh->b_prev;
if (bh->b_prev)
bh->b_prev->b_next = bh->b_next;
if (hash(bh->b_dev,bh->b_blocknr) == bh)
hash(bh->b_dev,bh->b_blocknr) = bh->b_next;
/
remove from free list */
if (!(bh->b_prev_free) || !(bh->b_next_free))
panic(“Free block list corrupted”);
bh->b_prev_free->b_next_free = bh->b_next_free;
bh->b_next_free->b_prev_free = bh->b_prev_free;
if (free_list == bh)
free_list = bh->b_next_free;
}

static inline void insert_into_queues(struct buffer_head * bh)
{
/* put at end of free list /
bh->b_next_free = free_list;
bh->b_prev_free = free_list->b_prev_free;
free_list->b_prev_free->b_next_free = bh;
free_list->b_prev_free = bh;
/
put the buffer in new hash-queue if it has a device */
bh->b_prev = NULL;
bh->b_next = NULL;
if (!bh->b_dev)
return;
bh->b_next = hash(bh->b_dev,bh->b_blocknr);
hash(bh->b_dev,bh->b_blocknr) = bh;
bh->b_next->b_prev = bh;
}

static struct buffer_head * find_buffer(int dev, int block)
{
struct buffer_head * tmp;

for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next)
	if (tmp->b_dev==dev && tmp->b_blocknr==block)
		return tmp;
return NULL;

}

/*

  • Why like this, I hear you say… The reason is race-conditions.
  • As we don’t lock buffers (unless we are readint them, that is),
  • something might happen to it while we sleep (ie a read-error
  • will force it bad). This shouldn’t really happen currently, but
  • the code is ready.
    */
    struct buffer_head * get_hash_table(int dev, int block)
    {
    struct buffer_head * bh;

repeat:
if (!(bh=find_buffer(dev,block)))
return NULL;
bh->b_count++;
wait_on_buffer(bh);
if (bh->b_dev != dev || bh->b_blocknr != block) {
brelse(bh);
goto repeat;
}
return bh;
}

/*

  • Ok, this is getblk, and it isn’t very clear, again to hinder
  • race-conditions. Most of the code is seldom used, (ie repeating),
  • so it should be much more efficient than it looks.
    */
    struct buffer_head * getblk(int dev,int block)
    {
    struct buffer_head * tmp;

repeat:
if (tmp=get_hash_table(dev,block))
return tmp;
tmp = free_list;
do {
if (!tmp->b_count) {
wait_on_buffer(tmp); /* we still have to wait /
if (!tmp->b_count) /
on it, it might be dirty /
break;
}
tmp = tmp->b_next_free;
} while (tmp != free_list || (tmp=NULL));
/
Kids, don’t try THIS at home ^^^^^. Magic /
if (!tmp) {
printk(“Sleeping on free buffer …”);
sleep_on(&buffer_wait);
printk(“ok\n”);
goto repeat;
}
tmp->b_count++;
remove_from_queues(tmp);
/

  • Now, when we know nobody can get to this node (as it’s removed from the
  • free list), we write it out. We can sleep here without fear of race-
  • conditions.
    /
    if (tmp->b_dirt)
    sync_dev(tmp->b_dev);
    /
    update buffer contents /
    tmp->b_dev=dev;
    tmp->b_blocknr=block;
    tmp->b_dirt=0;
    tmp->b_uptodate=0;
    /
    NOTE!! While we possibly slept in sync_dev(), somebody else might have
  • added “this” block already, so check for that. Thank God for goto’s.
    /
    if (find_buffer(dev,block)) {
    tmp->b_dev=0; /
    ok, someone else has beaten us /
    tmp->b_blocknr=0; /
    to it - free this block and /
    tmp->b_count=0; /
    try again /
    insert_into_queues(tmp);
    goto repeat;
    }
    /
    and then insert into correct position */
    insert_into_queues(tmp);
    return tmp;
    }

void brelse(struct buffer_head * buf)
{
if (!buf)
return;
wait_on_buffer(buf);
if (!(buf->b_count–))
panic(“Trying to free free buffer”);
wake_up(&buffer_wait);
}

/*

  • bread() reads a specified block and returns the buffer that contains

  • it. It returns NULL if the block was unreadable.
    */
    struct buffer_head * bread(int dev,int block)
    {
    struct buffer_head * bh;

    if (!(bh=getblk(dev,block)))
    panic(“bread: getblk returned NULL\n”);
    if (bh->b_uptodate)
    return bh;
    ll_rw_block(READ,bh);
    if (bh->b_uptodate)
    return bh;
    brelse(bh);
    return (NULL);
    }

void buffer_init(void)
{
struct buffer_head * h = start_buffer;
void * b = (void *) BUFFER_END;
int i;

while ( (b -= BLOCK_SIZE) >= ((void *) (h+1)) ) {
	h->b_dev = 0;
	h->b_dirt = 0;
	h->b_count = 0;
	h->b_lock = 0;
	h->b_uptodate = 0;
	h->b_wait = NULL;
	h->b_next = NULL;
	h->b_prev = NULL;
	h->b_data = (char *) b;
	h->b_prev_free = h-1;
	h->b_next_free = h+1;
	h++;
	NR_BUFFERS++;
	if (b == (void *) 0x100000)
		b = (void *) 0xA0000;
}
h--;
free_list = start_buffer;
free_list->b_prev_free = h;
h->b_next_free = free_list;
for (i=0;i<NR_HASH;i++)
	hash_table[i]=NULL;

}



char_dev.c
#include <errno.h>

#include <linux/sched.h>
#include <linux/kernel.h>

extern int tty_read(unsigned minor,char * buf,int count);
extern int tty_write(unsigned minor,char * buf,int count);

static int rw_ttyx(int rw,unsigned minor,char * buf,int count);
static int rw_tty(int rw,unsigned minor,char * buf,int count);

typedef (*crw_ptr)(int rw,unsigned minor,char * buf,int count);

#define NRDEVS ((sizeof (crw_table))/(sizeof (crw_ptr)))

static crw_ptr crw_table[]={
NULL, /* nodev /
NULL, /
/dev/mem /
NULL, /
/dev/fd /
NULL, /
/dev/hd /
rw_ttyx, /
/dev/ttyx /
rw_tty, /
/dev/tty /
NULL, /
/dev/lp /
NULL}; /
unnamed pipes */

static int rw_ttyx(int rw,unsigned minor,char * buf,int count)
{
return ((rw==READ)?tty_read(minor,buf,count):
tty_write(minor,buf,count));
}

static int rw_tty(int rw,unsigned minor,char * buf,int count)
{
if (current->tty<0)
return -EPERM;
return rw_ttyx(rw,current->tty,buf,count);
}

int rw_char(int rw,int dev, char * buf, int count)
{
crw_ptr call_addr;

if (MAJOR(dev)>=NRDEVS)
	panic("rw_char: dev>NRDEV");
if (!(call_addr=crw_table[MAJOR(dev)])) {
	printk("dev: %04x\n",dev);
	panic("Trying to r/w from/to nonexistent character device");
}
return call_addr(rw,MINOR(dev),buf,count);

}



exec.c
#include <errno.h>
#include <sys/stat.h>
#include <a.out.h>

#include <linux/fs.h>
#include <

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

低调的小哥哥

你的关注就是我为你服务的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值