diff options
-rw-r--r-- | fs/efs/dir.c | 81 | ||||
-rw-r--r-- | fs/efs/file.c | 57 | ||||
-rw-r--r-- | fs/efs/inode.c | 253 | ||||
-rw-r--r-- | fs/efs/namei.c | 22 | ||||
-rw-r--r-- | fs/efs/super.c | 119 | ||||
-rw-r--r-- | fs/efs/symlink.c | 17 | ||||
-rw-r--r-- | include/linux/efs_dir.h | 3 | ||||
-rw-r--r-- | include/linux/efs_fs.h | 59 | ||||
-rw-r--r-- | include/linux/efs_vh.h | 43 |
9 files changed, 360 insertions, 294 deletions
diff --git a/fs/efs/dir.c b/fs/efs/dir.c index 00d1f3e2e..89dedbdb8 100644 --- a/fs/efs/dir.c +++ b/fs/efs/dir.c @@ -9,43 +9,48 @@ static int efs_readdir(struct file *, void *, filldir_t); static struct file_operations efs_dir_operations = { - NULL, /* lseek */ - NULL, /* read */ - NULL, /* write */ - efs_readdir, - NULL, /* poll */ - NULL, /* ioctl */ - NULL, /* no special open code */ - NULL, /* flush */ - NULL, /* no special release code */ - NULL /* fsync */ + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + efs_readdir, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* open */ + NULL, /* flush */ + NULL, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL /* revalidate */ }; struct inode_operations efs_dir_inode_operations = { - &efs_dir_operations, - NULL, /* create */ - efs_lookup, - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* readlink */ - NULL, /* follow_link */ - NULL, /* readpage */ - NULL, /* writepage */ - efs_bmap, - NULL, /* truncate */ - NULL /* permission */ + &efs_dir_operations, /* default directory file-ops */ + NULL, /* create */ + efs_lookup, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + efs_bmap, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL /* smap */ }; /* read the next entry for a given directory */ 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.generic_ip; + struct efs_inode_info *ini = INODE_INFO(inode); struct buffer_head *bh; struct efs_dir *dirblock; @@ -61,17 +66,19 @@ static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) { if (ini->numextents != 1) printk("EFS: WARNING: readdir(): more than one extent\n"); - if (inode->i_size & (EFS_BLOCKSIZE-1)) - printk("EFS: WARNING: readdir(): directory size not a multiple of EFS_BLOCKSIZE\n"); + if (inode->i_size & (EFS_DIRBSIZE-1)) + printk("EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n"); /* work out where this entry can be found */ - block = filp->f_pos >> EFS_BLOCKSIZE_BITS; + block = filp->f_pos >> EFS_DIRBSIZE_BITS; + + /* each block contains at most 256 slots */ slot = filp->f_pos & 0xff; /* look at all blocks */ - while (block <= inode->i_blocks) { + while (block < inode->i_blocks) { /* read the dir block */ - bh = bread(inode->i_dev, efs_bmap(inode, block), EFS_BLOCKSIZE); + bh = bread(inode->i_dev, efs_bmap(inode, block), EFS_DIRBSIZE); if (!bh) { printk("EFS: readdir(): failed to read dir block %d\n", block); @@ -94,11 +101,11 @@ static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) { nameptr = dirslot->name; #ifdef DEBUG - printk("EFS: block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n", block, slot, numslots, inodenum, nameptr, namelen); + printk("EFS: readdir(): block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n", block, slot, dirblock->slots, inodenum, nameptr, namelen); #endif if (namelen > 0) { /* found the next entry */ - filp->f_pos = (block << EFS_BLOCKSIZE_BITS) | slot; + filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; /* copy filename and data in dirslot */ filldir(dirent, nameptr, namelen, filp->f_pos, inodenum); @@ -109,7 +116,7 @@ static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) { block++; } brelse(bh); - filp->f_pos = (block << EFS_BLOCKSIZE_BITS) | slot; + filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; return 0; } slot++; @@ -120,7 +127,7 @@ static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) { block++; } - filp->f_pos = (block << EFS_BLOCKSIZE_BITS) | slot; + filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; return 0; } diff --git a/fs/efs/file.c b/fs/efs/file.c index e43af509c..4f0c4cf6a 100644 --- a/fs/efs/file.c +++ b/fs/efs/file.c @@ -10,49 +10,54 @@ static struct file_operations efs_file_operations = { NULL, /* lseek */ - generic_file_read, + generic_file_read, /* read */ NULL, /* write */ NULL, /* readdir */ NULL, /* poll */ NULL, /* ioctl */ - generic_file_mmap, + generic_file_mmap, /* mmap */ + NULL, /* open */ NULL, /* flush */ - NULL, /* no special release code */ - NULL /* fsync */ + NULL, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL /* revalidate */ }; struct inode_operations efs_file_inode_operations = { - &efs_file_operations, - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - NULL, /* readlink */ - NULL, /* follow_link */ - generic_readpage, - NULL, /* writepage */ - efs_bmap, - NULL, /* truncate */ - NULL /* permission */ + &efs_file_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + generic_readpage, /* readpage */ + NULL, /* writepage */ + efs_bmap, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL /* smap */ }; int efs_bmap(struct inode *inode, efs_block_t block) { if (block < 0) { - printk("EFS: efs_bmap(): block < 0\n"); + printk("EFS: bmap(): block < 0\n"); return 0; } /* are we about to read past the end of a file ? */ - if (block > inode->i_blocks) { + if (!(block < inode->i_blocks)) { #ifdef DEBUG - /* dunno why this happens */ - printk("EFS: efs_bmap(): block %d > last block %ld (filesize %ld)\n", + /* i have no idea why this happens as often as it does */ + printk("EFS: bmap(): block %d >= %ld (filesize %ld)\n", block, inode->i_blocks, inode->i_size); @@ -60,6 +65,6 @@ int efs_bmap(struct inode *inode, efs_block_t block) { return 0; } - return efs_read_block(inode, block); + return efs_map_block(inode, block); } diff --git a/fs/efs/inode.c b/fs/efs/inode.c index 81c8e81c7..33e3863f3 100644 --- a/fs/efs/inode.c +++ b/fs/efs/inode.c @@ -12,9 +12,9 @@ static inline void extent_copy(efs_extent *src, efs_extent *dst) { /* - * this is slightly evil. it doesn't just copy the - * efs_extent from src to dst, it also mangles the bits - * so that dst ends up in cpu byte-order. + * this is slightly evil. it doesn't just copy + * efs_extent from src to dst, it also mangles + * the bits so that dst ends up in cpu byte-order. */ dst->cooked.ex_magic = (unsigned int) src->raw[0]; @@ -28,12 +28,12 @@ static inline void extent_copy(efs_extent *src, efs_extent *dst) { return; } -void efs_read_inode(struct inode *in) { - int i, extents, inode_index; +void efs_read_inode(struct inode *inode) { + int i, inode_index; dev_t device; struct buffer_head *bh; - struct efs_sb_info *sbp = (struct efs_sb_info *)&in->i_sb->u.generic_sbp; - struct efs_inode_info *ini = (struct efs_inode_info *)&in->u.generic_ip; + struct efs_sb_info *sb = SUPER_INFO(inode->i_sb); + struct efs_inode_info *in = INODE_INFO(inode); efs_block_t block, offset; struct efs_dinode *efs_inode; @@ -49,16 +49,18 @@ void efs_read_inode(struct inode *in) { ** offset of the inode within that block. */ - /* four inodes are stored in one block */ - inode_index = in->i_ino / (EFS_BLOCKSIZE / sizeof(struct efs_dinode)); + inode_index = inode->i_ino / + (EFS_BLOCKSIZE / sizeof(struct efs_dinode)); - block = sbp->fs_start + sbp->first_block + - (sbp->group_size * (inode_index / sbp->inode_blocks)) + - (inode_index % sbp->inode_blocks); + block = sb->fs_start + sb->first_block + + (sb->group_size * (inode_index / sb->inode_blocks)) + + (inode_index % sb->inode_blocks); - offset = (in->i_ino % (EFS_BLOCKSIZE / sizeof(struct efs_dinode))) << 7; + offset = (inode->i_ino % + (EFS_BLOCKSIZE / sizeof(struct efs_dinode))) * + sizeof(struct efs_dinode); - bh = bread(in->i_dev, block, EFS_BLOCKSIZE); + bh = bread(inode->i_dev, block, EFS_BLOCKSIZE); if (!bh) { printk("EFS: bread() failed at block %d\n", block); goto read_inode_error; @@ -67,17 +69,21 @@ void efs_read_inode(struct inode *in) { efs_inode = (struct efs_dinode *) (bh->b_data + offset); /* fill in standard inode infos */ - in->i_mode = be16_to_cpu(efs_inode->di_mode); - in->i_nlink = be16_to_cpu(efs_inode->di_nlink); - in->i_uid = be16_to_cpu(efs_inode->di_uid); - in->i_gid = be16_to_cpu(efs_inode->di_gid); - in->i_size = be32_to_cpu(efs_inode->di_size); - in->i_atime = be32_to_cpu(efs_inode->di_atime); - in->i_mtime = be32_to_cpu(efs_inode->di_mtime); - in->i_ctime = be32_to_cpu(efs_inode->di_ctime); - - /* this is last valid block in the file */ - in->i_blocks = ((in->i_size - 1) >> EFS_BLOCKSIZE_BITS); + inode->i_mode = be16_to_cpu(efs_inode->di_mode); + inode->i_nlink = be16_to_cpu(efs_inode->di_nlink); + inode->i_uid = be16_to_cpu(efs_inode->di_uid); + inode->i_gid = be16_to_cpu(efs_inode->di_gid); + inode->i_size = be32_to_cpu(efs_inode->di_size); + inode->i_atime = be32_to_cpu(efs_inode->di_atime); + inode->i_mtime = be32_to_cpu(efs_inode->di_mtime); + inode->i_ctime = be32_to_cpu(efs_inode->di_ctime); + + /* this is the number of blocks in the file */ + if (inode->i_size == 0) { + inode->i_blocks = 0; + } else { + inode->i_blocks = ((inode->i_size - 1) >> EFS_BLOCKSIZE_BITS) + 1; + } device = be32_to_cpu(efs_inode->di_u.di_dev); @@ -85,51 +91,50 @@ void efs_read_inode(struct inode *in) { They are necessary for further operations with the file */ /* get the number of extents for this object */ - extents = be16_to_cpu(efs_inode->di_numextents); + in->numextents = be16_to_cpu(efs_inode->di_numextents); + in->lastextent = 0; - /* copy the first 12 extents directly from the inode */ + /* copy the extents contained within the inode to memory */ for(i = 0; i < EFS_DIRECTEXTENTS; i++) { - extent_copy(&(efs_inode->di_u.di_extents[i]), &(ini->extents[i])); - if (i < extents && ini->extents[i].cooked.ex_magic != 0) { - printk("EFS: extent %d has bad magic number in inode %lu\n", i, in->i_ino); + extent_copy(&(efs_inode->di_u.di_extents[i]), &(in->extents[i])); + if (i < in->numextents && in->extents[i].cooked.ex_magic != 0) { + printk("EFS: extent %d has bad magic number in inode %lu\n", i, inode->i_ino); brelse(bh); goto read_inode_error; } } - ini->numextents = extents; - ini->lastextent = 0; brelse(bh); #ifdef DEBUG - printk("EFS: efs_read_inode(): inode %lu, extents %d\n", - in->i_ino, extents); + printk("EFS: read_inode(): inode %lu, extents %d\n", + inode->i_ino, in->numextents); #endif /* Install the filetype Handler */ - switch (in->i_mode & S_IFMT) { + switch (inode->i_mode & S_IFMT) { case S_IFDIR: - in->i_op = &efs_dir_inode_operations; + inode->i_op = &efs_dir_inode_operations; break; case S_IFREG: - in->i_op = &efs_file_inode_operations; + inode->i_op = &efs_file_inode_operations; break; case S_IFLNK: - in->i_op = &efs_symlink_inode_operations; + inode->i_op = &efs_symlink_inode_operations; break; case S_IFCHR: - in->i_rdev = device; - in->i_op = &chrdev_inode_operations; + inode->i_rdev = device; + inode->i_op = &chrdev_inode_operations; break; case S_IFBLK: - in->i_rdev = device; - in->i_op = &blkdev_inode_operations; + inode->i_rdev = device; + inode->i_op = &blkdev_inode_operations; break; case S_IFIFO: - init_fifo(in); + init_fifo(inode); break; default: - printk("EFS: unsupported inode mode %o\n",in->i_mode); + printk("EFS: unsupported inode mode %o\n", inode->i_mode); goto read_inode_error; break; } @@ -137,23 +142,23 @@ void efs_read_inode(struct inode *in) { return; read_inode_error: - printk("EFS: failed to read inode %lu\n", in->i_ino); - in->i_mode = S_IFREG; - in->i_atime = 0; - in->i_ctime = 0; - in->i_mtime = 0; - in->i_nlink = 1; - in->i_size = 0; - in->i_blocks = 0; - in->i_uid = 0; - in->i_gid = 0; - in->i_op = NULL; + printk("EFS: failed to read inode %lu\n", inode->i_ino); + inode->i_mode = S_IFREG; + inode->i_atime = 0; + inode->i_ctime = 0; + inode->i_mtime = 0; + inode->i_nlink = 1; + inode->i_size = 0; + inode->i_blocks = 0; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_op = NULL; return; } static inline efs_block_t -efs_extent_check(efs_extent *ptr, efs_block_t block, struct efs_sb_info *sbp, struct efs_inode_info *ini) { +efs_extent_check(efs_extent *ptr, efs_block_t block, struct efs_sb_info *sb) { efs_block_t start; efs_block_t length; efs_block_t offset; @@ -167,7 +172,7 @@ efs_extent_check(efs_extent *ptr, efs_block_t block, struct efs_sb_info *sbp, st offset = ptr->cooked.ex_offset; if ((block >= offset) && (block < offset+length)) { - return(sbp->fs_start + start + block - offset); + return(sb->fs_start + start + block - offset); } else { return 0; } @@ -175,101 +180,113 @@ efs_extent_check(efs_extent *ptr, efs_block_t block, struct efs_sb_info *sbp, st /* find the disk block number for a given logical file block number */ -efs_block_t efs_read_block(struct inode *inode, efs_block_t block) { - struct efs_sb_info *sbp = (struct efs_sb_info *) &inode->i_sb->u.generic_sbp; - struct efs_inode_info *ini = (struct efs_inode_info *) &inode->u.generic_ip; - struct buffer_head *bh; +efs_block_t efs_map_block(struct inode *inode, efs_block_t block) { + struct efs_sb_info *sb = SUPER_INFO(inode->i_sb); + struct efs_inode_info *in = INODE_INFO(inode); + struct buffer_head *bh = NULL; - efs_block_t result = 0; - int indirexts, indirext, imagic; - efs_block_t istart, iblock, ilen; - int i, cur, last, total, checked; - efs_extent *exts; - efs_extent ext; + int cur, last, first = 1; + int ibase, ioffset, dirext, direxts, indext, indexts; + efs_block_t iblock, result = 0, lastblock = 0; + efs_extent ext, *exts; - last = ini->lastextent; - total = ini->numextents; + last = in->lastextent; - if (total <= EFS_DIRECTEXTENTS) { + if (in->numextents <= EFS_DIRECTEXTENTS) { /* first check the last extent we returned */ - if ((result = efs_extent_check(&ini->extents[last], block, sbp, ini))) + if ((result = efs_extent_check(&in->extents[last], block, sb))) return result; /* if we only have one extent then nothing can be found */ - if (total == 1) { - printk("EFS: read_block() failed to map (1 extent)\n"); + if (in->numextents == 1) { + printk("EFS: map_block() failed to map (1 extent)\n"); return 0; } + direxts = in->numextents; + /* check the stored extents in the inode */ /* start with next extent and check forwards */ - for(i = 1; i < total; i++) { - if ((result = efs_extent_check(&ini->extents[(last + i) % total], block, sbp, ini))) { - ini->lastextent = i; + for(dirext = 1; dirext < direxts; dirext++) { + cur = (last + dirext) % in->numextents; + if ((result = efs_extent_check(&in->extents[cur], block, sb))) { + in->lastextent = cur; return result; } } - printk("EFS: read_block() failed to map for direct extents\n"); + printk("EFS: map_block() failed to map block %u (dir)\n", block); return 0; } #ifdef DEBUG - printk("EFS: indirect search for logical block %u\n", block); + printk("EFS: map_block(): indirect search for logical block %u\n", block); #endif + direxts = in->extents[0].cooked.ex_offset; + indexts = in->numextents; + + for(indext = 0; indext < indexts; indext++) { + cur = (last + indext) % indexts; + + /* + * work out which direct extent contains `cur'. + * + * also compute ibase: i.e. the number of the first + * indirect extent contained within direct extent `cur'. + * + */ + ibase = 0; + for(dirext = 0; cur < ibase && dirext < direxts; dirext++) { + ibase += in->extents[dirext].cooked.ex_length * + (EFS_BLOCKSIZE / sizeof(efs_extent)); + } - /* - * OPT: this lot is inefficient. - */ - - indirexts = ini->extents[0].cooked.ex_offset; - checked = 0; + if (dirext == direxts) { + /* should never happen */ + printk("EFS: couldn't find direct extent for indirect extent %d (block %u)\n", cur, block); + return 0; + } + + /* work out block number and offset of this indirect extent */ + iblock = sb->fs_start + in->extents[dirext].cooked.ex_bn + + (cur - ibase) / + (EFS_BLOCKSIZE / sizeof(efs_extent)); + ioffset = (cur - ibase) % + (EFS_BLOCKSIZE / sizeof(efs_extent)); - for(indirext = 0; indirext < indirexts; indirext++) { - cur = (last + indirext) % indirexts; - imagic = ini->extents[cur].cooked.ex_magic; - istart = ini->extents[cur].cooked.ex_bn + sbp->fs_start; - ilen = ini->extents[cur].cooked.ex_length; + if (first || lastblock != iblock) { + if (bh) brelse(bh); - for(iblock = istart; iblock < istart + ilen; iblock++) { bh = bread(inode->i_dev, iblock, EFS_BLOCKSIZE); if (!bh) { - printk("EFS: bread() failed at block %d\n", block); + printk("EFS: bread() failed at block %d\n", iblock); return 0; } #ifdef DEBUG - printk("EFS: read indirect extent block %d\n", iblock-istart); + printk("EFS: map_block(): read indirect extent block %d\n", iblock); #endif + first = 0; + lastblock = iblock; + } - exts = (efs_extent *) bh->b_data; - for(i = 0; i < EFS_BLOCKSIZE / sizeof(efs_extent) && checked < total; i++, checked++) { - /* - * this block might be read-cached - * so fiddle the endianness in a private copy - */ - extent_copy(&(exts[i]), &ext); - - if (ext.cooked.ex_magic != 0) { - printk("EFS: extent %d has bad magic number in block %d\n", i, iblock); - brelse(bh); - return 0; - } - - if ((result = efs_extent_check(&ext, block, sbp, ini))) { - brelse(bh); - ini->lastextent = cur; - return result; - } - } + exts = (efs_extent *) bh->b_data; + + extent_copy(&(exts[ioffset]), &ext); + + if (ext.cooked.ex_magic != 0) { + printk("EFS: extent %d has bad magic number in block %d\n", cur, iblock); brelse(bh); - /* shouldn't need this if the FS is consistent */ - if (checked == total) { - printk("EFS: unable to map (checked all extents)\n"); - return 0; - } + return 0; + } + + if ((result = efs_extent_check(&ext, block, sb))) { + brelse(bh); + in->lastextent = cur; + return result; } } - printk("EFS: unable to map (fell out of loop)\n"); + if (bh) brelse(bh); + printk("EFS: map_block() failed to map block %u (indir)\n", block); return 0; } diff --git a/fs/efs/namei.c b/fs/efs/namei.c index d73392ac7..088285f0c 100644 --- a/fs/efs/namei.c +++ b/fs/efs/namei.c @@ -10,8 +10,8 @@ /* search an efs directory inode for the given name */ -static uint32_t efs_find_entry(struct inode *inode, const char *name, int len) { - struct efs_inode_info *ini = (struct efs_inode_info *) &inode->u.generic_ip; +static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len) { + struct efs_inode_info *in = INODE_INFO(inode); struct buffer_head *bh; int slot, namelen; @@ -21,13 +21,13 @@ static uint32_t efs_find_entry(struct inode *inode, const char *name, int len) { efs_ino_t inodenum; efs_block_t block; - if (ini->numextents != 1) - printk("EFS: WARNING: readdir(): more than one extent\n"); + if (in->numextents != 1) + printk("EFS: WARNING: find_entry(): more than one extent\n"); if (inode->i_size & (EFS_BLOCKSIZE-1)) - printk("EFS: WARNING: readdir(): directory size not a multiple of EFS_BLOCKSIZE\n"); + printk("EFS: WARNING: find_entry(): directory size not a multiple of EFS_BLOCKSIZE\n"); - for(block = 0; block <= inode->i_blocks; block++) { + for(block = 0; block < inode->i_blocks; block++) { bh = bread(inode->i_dev, efs_bmap(inode, block), EFS_BLOCKSIZE); if (!bh) { @@ -38,7 +38,7 @@ static uint32_t efs_find_entry(struct inode *inode, const char *name, int len) { dirblock = (struct efs_dir *) bh->b_data; if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { - printk("EFS: readdir(): invalid directory block\n"); + printk("EFS: find_entry(): invalid directory block\n"); brelse(bh); return(0); } @@ -64,16 +64,16 @@ static uint32_t efs_find_entry(struct inode *inode, const char *name, int len) { /* get inode associated with directory entry */ int efs_lookup(struct inode *dir, struct dentry *dentry) { - int ino; + efs_ino_t inodenum; struct inode * inode; if (!dir || !S_ISDIR(dir->i_mode)) return -ENOENT; inode = NULL; - ino = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); - if (ino) { - if (!(inode = iget(dir->i_sb, ino))) + inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); + if (inodenum) { + if (!(inode = iget(dir->i_sb, inodenum))) return -EACCES; } diff --git a/fs/efs/super.c b/fs/efs/super.c index 2bc259d51..ba7f45fc0 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -6,18 +6,13 @@ * Portions derived from work (c) 1995,1996 Christian Vogelgsang. */ -#include <linux/module.h> #include <linux/init.h> - +#include <linux/module.h> +#include <linux/locks.h> #include <linux/efs_fs.h> #include <linux/efs_vh.h> #include <linux/efs_fs_sb.h> -void efs_read_inode(struct inode *); -void efs_put_super(struct super_block *); -int efs_statfs(struct super_block *, struct statfs *, int); -struct super_block * efs_read_super(struct super_block *, void *, int); - static struct file_system_type efs_fs_type = { "efs", /* filesystem name */ FS_REQUIRES_DEV, /* fs_flags */ @@ -38,8 +33,7 @@ static struct super_operations efs_superblock_operations = { }; __initfunc(int init_efs_fs(void)) { - printk(cprt); - printk(" - http://aeschi.ch.eu.org/efs/\n"); + printk("EFS: "EFS_VERSION" - http://aeschi.ch.eu.org/efs/\n"); return register_filesystem(&efs_fs_type); } @@ -55,11 +49,12 @@ void cleanup_module(void) { } #endif -static long efs_validate_vh(struct volume_header *vh) { - int i, j; - int32_t sblock = -1; - int type, slice = -1; - char name[VDNAMESIZE+1]; +static efs_block_t efs_validate_vh(struct volume_header *vh) { + int i; + unsigned int cs, csum, *ui; + efs_block_t sblock = 0; /* shuts up gcc */ + struct pt_types *pt_entry; + int pt_type, slice = -1; if (be32_to_cpu(vh->vh_magic) != VHMAGIC) { /* @@ -70,44 +65,65 @@ static long efs_validate_vh(struct volume_header *vh) { return 0; } + ui = ((unsigned int *) (vh + 1)) - 1; + for(csum = 0; ui >= ((unsigned int *) vh);) { + cs = *ui--; + csum += be32_to_cpu(cs); + } + if (csum) { + printk("EFS: SGI disklabel: checksum bad, label corrupted\n"); + return 0; + } + #ifdef DEBUG - printk("EFS: bf: %16s\n", vh->vh_bootfile); -#endif + printk("EFS: bf: \"%16s\"\n", vh->vh_bootfile); for(i = 0; i < NVDIR; i++) { + int j; + char name[VDNAMESIZE+1]; + for(j = 0; j < VDNAMESIZE; j++) { name[j] = vh->vh_vd[i].vd_name[j]; } name[j] = (char) 0; -#ifdef DEBUG if (name[0]) { printk("EFS: vh: %8s block: 0x%08x size: 0x%08x\n", name, (int) be32_to_cpu(vh->vh_vd[i].vd_lbn), (int) be32_to_cpu(vh->vh_vd[i].vd_nbytes)); } -#endif } +#endif for(i = 0; i < NPARTAB; i++) { - type = (int) be32_to_cpu(vh->vh_pt[i].pt_type); + pt_type = (int) be32_to_cpu(vh->vh_pt[i].pt_type); + for(pt_entry = sgi_pt_types; pt_entry->pt_name; pt_entry++) { + if (pt_type == pt_entry->pt_type) break; + } #ifdef DEBUG - printk("EFS: pt: start: %08d size: %08d type: %08d\n", - (int) be32_to_cpu(vh->vh_pt[i].pt_firstlbn), - (int) be32_to_cpu(vh->vh_pt[i].pt_nblks), - type); + if (be32_to_cpu(vh->vh_pt[i].pt_nblks)) { + printk("EFS: pt %2d: start: %08d size: %08d type: 0x%02x (%s)\n", + i, + (int) be32_to_cpu(vh->vh_pt[i].pt_firstlbn), + (int) be32_to_cpu(vh->vh_pt[i].pt_nblks), + pt_type, + (pt_entry->pt_name) ? pt_entry->pt_name : "unknown"); + } #endif - if (type == 5 || type == 7) { + if (IS_EFS(pt_type)) { sblock = be32_to_cpu(vh->vh_pt[i].pt_firstlbn); slice = i; } } - if (sblock < 0) { - printk("EFS: found valid partition table but no EFS partitions\n"); + if (slice == -1) { + printk("EFS: partition table contained no EFS partitions\n"); } else { - printk("EFS: using CD slice %d (offset 0x%x)\n", slice, sblock); + printk("EFS: using slice %d (type %s, offset 0x%x)\n", + slice, + (pt_entry->pt_name) ? pt_entry->pt_name : "unknown", + sblock); } return(sblock); } @@ -131,14 +147,13 @@ static int efs_validate_super(struct efs_sb_info *sb, struct efs_super *super) { struct super_block *efs_read_super(struct super_block *s, void *d, int verbose) { kdev_t dev = s->s_dev; struct inode *root_inode; - struct efs_sb_info *spb; + struct efs_sb_info *sb; struct buffer_head *bh; MOD_INC_USE_COUNT; lock_super(s); - /* approx 230 bytes available in this union */ - spb = (struct efs_sb_info *) &(s->u.generic_sbp); + sb = SUPER_INFO(s); set_blocksize(dev, EFS_BLOCKSIZE); @@ -155,21 +170,21 @@ struct super_block *efs_read_super(struct super_block *s, void *d, int verbose) * this isn't (yet) an error - just assume for the moment that * the device is valid and go on to search for a superblock. */ - spb->fs_start = efs_validate_vh((struct volume_header *) bh->b_data); + sb->fs_start = efs_validate_vh((struct volume_header *) bh->b_data); brelse(bh); - if (spb->fs_start < 0) { + if (sb->fs_start == -1) { goto out_no_fs_ul; } - bh = bread(dev, spb->fs_start + EFS_SUPER, EFS_BLOCKSIZE); + bh = bread(dev, sb->fs_start + EFS_SUPER, EFS_BLOCKSIZE); if (!bh) { printk("EFS: unable to read superblock\n"); goto out_no_fs_ul; } - if (efs_validate_super(spb, (struct efs_super *) bh->b_data)) { - printk("EFS: invalid superblock\n"); + if (efs_validate_super(sb, (struct efs_super *) bh->b_data)) { + printk("EFS: invalid superblock at block %u\n", sb->fs_start + EFS_SUPER); brelse(bh); goto out_no_fs_ul; } @@ -179,7 +194,7 @@ struct super_block *efs_read_super(struct super_block *s, void *d, int verbose) s->s_blocksize_bits = EFS_BLOCKSIZE_BITS; if (!(s->s_flags & MS_RDONLY)) { #ifdef DEBUG - printk("EFS: forcing read-only: RW access not supported\n"); + printk("EFS: forcing read-only mode\n"); #endif s->s_flags |= MS_RDONLY; } @@ -222,23 +237,23 @@ void efs_put_super(struct super_block *s) { } int efs_statfs(struct super_block *s, struct statfs *buf, int bufsiz) { - struct statfs tmp; - struct efs_sb_info *sbp = (struct efs_sb_info *)&s->u.generic_sbp; - - tmp.f_type = EFS_SUPER_MAGIC; /* efs magic number */ - tmp.f_bsize = EFS_BLOCKSIZE; /* blocksize */ - tmp.f_blocks = sbp->total_groups * /* total data blocks */ - (sbp->group_size - sbp->inode_blocks); - tmp.f_bfree = sbp->data_free; /* free data blocks */ - tmp.f_bavail = sbp->data_free; /* free blocks for non-root */ - tmp.f_files = sbp->total_groups * /* total inodes */ - sbp->inode_blocks * + struct statfs ret; + struct efs_sb_info *sb = SUPER_INFO(s); + + ret.f_type = EFS_SUPER_MAGIC; /* efs magic number */ + ret.f_bsize = EFS_BLOCKSIZE; /* blocksize */ + ret.f_blocks = sb->total_groups * /* total data blocks */ + (sb->group_size - sb->inode_blocks); + ret.f_bfree = sb->data_free; /* free data blocks */ + ret.f_bavail = sb->data_free; /* free blocks for non-root */ + ret.f_files = sb->total_groups * /* total inodes */ + sb->inode_blocks * (EFS_BLOCKSIZE / sizeof(struct efs_dinode)); - tmp.f_ffree = sbp->inode_free; /* free inodes */ - tmp.f_fsid.val[0] = (sbp->fs_magic >> 16) & 0xffff; /* fs ID */ - tmp.f_fsid.val[1] = sbp->fs_magic & 0xffff; /* fs ID */ - tmp.f_namelen = EFS_MAXNAMELEN; /* max filename length */ + ret.f_ffree = sb->inode_free; /* free inodes */ + ret.f_fsid.val[0] = (sb->fs_magic >> 16) & 0xffff; /* fs ID */ + ret.f_fsid.val[1] = sb->fs_magic & 0xffff; /* fs ID */ + ret.f_namelen = EFS_MAXNAMELEN; /* max filename length */ - return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; + return copy_to_user(buf, &ret, bufsiz) ? -EFAULT : 0; } diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c index c2783100b..c1b84d12d 100644 --- a/fs/efs/symlink.c +++ b/fs/efs/symlink.c @@ -6,6 +6,7 @@ * Portions derived from work (c) 1995,1996 Christian Vogelgsang. */ +#include <linux/malloc.h> #include <linux/efs_fs.h> static int @@ -14,7 +15,7 @@ static struct dentry * efs_follow_link(struct dentry *, struct dentry *, unsigned int); struct inode_operations efs_symlink_inode_operations = { - NULL, /* no file-operations */ + NULL, /* no symlink file-operations */ NULL, /* create */ NULL, /* lookup */ NULL, /* link */ @@ -30,7 +31,8 @@ struct inode_operations efs_symlink_inode_operations = { NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ - NULL /* permission */ + NULL, /* permission */ + NULL /* smap */ }; static char *efs_linktarget(struct inode *in, int *len) { @@ -39,7 +41,7 @@ static char *efs_linktarget(struct inode *in, int *len) { efs_block_t size = in->i_size; if (size > 2 * EFS_BLOCKSIZE) { - printk("EFS: efs_linktarget: name too long: %lu\n", in->i_size); + printk("EFS: linktarget(): name too long: %lu\n", in->i_size); return NULL; } @@ -50,7 +52,7 @@ static char *efs_linktarget(struct inode *in, int *len) { bh = bread(in->i_dev, efs_bmap(in, 0), EFS_BLOCKSIZE); if (!bh) { kfree(name); - printk("EFS: efs_linktarget: couldn't read block %d\n", efs_bmap(in, 0)); + printk("EFS: linktarget(): couldn't read block %d\n", efs_bmap(in, 0)); return NULL; } @@ -61,7 +63,7 @@ static char *efs_linktarget(struct inode *in, int *len) { bh = bread(in->i_dev, efs_bmap(in, 1), EFS_BLOCKSIZE); if (!bh) { kfree(name); - printk("EFS: efs_linktarget: couldn't read block %d\n", efs_bmap(in, 1)); + printk("EFS: linktarget(): couldn't read block %d\n", efs_bmap(in, 1)); return NULL; } memcpy(name + EFS_BLOCKSIZE, bh->b_data, size - EFS_BLOCKSIZE); @@ -78,7 +80,10 @@ static struct dentry *efs_follow_link(struct dentry *dentry, struct dentry *base char *name; struct inode *inode = dentry->d_inode; - name = efs_linktarget(inode, NULL); + if (!(name = efs_linktarget(inode, NULL))) { + dput(base); + return ERR_PTR(-ELOOP); + } base = lookup_dentry(name, base, follow); kfree(name); diff --git a/include/linux/efs_dir.h b/include/linux/efs_dir.h index 3459bd4bf..331524130 100644 --- a/include/linux/efs_dir.h +++ b/include/linux/efs_dir.h @@ -7,7 +7,8 @@ #ifndef __EFS_DIR_H__ #define __EFS_DIR_H__ -#define EFS_DIRBSIZE EFS_BLOCKSIZE +#define EFS_DIRBSIZE_BITS EFS_BLOCKSIZE_BITS +#define EFS_DIRBSIZE (1 << EFS_DIRBSIZE_BITS) struct efs_dentry { unsigned int inode; diff --git a/include/linux/efs_fs.h b/include/linux/efs_fs.h index 98b0181ee..c9c30e290 100644 --- a/include/linux/efs_fs.h +++ b/include/linux/efs_fs.h @@ -9,52 +9,41 @@ #ifndef __EFS_FS_H__ #define __EFS_FS_H__ -#define VERSION "0.97" - -static const char cprt[] = "EFS: version "VERSION" - (c) 1999 Al Smith <Al.Smith@aeschi.ch.eu.org>"; - -#include <linux/stat.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/mm.h> -#include <linux/string.h> -#include <linux/locks.h> -#include <linux/malloc.h> -#include <linux/errno.h> -#include <linux/cdrom.h> - -#include <asm/system.h> -#include <asm/segment.h> +#define EFS_VERSION "0.97e" + +static const char cprt[] = "EFS: "EFS_VERSION" - (c) 1999 Al Smith <Al.Smith@aeschi.ch.eu.org>"; + #include <asm/uaccess.h> -#include <asm/byteorder.h> -#define EFS_BLOCKSIZE 512 +#ifndef LINUX_VERSION_CODE +#include <linux/version.h> +#endif + +#if LINUX_VERSION_CODE < 0x20200 +#error This code is only for linux-2.2 and later. +#endif + +/* 1 block is 512 bytes */ #define EFS_BLOCKSIZE_BITS 9 +#define EFS_BLOCKSIZE (1 << EFS_BLOCKSIZE_BITS) #include <linux/efs_fs_i.h> #include <linux/efs_dir.h> #ifndef MIN -#define MIN(a,b) ((a)<(b)?(a):(b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #ifndef MAX -#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif -/* efs superblock information in memory */ -struct efs_spb { - int32_t fs_magic; /* superblock magic number */ - int32_t fs_start; /* first block of filesystem */ - int32_t first_block; /* first data block in filesystem */ - int32_t total_blocks; /* total number of blocks in filesystem */ - int32_t group_size; /* # of blocks a group consists of */ - int32_t data_free; /* # of free data blocks */ - int32_t inode_free; /* # of free inodes */ - short inode_blocks; /* # of blocks used for inodes in every grp */ - short total_groups; /* # of groups */ -}; - +#ifdef _EFS_USE_GENERIC +#define INODE_INFO(i) (struct efs_inode_info *) &((i)->u.generic_ip) +#define SUPER_INFO(s) (struct efs_sb_info *) &((s)->u.generic_sbp) +#else +#define INODE_INFO(i) &((i)->u.efs_i) +#define SUPER_INFO(s) &((s)->u.efs_sb) +#endif extern struct inode_operations efs_dir_inode_operations; extern struct inode_operations efs_file_inode_operations; @@ -67,7 +56,7 @@ extern void efs_put_super(struct super_block *); extern int efs_statfs(struct super_block *, struct statfs *, int); extern void efs_read_inode(struct inode *); -extern efs_block_t efs_read_block(struct inode *, efs_block_t); +extern efs_block_t efs_map_block(struct inode *, efs_block_t); extern int efs_lookup(struct inode *, struct dentry *); extern int efs_bmap(struct inode *, int); diff --git a/include/linux/efs_vh.h b/include/linux/efs_vh.h index 013c7aaf6..b9d7e4dda 100644 --- a/include/linux/efs_vh.h +++ b/include/linux/efs_vh.h @@ -28,15 +28,42 @@ struct partition_table { /* one per logical partition */ }; struct volume_header { - int vh_magic; /* identifies volume header */ - short vh_rootpt; /* root partition number */ - short vh_swappt; /* swap partition number */ - char vh_bootfile[BFNAMESIZE]; /* name of file to boot */ - char pad[48]; /* space for device params */ + int vh_magic; /* identifies volume header */ + short vh_rootpt; /* root partition number */ + short vh_swappt; /* swap partition number */ + char vh_bootfile[BFNAMESIZE]; /* name of file to boot */ + char pad[48]; /* device param space */ struct volume_directory vh_vd[NVDIR]; /* other vol hdr contents */ - struct partition_table vh_pt[NPARTAB]; /* device partition layout */ - int vh_csum; /* volume header checksum */ - int vh_fill; /* fill out to 512 bytes */ + struct partition_table vh_pt[NPARTAB]; /* device partition layout */ + int vh_csum; /* volume header checksum */ + int vh_fill; /* fill out to 512 bytes */ +}; + +/* partition type sysv is used for EFS format CD-ROM partitions */ +#define SGI_SYSV 0x05 +#define SGI_EFS 0x07 +#define IS_EFS(x) (((x) == SGI_EFS) || ((x) == SGI_SYSV)) + +struct pt_types { + int pt_type; + char *pt_name; +} sgi_pt_types[] = { + {0x00, "SGI vh"}, + {0x01, "SGI trkrepl"}, + {0x02, "SGI secrepl"}, + {0x03, "SGI raw"}, + {0x04, "SGI bsd"}, + {SGI_SYSV, "SGI sysv"}, + {0x06, "SGI vol"}, + {SGI_EFS, "SGI efs"}, + {0x08, "SGI lv"}, + {0x09, "SGI rlv"}, + {0x0A, "SGI xfs"}, + {0x0B, "SGI xfslog"}, + {0x0C, "SGI xlv"}, + {0x82, "Linux swap"}, + {0x83, "Linux native"}, + {0, NULL} }; #endif /* __EFS_VH_H__ */ |