diff options
Diffstat (limited to 'fs/omfs')
-rw-r--r-- | fs/omfs/dir.c | 22 | ||||
-rw-r--r-- | fs/omfs/file.c | 46 | ||||
-rw-r--r-- | fs/omfs/inode.c | 53 | ||||
-rw-r--r-- | fs/omfs/omfs.h | 1 | ||||
-rw-r--r-- | fs/omfs/omfs_fs.h | 1 |
5 files changed, 87 insertions, 36 deletions
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c index b42d62419034..393f3f659da7 100644 --- a/fs/omfs/dir.c +++ b/fs/omfs/dir.c @@ -25,11 +25,10 @@ static struct buffer_head *omfs_get_bucket(struct inode *dir, const char *name, int namelen, int *ofs) { int nbuckets = (dir->i_size - OMFS_DIR_START)/8; - int block = clus_to_blk(OMFS_SB(dir->i_sb), dir->i_ino); int bucket = omfs_hash(name, namelen, nbuckets); *ofs = OMFS_DIR_START + bucket * 8; - return sb_bread(dir->i_sb, block); + return omfs_bread(dir->i_sb, dir->i_ino); } static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block, @@ -42,8 +41,7 @@ static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block, *prev_block = ~0; while (block != ~0) { - bh = sb_bread(dir->i_sb, - clus_to_blk(OMFS_SB(dir->i_sb), block)); + bh = omfs_bread(dir->i_sb, block); if (!bh) { err = -EIO; goto err; @@ -86,11 +84,10 @@ static struct buffer_head *omfs_find_entry(struct inode *dir, int omfs_make_empty(struct inode *inode, struct super_block *sb) { struct omfs_sb_info *sbi = OMFS_SB(sb); - int block = clus_to_blk(sbi, inode->i_ino); struct buffer_head *bh; struct omfs_inode *oi; - bh = sb_bread(sb, block); + bh = omfs_bread(sb, inode->i_ino); if (!bh) return -ENOMEM; @@ -134,7 +131,7 @@ static int omfs_add_link(struct dentry *dentry, struct inode *inode) brelse(bh); /* now set the sibling and parent pointers on the new inode */ - bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), inode->i_ino)); + bh = omfs_bread(dir->i_sb, inode->i_ino); if (!bh) goto out; @@ -190,8 +187,7 @@ static int omfs_delete_entry(struct dentry *dentry) if (prev != ~0) { /* found in middle of list, get list ptr */ brelse(bh); - bh = sb_bread(dir->i_sb, - clus_to_blk(OMFS_SB(dir->i_sb), prev)); + bh = omfs_bread(dir->i_sb, prev); if (!bh) goto out; @@ -224,8 +220,7 @@ static int omfs_dir_is_empty(struct inode *inode) u64 *ptr; int i; - bh = sb_bread(inode->i_sb, clus_to_blk(OMFS_SB(inode->i_sb), - inode->i_ino)); + bh = omfs_bread(inode->i_sb, inode->i_ino); if (!bh) return 0; @@ -353,8 +348,7 @@ static int omfs_fill_chain(struct file *filp, void *dirent, filldir_t filldir, /* follow chain in this bucket */ while (fsblock != ~0) { - bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), - fsblock)); + bh = omfs_bread(dir->i_sb, fsblock); if (!bh) goto out; @@ -466,7 +460,7 @@ static int omfs_readdir(struct file *filp, void *dirent, filldir_t filldir) hchain = (filp->f_pos >> 20) - 1; hindex = filp->f_pos & 0xfffff; - bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), dir->i_ino)); + bh = omfs_bread(dir->i_sb, dir->i_ino); if (!bh) goto out; diff --git a/fs/omfs/file.c b/fs/omfs/file.c index 6e7a3291bbe8..8a6d34fa668a 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c @@ -50,7 +50,7 @@ int omfs_shrink_inode(struct inode *inode) if (inode->i_size != 0) goto out; - bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); + bh = omfs_bread(inode->i_sb, next); if (!bh) goto out; @@ -90,7 +90,7 @@ int omfs_shrink_inode(struct inode *inode) if (next == ~0) break; - bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); + bh = omfs_bread(inode->i_sb, next); if (!bh) goto out; oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]); @@ -222,7 +222,7 @@ static int omfs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh; sector_t next, offset; int ret; - u64 new_block; + u64 uninitialized_var(new_block); u32 max_extents; int extent_count; struct omfs_extent *oe; @@ -232,7 +232,7 @@ static int omfs_get_block(struct inode *inode, sector_t block, int remain; ret = -EIO; - bh = sb_bread(inode->i_sb, clus_to_blk(sbi, inode->i_ino)); + bh = omfs_bread(inode->i_sb, inode->i_ino); if (!bh) goto out; @@ -265,7 +265,7 @@ static int omfs_get_block(struct inode *inode, sector_t block, break; brelse(bh); - bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); + bh = omfs_bread(inode->i_sb, next); if (!bh) goto out; oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]); @@ -312,9 +312,17 @@ static int omfs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { - *pagep = NULL; - return block_write_begin(file, mapping, pos, len, flags, - pagep, fsdata, omfs_get_block); + int ret; + + ret = block_write_begin(mapping, pos, len, flags, pagep, + omfs_get_block); + if (unlikely(ret)) { + loff_t isize = mapping->host->i_size; + if (pos + len > isize) + vmtruncate(mapping->host, isize); + } + + return ret; } static sector_t omfs_bmap(struct address_space *mapping, sector_t block) @@ -333,7 +341,29 @@ const struct file_operations omfs_file_operations = { .splice_read = generic_file_splice_read, }; +static int omfs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + int error; + + error = inode_change_ok(inode, attr); + if (error) + return error; + + if ((attr->ia_valid & ATTR_SIZE) && + attr->ia_size != i_size_read(inode)) { + error = vmtruncate(inode, attr->ia_size); + if (error) + return error; + } + + setattr_copy(inode, attr); + mark_inode_dirty(inode); + return 0; +} + const struct inode_operations omfs_file_inops = { + .setattr = omfs_setattr, .truncate = omfs_truncate }; diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index 089839a6cc64..14a22863291a 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c @@ -19,6 +19,15 @@ MODULE_AUTHOR("Bob Copeland <me@bobcopeland.com>"); MODULE_DESCRIPTION("OMFS (ReplayTV/Karma) Filesystem for Linux"); MODULE_LICENSE("GPL"); +struct buffer_head *omfs_bread(struct super_block *sb, sector_t block) +{ + struct omfs_sb_info *sbi = OMFS_SB(sb); + if (block >= sbi->s_num_blocks) + return NULL; + + return sb_bread(sb, clus_to_blk(sbi, block)); +} + struct inode *omfs_new_inode(struct inode *dir, int mode) { struct inode *inode; @@ -93,15 +102,13 @@ static int __omfs_write_inode(struct inode *inode, int wait) struct omfs_inode *oi; struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb); struct buffer_head *bh, *bh2; - unsigned int block; u64 ctime; int i; int ret = -EIO; int sync_failed = 0; /* get current inode since we may have written sibling ptrs etc. */ - block = clus_to_blk(sbi, inode->i_ino); - bh = sb_bread(inode->i_sb, block); + bh = omfs_bread(inode->i_sb, inode->i_ino); if (!bh) goto out; @@ -140,8 +147,7 @@ static int __omfs_write_inode(struct inode *inode, int wait) /* if mirroring writes, copy to next fsblock */ for (i = 1; i < sbi->s_mirrors; i++) { - bh2 = sb_bread(inode->i_sb, block + i * - (sbi->s_blocksize / sbi->s_sys_blocksize)); + bh2 = omfs_bread(inode->i_sb, inode->i_ino + i); if (!bh2) goto out_brelse; @@ -175,9 +181,13 @@ int omfs_sync_inode(struct inode *inode) * called when an entry is deleted, need to clear the bits in the * bitmaps. */ -static void omfs_delete_inode(struct inode *inode) +static void omfs_evict_inode(struct inode *inode) { truncate_inode_pages(&inode->i_data, 0); + end_writeback(inode); + + if (inode->i_nlink) + return; if (S_ISREG(inode->i_mode)) { inode->i_size = 0; @@ -185,7 +195,6 @@ static void omfs_delete_inode(struct inode *inode) } omfs_clear_range(inode->i_sb, inode->i_ino, 2); - clear_inode(inode); } struct inode *omfs_iget(struct super_block *sb, ino_t ino) @@ -193,7 +202,6 @@ struct inode *omfs_iget(struct super_block *sb, ino_t ino) struct omfs_sb_info *sbi = OMFS_SB(sb); struct omfs_inode *oi; struct buffer_head *bh; - unsigned int block; u64 ctime; unsigned long nsecs; struct inode *inode; @@ -204,8 +212,7 @@ struct inode *omfs_iget(struct super_block *sb, ino_t ino) if (!(inode->i_state & I_NEW)) return inode; - block = clus_to_blk(sbi, ino); - bh = sb_bread(inode->i_sb, block); + bh = omfs_bread(inode->i_sb, ino); if (!bh) goto iget_failed; @@ -284,7 +291,7 @@ static int omfs_statfs(struct dentry *dentry, struct kstatfs *buf) static const struct super_operations omfs_sops = { .write_inode = omfs_write_inode, - .delete_inode = omfs_delete_inode, + .evict_inode = omfs_evict_inode, .put_super = omfs_put_super, .statfs = omfs_statfs, .show_options = generic_show_options, @@ -319,6 +326,9 @@ static int omfs_get_imap(struct super_block *sb) goto nomem; block = clus_to_blk(sbi, sbi->s_bitmap_ino); + if (block >= sbi->s_num_blocks) + goto nomem; + ptr = sbi->s_imap; for (count = bitmap_size; count > 0; count -= sb->s_blocksize) { bh = sb_bread(sb, block++); @@ -417,7 +427,6 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) struct omfs_root_block *omfs_rb; struct omfs_sb_info *sbi; struct inode *root; - sector_t start; int ret = -EINVAL; save_mount_options(sb, (char *) data); @@ -486,8 +495,7 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) sbi->s_block_shift = get_bitmask_order(sbi->s_blocksize) - get_bitmask_order(sbi->s_sys_blocksize); - start = clus_to_blk(sbi, be64_to_cpu(omfs_sb->s_root_block)); - bh2 = sb_bread(sb, start); + bh2 = omfs_bread(sb, be64_to_cpu(omfs_sb->s_root_block)); if (!bh2) goto out_brelse_bh; @@ -504,6 +512,21 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) goto out_brelse_bh2; } + if (sbi->s_bitmap_ino != ~0ULL && + sbi->s_bitmap_ino > sbi->s_num_blocks) { + printk(KERN_ERR "omfs: free space bitmap location is corrupt " + "(%llx, total blocks %llx)\n", + (unsigned long long) sbi->s_bitmap_ino, + (unsigned long long) sbi->s_num_blocks); + goto out_brelse_bh2; + } + if (sbi->s_clustersize < 1 || + sbi->s_clustersize > OMFS_MAX_CLUSTER_SIZE) { + printk(KERN_ERR "omfs: cluster size out of range (%d)", + sbi->s_clustersize); + goto out_brelse_bh2; + } + ret = omfs_get_imap(sb); if (ret) goto out_brelse_bh2; @@ -529,6 +552,8 @@ out_brelse_bh2: out_brelse_bh: brelse(bh); end: + if (ret) + kfree(sbi); return ret; } diff --git a/fs/omfs/omfs.h b/fs/omfs/omfs.h index ebe2fdbe535e..7d414fef501a 100644 --- a/fs/omfs/omfs.h +++ b/fs/omfs/omfs.h @@ -58,6 +58,7 @@ extern void omfs_make_empty_table(struct buffer_head *bh, int offset); extern int omfs_shrink_inode(struct inode *inode); /* inode.c */ +extern struct buffer_head *omfs_bread(struct super_block *sb, sector_t block); extern struct inode *omfs_iget(struct super_block *sb, ino_t inode); extern struct inode *omfs_new_inode(struct inode *dir, int mode); extern int omfs_reserve_block(struct super_block *sb, sector_t block); diff --git a/fs/omfs/omfs_fs.h b/fs/omfs/omfs_fs.h index 12cca245d6e8..ee5e4327de92 100644 --- a/fs/omfs/omfs_fs.h +++ b/fs/omfs/omfs_fs.h @@ -17,6 +17,7 @@ #define OMFS_EXTENT_CONT 0x40 #define OMFS_XOR_COUNT 19 #define OMFS_MAX_BLOCK_SIZE 8192 +#define OMFS_MAX_CLUSTER_SIZE 8 struct omfs_super_block { char s_fill1[256]; |