Signed-off-by: Christoph Hellwig <hch@xxxxxx> Index: vfs-2.6.git/fs/sysv/file.c =================================================================== --- vfs-2.6.git.orig/fs/sysv/file.c 2009-09-22 15:23:55.049764156 -0300 +++ vfs-2.6.git/fs/sysv/file.c 2009-09-22 15:35:52.993764871 -0300 @@ -31,6 +31,7 @@ const struct file_operations sysv_file_o }; const struct inode_operations sysv_file_inode_operations = { - .truncate = sysv_truncate, + .truncate_kludge_to_be_killed = 1, + .setattr = sysv_setattr, .getattr = sysv_getattr, }; Index: vfs-2.6.git/fs/sysv/inode.c =================================================================== --- vfs-2.6.git.orig/fs/sysv/inode.c 2009-09-22 15:23:55.077764435 -0300 +++ vfs-2.6.git/fs/sysv/inode.c 2009-09-22 15:31:45.210264810 -0300 @@ -305,7 +305,8 @@ static void sysv_delete_inode(struct ino { truncate_inode_pages(&inode->i_data, 0); inode->i_size = 0; - sysv_truncate(inode); + if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) + sysv_truncate_blocks(inode, 0); sysv_free_inode(inode); } Index: vfs-2.6.git/fs/sysv/itree.c =================================================================== --- vfs-2.6.git.orig/fs/sysv/itree.c 2009-09-22 15:23:55.121765981 -0300 +++ vfs-2.6.git/fs/sysv/itree.c 2009-09-22 15:39:17.898295684 -0300 @@ -360,7 +360,7 @@ static void free_branches(struct inode * free_data(inode, p, q); } -void sysv_truncate (struct inode * inode) +void sysv_truncate_blocks(struct inode *inode, loff_t offset) { sysv_zone_t *i_data = SYSV_I(inode)->i_data; int offsets[DEPTH]; @@ -371,15 +371,8 @@ void sysv_truncate (struct inode * inode long iblock; unsigned blocksize; - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - S_ISLNK(inode->i_mode))) - return; - blocksize = inode->i_sb->s_blocksize; - iblock = (inode->i_size + blocksize-1) - >> inode->i_sb->s_blocksize_bits; - - block_truncate_page(inode->i_mapping, inode->i_size, get_block); + iblock = (offset + blocksize - 1) >> inode->i_sb->s_blocksize_bits; n = block_to_path(inode, iblock, offsets); if (n == 0) @@ -449,6 +442,47 @@ int sysv_getattr(struct vfsmount *mnt, s return 0; } +static int sysv_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, get_block); + if (error) + return error; + + sysv_truncate_blocks(inode, newsize); + return 0; +} + +int sysv_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 = sysv_setsize(inode, iattr->ia_size); + if (error) + return error; + } + + generic_setattr(inode, iattr); + mark_inode_dirty(inode); + return 0; +} + static int sysv_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page,get_block,wbc); @@ -471,8 +505,33 @@ static int sysv_write_begin(struct file loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { + int ret; + *pagep = NULL; - return __sysv_write_begin(file, mapping, pos, len, flags, pagep, fsdata); + ret = __sysv_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) + sysv_truncate_blocks(inode, isize); + } + return ret; +} + +static int sysv_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) + sysv_truncate_blocks(inode, isize); + } + return ret; } static sector_t sysv_bmap(struct address_space *mapping, sector_t block) @@ -485,6 +544,6 @@ const struct address_space_operations sy .writepage = sysv_writepage, .sync_page = block_sync_page, .write_begin = sysv_write_begin, - .write_end = generic_write_end, + .write_end = sysv_write_end, .bmap = sysv_bmap }; Index: vfs-2.6.git/fs/sysv/sysv.h =================================================================== --- vfs-2.6.git.orig/fs/sysv/sysv.h 2009-09-22 15:23:55.097764604 -0300 +++ vfs-2.6.git/fs/sysv/sysv.h 2009-09-22 15:32:51.722266473 -0300 @@ -135,7 +135,7 @@ extern void sysv_free_block(struct super extern unsigned long sysv_count_free_blocks(struct super_block *); /* itree.c */ -extern void sysv_truncate(struct inode *); +extern void sysv_truncate_blocks(struct inode *, loff_t); extern int __sysv_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata); @@ -146,6 +146,7 @@ extern int sysv_write_inode(struct inode extern int sysv_sync_inode(struct inode *); extern void sysv_set_inode(struct inode *, dev_t); extern int sysv_getattr(struct vfsmount *, struct dentry *, struct kstat *); +extern int sysv_setattr(struct dentry *dentry, struct iattr *iattr); extern int sysv_init_icache(void); extern void sysv_destroy_icache(void); -- 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