Cc: Christoph Hellwig <hch@xxxxxx> Signed-off-by: Nick Piggin <npiggin@xxxxxxx> --- fs/minix/file.c | 3 + fs/minix/inode.c | 82 +++++++++++++++++++++++++++++++++++++++++++----- fs/minix/itree_common.c | 5 +- fs/minix/itree_v1.c | 4 +- fs/minix/itree_v2.c | 4 +- fs/minix/minix.h | 6 +-- 6 files changed, 85 insertions(+), 19 deletions(-) Index: linux-2.6/fs/minix/file.c =================================================================== --- linux-2.6.orig/fs/minix/file.c +++ linux-2.6/fs/minix/file.c @@ -24,6 +24,7 @@ const struct file_operations minix_file_ }; const struct inode_operations minix_file_inode_operations = { - .truncate = minix_truncate, + .new_truncate = 1, + .setattr = minix_setattr, .getattr = minix_getattr, }; Index: linux-2.6/fs/minix/inode.c =================================================================== --- linux-2.6.orig/fs/minix/inode.c +++ linux-2.6/fs/minix/inode.c @@ -18,15 +18,16 @@ #include <linux/highuid.h> #include <linux/vfs.h> -static int minix_write_inode(struct inode * inode, int wait); +static int minix_write_inode(struct inode *inode, int wait); static int minix_statfs(struct dentry *dentry, struct kstatfs *buf); -static int minix_remount (struct super_block * sb, int * flags, char * data); +static int minix_remount(struct super_block *sb, int *flags, char *data); +static void minix_truncate_blocks(struct inode *inode, loff_t offset); static void minix_delete_inode(struct inode *inode) { truncate_inode_pages(&inode->i_data, 0); inode->i_size = 0; - minix_truncate(inode); + minix_truncate_blocks(inode, 0); minix_free_inode(inode); } @@ -367,8 +368,33 @@ static int minix_write_begin(struct file loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { + int ret; + *pagep = NULL; - return __minix_write_begin(file, mapping, pos, len, flags, pagep, fsdata); + ret = __minix_write_begin(file, mapping, pos, len, flags, pagep,fsdata); + if (ret < 0) { + struct inode *inode = mapping->host; + loff_t isize = inode->i_size; + if (pos + len > isize) + minix_truncate_blocks(inode, isize); + } + return ret; +} + +static int minix_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ + int ret; + + ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); + if (ret < len) { + struct inode *inode = mapping->host; + loff_t isize = inode->i_size; + if (pos + len > isize) + minix_truncate_blocks(inode, isize); + } + return ret; } static sector_t minix_bmap(struct address_space *mapping, sector_t block) @@ -381,7 +407,7 @@ static const struct address_space_operat .writepage = minix_writepage, .sync_page = block_sync_page, .write_begin = minix_write_begin, - .write_end = generic_write_end, + .write_end = minix_write_end, .bmap = minix_bmap }; @@ -591,14 +617,54 @@ int minix_getattr(struct vfsmount *mnt, /* * The function that is called for file truncation. */ -void minix_truncate(struct inode * inode) +static void minix_truncate_blocks(struct inode *inode, loff_t offset) { if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) return; if (INODE_VERSION(inode) == MINIX_V1) - V1_minix_truncate(inode); + V1_minix_truncate_blocks(inode, offset); else - V2_minix_truncate(inode); + V2_minix_truncate_blocks(inode, offset); +} + +static int minix_setsize(struct inode *inode, loff_t newsize) +{ + loff_t oldsize; + int error; + + error = inode_newsize_ok(inode, newsize); + if (error) + return error; + + oldsize = inode->i_size; + i_size_write(inode, newsize); + truncate_pagecache(inode, oldsize, newsize); + + error = block_truncate_page(inode->i_mapping, newsize, minix_get_block); + if (error) + return error; + minix_truncate_blocks(inode, newsize); + + return error; +} + +int minix_setattr(struct dentry *dentry, struct iattr *iattr) +{ + struct inode *inode = dentry->d_inode; + int error; + + error = inode_change_ok(inode, iattr); + if (error) + return error; + if (iattr->ia_valid & ATTR_SIZE) { + error = minix_setsize(inode, iattr->ia_size); + if (error) + return error; + } + generic_setattr(inode, iattr); + mark_inode_dirty(inode); + + return error; } static int minix_get_sb(struct file_system_type *fs_type, Index: linux-2.6/fs/minix/itree_common.c =================================================================== --- linux-2.6.orig/fs/minix/itree_common.c +++ linux-2.6/fs/minix/itree_common.c @@ -290,7 +290,7 @@ static void free_branches(struct inode * free_data(inode, p, q); } -static inline void truncate (struct inode * inode) +static inline void truncate_blocks(struct inode *inode, loff_t offset) { struct super_block *sb = inode->i_sb; block_t *idata = i_data(inode); @@ -302,8 +302,7 @@ static inline void truncate (struct inod int first_whole; long iblock; - iblock = (inode->i_size + sb->s_blocksize -1) >> sb->s_blocksize_bits; - block_truncate_page(inode->i_mapping, inode->i_size, get_block); + iblock = (offset + sb->s_blocksize - 1) >> sb->s_blocksize_bits; n = block_to_path(inode, iblock, offsets); if (!n) Index: linux-2.6/fs/minix/itree_v1.c =================================================================== --- linux-2.6.orig/fs/minix/itree_v1.c +++ linux-2.6/fs/minix/itree_v1.c @@ -55,9 +55,9 @@ int V1_minix_get_block(struct inode * in return get_block(inode, block, bh_result, create); } -void V1_minix_truncate(struct inode * inode) +void V1_minix_truncate_blocks(struct inode *inode, loff_t offset) { - truncate(inode); + truncate_blocks(inode, offset); } unsigned V1_minix_blocks(loff_t size, struct super_block *sb) Index: linux-2.6/fs/minix/itree_v2.c =================================================================== --- linux-2.6.orig/fs/minix/itree_v2.c +++ linux-2.6/fs/minix/itree_v2.c @@ -61,9 +61,9 @@ int V2_minix_get_block(struct inode * in return get_block(inode, block, bh_result, create); } -void V2_minix_truncate(struct inode * inode) +void V2_minix_truncate_blocks(struct inode *inode, loff_t offset) { - truncate(inode); + truncate_blocks(inode, offset); } unsigned V2_minix_blocks(loff_t size, struct super_block *sb) Index: linux-2.6/fs/minix/minix.h =================================================================== --- linux-2.6.orig/fs/minix/minix.h +++ linux-2.6/fs/minix/minix.h @@ -52,14 +52,14 @@ extern unsigned long minix_count_free_in extern int minix_new_block(struct inode * inode); extern void minix_free_block(struct inode *inode, unsigned long block); extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi); +extern int minix_setattr(struct dentry *dentry, struct iattr *iattr); extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int __minix_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata); -extern void V1_minix_truncate(struct inode *); -extern void V2_minix_truncate(struct inode *); -extern void minix_truncate(struct inode *); +extern void V1_minix_truncate_blocks(struct inode *, loff_t); +extern void V2_minix_truncate_blocks(struct inode *, loff_t); extern void minix_set_inode(struct inode *, dev_t); extern int V1_minix_get_block(struct inode *, long, struct buffer_head *, int); extern int V2_minix_get_block(struct inode *, long, struct buffer_head *, int); -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html