description: handle limited hard blocksizes in EFS (512, 1024, 2048 bytes) changelog: convert all reads from logical to physical sector numbers & add a buffer_head offset to get back to the logical sectors maintainer: product_versions: Linux 2.6.0-test8 patch_name: efs_blocksizes.patch patch_version: 2003-10-21.21:29:22 author: Randy.Dunlap diffstat:= fs/efs/dir.c | 15 +++++++++------ fs/efs/file.c | 4 ++-- fs/efs/inode.c | 36 +++++++++++++++++++++++++++++------- fs/efs/namei.c | 12 ++++++------ fs/efs/super.c | 34 +++++++++++++++++++++------------- fs/efs/symlink.c | 13 ++++++++----- include/linux/efs_fs.h | 2 ++ include/linux/efs_fs_sb.h | 1 + 8 files changed, 78 insertions(+), 39 deletions(-) diff -Naur ./fs/efs/dir.c~blocksize ./fs/efs/dir.c --- ./fs/efs/dir.c~blocksize 2003-10-17 14:43:20.000000000 -0700 +++ ./fs/efs/dir.c 2003-10-21 20:28:34.000000000 -0700 @@ -19,10 +19,12 @@ .lookup = efs_lookup, }; -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 buffer_head *bh; - + struct buffer_head *bh_log; + unsigned long bh_log_offset; struct efs_dir *dirblock; struct efs_dentry *dirslot; efs_ino_t inodenum; @@ -44,14 +46,15 @@ /* look at all blocks */ while (block < inode->i_blocks) { /* read the dir block */ - bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); + bh = efs_bread(inode->i_sb, efs_bmap(inode, block), &bh_log_offset); if (!bh) { printk(KERN_ERR "EFS: readdir(): failed to read dir block %d\n", block); break; } - dirblock = (struct efs_dir *) bh->b_data; + bh_log = (void *)bh + bh_log_offset; + dirblock = (struct efs_dir *) bh_log->b_data; if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { printk(KERN_ERR "EFS: readdir(): invalid directory block\n"); @@ -65,7 +68,8 @@ continue; } - dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); + dirslot = (struct efs_dentry *) (((char *) bh_log->b_data) + + EFS_SLOTAT(dirblock, slot)); inodenum = be32_to_cpu(dirslot->inode); namelen = dirslot->namelen; @@ -110,4 +114,3 @@ unlock_kernel(); return 0; } - diff -Naur ./fs/efs/file.c~blocksize ./fs/efs/file.c --- ./fs/efs/file.c~blocksize 2003-10-17 14:43:15.000000000 -0700 +++ ./fs/efs/file.c 2003-10-21 20:34:45.000000000 -0700 @@ -35,8 +35,8 @@ return 0; } -int efs_bmap(struct inode *inode, efs_block_t block) { - +int efs_bmap(struct inode *inode, efs_block_t block) +{ if (block < 0) { printk(KERN_WARNING "EFS: bmap(): block < 0\n"); return 0; diff -Naur ./fs/efs/inode.c~blocksize ./fs/efs/inode.c --- ./fs/efs/inode.c~blocksize 2003-10-17 14:43:03.000000000 -0700 +++ ./fs/efs/inode.c 2003-10-21 21:27:36.000000000 -0700 @@ -52,7 +52,8 @@ int i, inode_index; dev_t device; u32 rdev; - struct buffer_head *bh; + struct buffer_head *bh, *bh_log; + unsigned long bh_log_offset; struct efs_sb_info *sb = SUPER_INFO(inode->i_sb); struct efs_inode_info *in = INODE_INFO(inode); efs_block_t block, offset; @@ -81,13 +82,14 @@ (EFS_BLOCKSIZE / sizeof(struct efs_dinode))) * sizeof(struct efs_dinode); - bh = sb_bread(inode->i_sb, block); + bh = efs_bread(inode->i_sb, block, &bh_log_offset); if (!bh) { printk(KERN_WARNING "EFS: bread() failed at block %d\n", block); goto read_inode_error; } - efs_inode = (struct efs_dinode *) (bh->b_data + offset); + bh_log = (void *)bh + bh_log_offset; + efs_inode = (struct efs_dinode *) (bh_log->b_data + offset); inode->i_mode = be16_to_cpu(efs_inode->di_mode); inode->i_nlink = be16_to_cpu(efs_inode->di_nlink); @@ -191,11 +193,13 @@ } } -efs_block_t efs_map_block(struct inode *inode, efs_block_t block) { +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; - + struct buffer_head *bh_log = NULL; + unsigned long bh_log_offset; int cur, last, first = 1; int ibase, ioffset, dirext, direxts, indext, indexts; efs_block_t iblock, result = 0, lastblock = 0; @@ -271,11 +275,12 @@ if (first || lastblock != iblock) { if (bh) brelse(bh); - bh = sb_bread(inode->i_sb, iblock); + bh = efs_bread(inode->i_sb, iblock, &bh_log_offset); if (!bh) { printk(KERN_ERR "EFS: bread() failed at block %d\n", iblock); return 0; } + bh_log = (void *)bh + bh_log_offset; #ifdef DEBUG printk(KERN_DEBUG "EFS: map_block(): read indirect extent block %d\n", iblock); #endif @@ -283,7 +288,7 @@ lastblock = iblock; } - exts = (efs_extent *) bh->b_data; + exts = (efs_extent *) bh_log->b_data; extent_copy(&(exts[ioffset]), &ext); @@ -304,4 +309,21 @@ return 0; } +struct buffer_head *efs_bread(struct super_block *sb, + sector_t block, unsigned long *bh_offset) +{ + struct efs_sb_info *sinfo = SUPER_INFO(sb); + unsigned blocking = sinfo->blocking; + sector_t phys_sector; + + if (blocking == 1) { + *bh_offset = 0; + return sb_bread(sb, block); + } + + *bh_offset = (block % blocking) * EFS_BLOCKSIZE; + phys_sector = block / blocking; + return sb_bread(sb, phys_sector); +} + MODULE_LICENSE("GPL"); diff -Naur ./fs/efs/namei.c~blocksize ./fs/efs/namei.c --- ./fs/efs/namei.c~blocksize 2003-10-17 14:43:20.000000000 -0700 +++ ./fs/efs/namei.c 2003-10-21 20:28:31.000000000 -0700 @@ -12,8 +12,8 @@ #include static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len) { - struct buffer_head *bh; - + struct buffer_head *bh, *bh_log; + unsigned long bh_log_offset; int slot, namelen; char *nameptr; struct efs_dir *dirblock; @@ -26,13 +26,14 @@ for(block = 0; block < inode->i_blocks; block++) { - bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); + bh = efs_bread(inode->i_sb, efs_bmap(inode, block), &bh_log_offset); if (!bh) { printk(KERN_ERR "EFS: find_entry(): failed to read dir block %d\n", block); return 0; } - dirblock = (struct efs_dir *) bh->b_data; + bh_log = (void *)bh + bh_log_offset; + dirblock = (struct efs_dir *) bh_log->b_data; if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { printk(KERN_ERR "EFS: find_entry(): invalid directory block\n"); @@ -41,7 +42,7 @@ } for(slot = 0; slot < dirblock->slots; slot++) { - dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); + dirslot = (struct efs_dentry *) (((char *) bh_log->b_data) + EFS_SLOTAT(dirblock, slot)); namelen = dirslot->namelen; nameptr = dirslot->name; @@ -74,4 +75,3 @@ d_add(dentry, inode); return NULL; } - diff -Naur ./fs/efs/super.c~blocksize ./fs/efs/super.c --- ./fs/efs/super.c~blocksize 2003-10-17 14:43:25.000000000 -0700 +++ ./fs/efs/super.c 2003-10-21 21:09:02.000000000 -0700 @@ -209,7 +209,9 @@ int efs_fill_super(struct super_block *s, void *d, int silent) { struct efs_sb_info *sb; - struct buffer_head *bh; + struct buffer_head *bh, *bh_log; + unsigned long bh_log_offset; + unsigned long blocksize; sb = kmalloc(sizeof(struct efs_sb_info), GFP_KERNEL); if (!sb) @@ -217,40 +219,47 @@ s->s_fs_info = sb; memset(sb, 0, sizeof(struct efs_sb_info)); - s->s_magic = EFS_SUPER_MAGIC; - if (!sb_set_blocksize(s, EFS_BLOCKSIZE)) { - printk(KERN_ERR "EFS: device does not support %d byte blocks\n", - EFS_BLOCKSIZE); - goto out_no_fs_ul; + s->s_magic = EFS_SUPER_MAGIC; + sb->blocking = 1; + for (blocksize = EFS_BLOCKSIZE; blocksize <= 4 * EFS_BLOCKSIZE; + blocksize += blocksize, sb->blocking += sb->blocking) { + if (!sb_set_blocksize(s, blocksize)) + printk(KERN_ERR "EFS: device does not support %ld byte blocks\n", + blocksize); + else + goto efs_have_blocksize; } - - /* read the vh (volume header) block */ - bh = sb_bread(s, 0); + goto out_no_fs_ul; +efs_have_blocksize: + /* read the vh (volume header) block */ + bh = efs_bread(s, 0, &bh_log_offset); if (!bh) { printk(KERN_ERR "EFS: cannot read volume header\n"); goto out_no_fs_ul; } + bh_log = (void *)bh + bh_log_offset; /* * if this returns zero then we didn't find any partition table. * this isn't (yet) an error - just assume for the moment that * the device is valid and go on to search for a superblock. */ - sb->fs_start = efs_validate_vh((struct volume_header *) bh->b_data); + sb->fs_start = efs_validate_vh((struct volume_header *) bh_log->b_data); brelse(bh); if (sb->fs_start == -1) { goto out_no_fs_ul; } - bh = sb_bread(s, sb->fs_start + EFS_SUPER); + bh = efs_bread(s, sb->fs_start + EFS_SUPER, &bh_log_offset); if (!bh) { printk(KERN_ERR "EFS: cannot read superblock\n"); goto out_no_fs_ul; } + bh_log = (void *)bh + bh_log_offset; - if (efs_validate_super(sb, (struct efs_super *) bh->b_data)) { + if (efs_validate_super(sb, (struct efs_super *) bh_log->b_data)) { #ifdef DEBUG printk(KERN_WARNING "EFS: invalid superblock at block %u\n", sb->fs_start + EFS_SUPER); #endif @@ -301,4 +310,3 @@ return 0; } - diff -Naur ./fs/efs/symlink.c~blocksize ./fs/efs/symlink.c --- ./fs/efs/symlink.c~blocksize 2003-10-17 14:43:16.000000000 -0700 +++ ./fs/efs/symlink.c 2003-10-21 20:39:05.000000000 -0700 @@ -15,7 +15,8 @@ static int efs_symlink_readpage(struct file *file, struct page *page) { char *link = kmap(page); - struct buffer_head * bh; + struct buffer_head * bh, *bh_log; + unsigned long bh_log_offset; struct inode * inode = page->mapping->host; efs_block_t size = inode->i_size; int err; @@ -27,16 +28,18 @@ lock_kernel(); /* read first 512 bytes of link target */ err = -EIO; - bh = sb_bread(inode->i_sb, efs_bmap(inode, 0)); + bh = efs_bread(inode->i_sb, efs_bmap(inode, 0), &bh_log_offset); if (!bh) goto fail; - memcpy(link, bh->b_data, (size > EFS_BLOCKSIZE) ? EFS_BLOCKSIZE : size); + bh_log = (void *)bh + bh_log_offset; + memcpy(link, bh_log->b_data, (size > EFS_BLOCKSIZE) ? EFS_BLOCKSIZE : size); brelse(bh); if (size > EFS_BLOCKSIZE) { - bh = sb_bread(inode->i_sb, efs_bmap(inode, 1)); + bh = efs_bread(inode->i_sb, efs_bmap(inode, 1), &bh_log_offset); if (!bh) goto fail; - memcpy(link + EFS_BLOCKSIZE, bh->b_data, size - EFS_BLOCKSIZE); + bh_log = (void *)bh + bh_log_offset; + memcpy(link + EFS_BLOCKSIZE, bh_log->b_data, size - EFS_BLOCKSIZE); brelse(bh); } link[size] = '\0'; diff -Naur ./include/linux/efs_fs.h~blocksize ./include/linux/efs_fs.h --- ./include/linux/efs_fs.h~blocksize 2003-10-17 14:43:04.000000000 -0700 +++ ./include/linux/efs_fs.h 2003-10-21 20:08:39.000000000 -0700 @@ -48,5 +48,7 @@ extern struct dentry *efs_lookup(struct inode *, struct dentry *, struct nameidata *); extern int efs_bmap(struct inode *, int); +extern struct buffer_head *efs_bread(struct super_block *sb, + sector_t block, unsigned long *bh_offset); #endif /* __EFS_FS_H__ */ diff -Naur ./include/linux/efs_fs_sb.h~blocksize ./include/linux/efs_fs_sb.h --- ./include/linux/efs_fs_sb.h~blocksize 2003-10-17 14:43:20.000000000 -0700 +++ ./include/linux/efs_fs_sb.h 2003-10-21 20:48:22.000000000 -0700 @@ -56,6 +56,7 @@ int32_t inode_free; /* # of free inodes */ short inode_blocks; /* # of blocks used for inodes in every grp */ short total_groups; /* # of groups */ + int32_t blocking; /* number of logical blocks per physical block */ }; #endif /* __EFS_FS_SB_H__ */