diff options
author | Mike Shaver <shaver@ingenia.com> | 1998-05-23 04:48:39 +0000 |
---|---|---|
committer | Mike Shaver <shaver@ingenia.com> | 1998-05-23 04:48:39 +0000 |
commit | 74c548680437147ae09d70e8505c38d9b3eadee5 (patch) | |
tree | 53839b4b36e0d54ded13c2fb23d71f63f6787cc6 /fs/efs | |
parent | b4930b0d404da1157965de172686b7dbf14b5e99 (diff) |
Some (incomplete) EFS fixes: can now walk directory trees, follow symlinks
and read files that don't have indirect extents. Unmounting the EFS
partition causes hangs (deadlock with the locking of the superblock, I
think), and it's nothing resembling fast or clean code. That's for
tomorrow.
Diffstat (limited to 'fs/efs')
-rw-r--r-- | fs/efs/dir.c | 171 | ||||
-rw-r--r-- | fs/efs/inode.c | 11 | ||||
-rw-r--r-- | fs/efs/namei.c | 16 | ||||
-rw-r--r-- | fs/efs/symlink.c | 21 |
4 files changed, 132 insertions, 87 deletions
diff --git a/fs/efs/dir.c b/fs/efs/dir.c index a89dd304e..0fd4f3187 100644 --- a/fs/efs/dir.c +++ b/fs/efs/dir.c @@ -60,78 +60,109 @@ struct inode_operations efs_dir_in_ops = { return - 0 ok, <0 error */ -static int efs_readdir(struct file *filp, - void *dirent, filldir_t filldir) +static int +efs_readdir(struct file *filp, + void *dirent, filldir_t filldir) { - struct inode *inode = filp->f_dentry->d_inode; - struct efs_inode_info *ini = (struct efs_inode_info *)&inode->u.efs_i; - struct buffer_head *bh; - __u8 *rawdirblk; - __u32 iteminode; - __u16 namelen; - __u8 *nameptr; - __u32 numitems; - __u16 itemnum; - __u32 block; - __u16 rawdepos; - - /* some checks */ - if(!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) - return -EBADF; - - /* Warnings */ - if(ini->tot!=1) { - printk("EFS: directory %s has more than one extent.\n", - filp->f_dentry->d_name.name); - printk("EFS: Mike is lazy, so we can't handle this yet. Sorry =(\n"); - return 0; - } - if(inode->i_size & (EFS_BLOCK_SIZE-1)) - printk("efs_readdir: dirsize != blocksize*n\n"); - - /* f_pos contains: dirblock<<BLOCK_SIZE | # of item in dirblock */ - block = filp->f_pos >> EFS_BLOCK_SIZE_BITS; - itemnum = filp->f_pos & 0xff; - - /* We found the last entry -> ready */ - if(block == (inode->i_size>>EFS_BLOCK_SIZE_BITS)) - return 0; - - /* get disc block number from dir block num: 0..i_size/BLOCK_SIZE */ - bh = bread(inode->i_dev,efs_bmap(inode,block),EFS_BLOCK_SIZE); - if(!bh) return 0; - - /* dirblock */ - rawdirblk = (__u8 *)bh->b_data; - /* number of entries stored in this dirblock */ - numitems = rawdirblk[EFS_DB_ENTRIES]; - /* offset in block of #off diritem */ - rawdepos = (__u16)rawdirblk[EFS_DB_FIRST+itemnum]<<1; - - /* diritem first contains the inode number, the namelen and the name */ - iteminode = ConvertLong(rawdirblk,rawdepos); - namelen = (__u16)rawdirblk[rawdepos+EFS_DI_NAMELEN]; - nameptr = rawdirblk + rawdepos + EFS_DI_NAME; - -#ifdef DEBUG_EFS - printk("efs: dir #%d @ %0#3x - inode %lx %s namelen %u\n", - itemnum,rawdepos,iteminode,nameptr,namelen); + struct inode *inode = filp->f_dentry->d_inode; + struct efs_inode_info *ini = (struct efs_inode_info *)&inode->u.efs_i; + struct buffer_head *bh; + struct efs_dirblk *dirblk; + __u32 iteminode; + __u16 namelen; + char *nameptr; + __u16 itemnum; + __u32 block; + int db_offset; + int error = 0; + struct efs_dent *de = NULL; + + /* some checks -- ISDIR should be done by upper layer */ + if(!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) { + printk("EFS: bad inode for readdir!\n"); + return -EBADF; + } + + if(ini->tot!=1) { + printk("EFS: directory %s has more than one extent.\n", + filp->f_dentry->d_name.name); + printk("EFS: Mike is lazy, so we can't handle this yet. Sorry =(\n"); + return -EBADF; + } + + /* Warnings */ + if(inode->i_size & (EFS_BLOCK_SIZE-1)) + printk("efs_readdir: dirsize != blocksize*n\n"); + + /* f_pos contains: dirblock<<BLOCK_SIZE | # of item in dirblock */ + block = filp->f_pos >> EFS_BLOCK_SIZE_BITS; + itemnum = filp->f_pos & 0xff; + + /* We found the last entry -> ready */ + if(block == (inode->i_size>>EFS_BLOCK_SIZE_BITS)) { + printk("EFS: read all entries -- done\n"); + return 0; + } + + /* get disc block number from dir block num: 0..i_size/BLOCK_SIZE */ + bh = bread(inode->i_dev,efs_bmap(inode,block),EFS_BLOCK_SIZE); + if(!bh) { + /* XXX try next block? */ + return -EBADF; + } + + /* from here on, we must exit through out: to release bh */ + + /* dirblock */ + dirblk = (struct efs_dirblk *)bh->b_data; + if (dirblk->db_magic != EFS_DIRBLK_MAGIC) { + printk("EFS: bad dirblk magic %#xl\n", dirblk->db_magic); + error = -EBADF; + goto out; + } + db_offset = ((__u16)dirblk->db_space[itemnum] << 1) + - EFS_DIRBLK_HEADERSIZE; + de = (struct efs_dent *)(&dirblk->db_space[db_offset]); + if (dirblk->db_slots == 0) { + error = 0; + goto out; + } + +#ifdef DEBUG_EFS_DIRS + if (itemnum == 0) { + printk("efs: readdir: db %d has %d entries, starting at offset %0#x\n", + block, dirblk->db_slots, (__u16)dirblk->db_firstused << 1); + } +#endif + + /* diritem first contains the inode number, the namelen and the name */ + iteminode = EFS_DE_GET_INUM(de); + namelen = de->d_namelen; + nameptr = de->d_name; + +#ifdef DEBUG_EFS_DIRS + printk("efs: dir #%d @ %0#x - inode %#0x %*s namelen %u\n", + itemnum,db_offset,iteminode, namelen, + nameptr ? nameptr : "(null)", namelen); #endif - /* copy filename and data in direntry */ - filldir(dirent,nameptr,namelen,filp->f_pos,iteminode); - - brelse(bh); - - /* store pos of next item */ - itemnum++; - if(itemnum==numitems) { - itemnum = 0; - block++; - } - filp->f_pos = (block<<EFS_BLOCK_SIZE_BITS) | itemnum; - UPDATE_ATIME(inode); - - return 0; + /* copy filename and data in direntry */ + error = filldir(dirent,nameptr,namelen,filp->f_pos,iteminode); + if (error) + goto out; + + /* store pos of next item */ + itemnum++; + if(itemnum == dirblk->db_slots) { + itemnum = 0; + block++; + } + filp->f_pos = (block<<EFS_BLOCK_SIZE_BITS) | itemnum; + UPDATE_ATIME(inode); + + out: + brelse(bh); + + return error; } diff --git a/fs/efs/inode.c b/fs/efs/inode.c index 7928e45b4..a75d44956 100644 --- a/fs/efs/inode.c +++ b/fs/efs/inode.c @@ -17,13 +17,14 @@ /* ----- Define the operations for the Superblock ----- */ void efs_read_inode(struct inode *); +void efs_put_inode(struct inode *); void efs_put_super(struct super_block *); int efs_statfs(struct super_block *, struct statfs *,int ); static struct super_operations efs_sops = { efs_read_inode, NULL, /* write_inode */ - NULL, /* put_inode */ + efs_put_inode, /* put_inode */ NULL, /* delete_inode */ NULL, /* notify_change */ efs_put_super, @@ -32,6 +33,10 @@ static struct super_operations efs_sops = { NULL }; +static void efs_put_inode(struct inode *i) { + printk("efs_put_inode: iput()ting inode %d\n", i->i_ino); +} + /* ----- Conversion utilities ----- Get 16- and 32-bit unsigned values in big-endian format from a byte buffer @@ -369,7 +374,7 @@ void efs_read_inode(struct inode *in) /* Read the block with the inode from disk */ #ifdef DEBUG_EFS - printk("EFS: looking for inode %#xl\n", in->i_ino); + printk("EFS: looking for inode %#lx\n", in->i_ino); #endif bh = bread(in->i_dev,blk,EFS_BLOCK_SIZE); if(bh) { @@ -430,7 +435,7 @@ void efs_read_inode(struct inode *in) } else { #ifdef DEBUG_EFS - printk("EFS: inode %#Xl is direct (woohoo!)\n", + printk("EFS: inode %#lx is direct (woohoo!)\n", in->i_ino); #endif /* The extends are found in the inode block */ diff --git a/fs/efs/namei.c b/fs/efs/namei.c index 752aa5fe1..9cbdd9550 100644 --- a/fs/efs/namei.c +++ b/fs/efs/namei.c @@ -47,13 +47,13 @@ static struct buffer_head * efs_find_entry(struct inode *dir, /* Search in every dirblock */ inode = 0; blknum = dir->i_size >> EFS_BLOCK_SIZE_BITS; -#ifdef DEBUG_EFS +#ifdef DEBUG_EFS_DIRS printk("EFS: directory with inode %#xd has %d blocks\n", dir->i_ino, blknum); #endif for(b=0;b<blknum;b++) { int db_offset; -#ifdef DEBUG_EFS +#ifdef DEBUG_EFS_DIRS printk("EFS: trying block %d\n", b); #endif /* Read a raw dirblock */ @@ -69,7 +69,7 @@ static struct buffer_head * efs_find_entry(struct inode *dir, db->db_magic); return NULL; } -#ifdef DEBUG_EFS +#ifdef DEBUG_EFS_DIRS printk("EFS: db %d has %d entries, starting at offset %#x\n", b, db->db_slots, (__u16)db->db_firstused << 1); #endif @@ -81,18 +81,18 @@ static struct buffer_head * efs_find_entry(struct inode *dir, de = (struct efs_dent *)(&db->db_space[db_offset]); /* inode, namelen and name of direntry */ - entry_inode = efs_swab32(de->ud_inum.l); + entry_inode = EFS_DE_GET_INUM(de); namelen = de->d_namelen; name = de->d_name; -#ifdef 0 - printk("EFS: entry %d @ %#x has inode %#x, %s/%d\n", - i, db_offset, entry_inode, name, namelen); +#ifdef DEBUG_EFS_DIRS + printk("EFS: entry %d @ %#lx has inode %#x: \"%*s\"\n", + i, db_offset, entry_inode, namelen, name); #endif /* we found the name! */ if((namelen==onamelen)&& (!memcmp(oname,name,onamelen))) { res_dir->inode = entry_inode; -#ifdef DEBUG_EFS +#ifdef DEBUG_EFS_DIRS printk("EFS: found inode %d\n", entry_inode); #endif diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c index 05e3c082d..8c52411a1 100644 --- a/fs/efs/symlink.c +++ b/fs/efs/symlink.c @@ -16,8 +16,8 @@ #include <linux/slab.h> #include <asm/uaccess.h> -static int efs_readlink(struct inode *, char *, int); -static struct dentry * efs_follow_link(struct inode *, struct dentry *); +static int efs_readlink(struct dentry *, char *, int); +static struct dentry * efs_follow_link(struct dentry *, struct dentry *); struct inode_operations efs_symlink_in_ops = { NULL, /* no file-operations */ @@ -50,6 +50,10 @@ static char *efs_getlinktarget(struct inode *in) __u32 size = in->i_size; __u32 block; +#ifdef DEBUG_EFS + printk("efs_getlinktarget: size of inode %#0lx is %d\n", in->i_ino, + size); +#endif /* link data longer than 1024 not supported */ if(size>2*EFS_BLOCK_SIZE) { printk("efs_getlinktarget: name too long: %lu\n",in->i_size); @@ -64,6 +68,7 @@ static char *efs_getlinktarget(struct inode *in) block = efs_bmap(in,0); bh = bread(in->i_dev,block,EFS_BLOCK_SIZE); if(!bh) { + printk("efs_getlinktarget: unable to read first block (%d)\n", block); kfree(name); return NULL; } @@ -74,8 +79,9 @@ static char *efs_getlinktarget(struct inode *in) if(size>EFS_BLOCK_SIZE) { bh = bread(in->i_dev,block+1,EFS_BLOCK_SIZE); if(!bh) { - kfree(name); - return NULL; + printk("efs_getlinktarget: unable to read second block (%d)\n", block); + kfree(name); + return NULL; } memcpy(name+EFS_BLOCK_SIZE,bh->b_data,size-EFS_BLOCK_SIZE); brelse(bh); @@ -90,8 +96,10 @@ static char *efs_getlinktarget(struct inode *in) /* ----- efs_follow_link ----- get the inode of the link target */ -static struct dentry * efs_follow_link(struct inode * dir, struct dentry *base) +static struct dentry * efs_follow_link(struct dentry * dent, + struct dentry *base) { + struct inode * dir = dent->d_inode; char * name; UPDATE_ATIME(dir); name = efs_getlinktarget(dir); @@ -107,10 +115,11 @@ static struct dentry * efs_follow_link(struct inode * dir, struct dentry *base) /* ----- efs_readlink ----- read the target of a link and return the name */ -static int efs_readlink(struct inode * dir, char * buffer, int buflen) +static int efs_readlink(struct dentry * dent, char * buffer, int buflen) { int i; struct buffer_head * bh; + struct inode * dir = dent->d_inode; if (buflen > 1023) buflen = 1023; |