diff --git a/fs/Makefile b/fs/Makefile index 1fc1c1f352dca7686d66fd67535f4f9c322b280f..37ebe9441fd5ba8c2109766374d957d08646520e 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -3,7 +3,7 @@ LD := ld CCFLAG := -I../include -nostdinc -ffreestanding -Wall -fomit-frame-pointer -fno-stack-protector -fno-pic -c -m32 LDFLAG := -Ttext 0x0 -s --oformat binary -m elf_i386 INCDIR := ../include -OBJS := read_write.o buffer.o super.o open.o file_table.o inode.o namei.o fcntl.o char_dev.o +OBJS := read_write.o buffer.o super.o open.o file_table.o inode.o namei.o fcntl.o char_dev.o bitmap.o fs.o : $(OBJS) $(LD) -m elf_i386 -r -o $@ $^ @@ -35,6 +35,9 @@ fcntl.o : fcntl.c char_dev.o : char_dev.c $(GCC) $(CCFLAG) -o $@ $< +bitmap.o : bitmap.c + $(GCC) $(CCFLAG) -o $@ $< + clean : rm *.o diff --git a/fs/bitmap.c b/fs/bitmap.c new file mode 100644 index 0000000000000000000000000000000000000000..c584589c8b555893ac55e7eae162e64150a5a029 --- /dev/null +++ b/fs/bitmap.c @@ -0,0 +1,81 @@ +#include + +#include +#include + +#define clear_block(addr) \ + __asm__("cld\n\t" \ + "rep\n\t" \ + "stosl" \ + ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):) + + +#define set_bit(nr,addr) ({\ + register int res __asm__("ax"); \ + __asm__ __volatile__("btsl %2,%3\n\tsetb %%al": \ + "=a" (res):"a" (0),"r" (nr),"m" (*(addr))); \ + res;}) + +#define clear_bit(nr, addr) ({\ + register int res __asm__("ax"); \ + __asm__ __volatile__("btrl %2,%3\n\tsetnb %%al": \ + "=a" (res):"a" (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"); \ + __res;}) + + + +int new_block(int dev) { + struct buffer_head * bh; + struct super_block * sb; + int i, j; + + if (!(sb = get_super(dev))) { + printk("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)) + printk("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))) + printk("new_block: cannot get block"); + if (bh->b_count != 1) + printk("new block: count is != 1"); + clear_block(bh->b_data); + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse(bh); + return j; +} diff --git a/fs/inode.c b/fs/inode.c index 9dbd8647a4289c531c93e270743793e665e6815a..f62033cf8b69c9280ec079bdfced93de6e94289d 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -35,6 +35,87 @@ static inline void unlock_inode(struct m_inode * inode) { wake_up(&inode->i_wait); } +static int _bmap(struct m_inode * inode,int block,int create) { + struct buffer_head * bh; + int i; + + if (block<0) { + printk("_bmap: block<0"); + } + + if (block >= 7+512+512*512) { + printk("_bmap: block>big"); + } + + if (block < 7) { + if (create && !inode->i_zone[block]) { + if (inode->i_zone[block] = new_block(inode->i_dev)) { + inode->i_dirt = 1; + } + return inode->i_zone[block]; + } + } + block -= 7; + if (block < 512) { + if (create && !inode->i_zone[7]) { + if (inode->i_zone[7]=new_block(inode->i_dev)) { + inode->i_dirt=1; + } + } + if (!inode->i_zone[7]) + return 0; + if (!(bh = bread(inode->i_dev,inode->i_zone[7]))) + return 0; + i = ((unsigned short *) (bh->b_data))[block]; + if (create && !i) { + if (i = new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block]=i; + bh->b_dirt = 1; + } + } + + brelse(bh); + return i; + } + + block -= 512; + if (create && !inode->i_zone[8]) { + if (inode->i_zone[8]=new_block(inode->i_dev)) { + inode->i_dirt=1; + } + } + if (!inode->i_zone[8]) + return 0; + if (!(bh = bread(inode->i_dev,inode->i_zone[8]))) + return 0; + i = ((unsigned short *) (bh->b_data))[block >> 9]; + if (create && !i) { + if (i = new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block >> 9]=i; + bh->b_dirt = 1; + } + } + brelse(bh); + + if (!i) + return 0; + if (!(bh = bread(inode->i_dev,i))) + return 0; + i = ((unsigned short *)bh->b_data)[block & 511]; + if (create && !i) { + if (i = new_block(inode->i_dev)) { + ((unsigned short *) (bh->b_data))[block & 511] = i; + bh->b_dirt = 1; + } + } + brelse(bh); + return i; +} + +int bmap(struct m_inode * inode,int block) { + return _bmap(inode,block,0); +} + struct m_inode * get_empty_inode() { struct m_inode * inode; static struct m_inode * last_inode = inode_table; diff --git a/fs/namei.c b/fs/namei.c index f8a513dd3885ccbcd26664b2f6f0e630857ef7db..ea28f9c184e35d0ef5d7c726966c5c50b2acfaae 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -42,7 +42,7 @@ static struct buffer_head * find_entry(struct m_inode ** dir, int block,i; struct buffer_head * bh; struct dir_entry * de; - struct super_block * psb; + struct super_block * sb; entries = (*dir)->i_size / (sizeof (struct dir_entry)); *res_dir = NULL; @@ -50,6 +50,14 @@ static struct buffer_head * find_entry(struct m_inode ** dir, if (namelen==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') { if ((*dir) == current->root) namelen=1; + else if ((*dir)->i_num == ROOT_INO) { + sb=get_super((*dir)->i_dev); + if (sb->s_imount) { + //iput(*dir); + (*dir) = sb->s_imount; + (*dir)->i_count++; + } + } } if (!(block = (*dir)->i_zone[0])) @@ -61,6 +69,16 @@ static struct buffer_head * find_entry(struct m_inode ** dir, i = 0; de = (struct dir_entry *) bh->b_data; while (i < entries) { + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; + if (!(block = bmap(*dir,i/DIR_ENTRIES_PER_BLOCK)) || + !(bh = bread((*dir)->i_dev,block))) { + i += DIR_ENTRIES_PER_BLOCK; + continue; + } + de = (struct dir_entry *) bh->b_data; + } if (match(namelen,name,de)) { *res_dir = de; return bh; diff --git a/include/linux/fs.h b/include/linux/fs.h index 7a3876a924c5fd8efb3ecbf0dc89ed5771d5cd33..575d4cf6706e01c203fb6f1fbc1113f8ae6799ff 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -142,6 +142,8 @@ extern struct buffer_head * bread(int dev,int block); extern int open_namei(const char * pathname, int flag, int mode, struct m_inode ** res_inode); +extern struct super_block * get_super(int dev); + extern int ROOT_DEV; void mount_root();