From eafdc7d190a944c755a9fe68573c193e6e0217e7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 4 Jun 2010 11:29:53 +0200 Subject: sort out blockdev_direct_IO variants Move the call to vmtruncate to get rid of accessive blocks to the callers in prepearation of the new truncate calling sequence. This was only done for DIO_LOCKING filesystems, so the __blockdev_direct_IO_newtrunc variant was not needed anyway. Get rid of blockdev_direct_IO_no_locking and its _newtrunc variant while at it as just opencoding the two additional paramters is shorted than the name suffix. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/ext2/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/ext2/inode.c') diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 3675088cb88c..f36e967e4fde 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -838,7 +838,7 @@ ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, struct inode *inode = mapping->host; ssize_t ret; - ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev, + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, ext2_get_block, NULL); if (ret < 0 && (rw & WRITE)) ext2_write_failed(mapping, offset + iov_length(iov, nr_segs)); -- cgit v1.2.2 From ea0f04e59543bafb3d2cbe37a0d375acb0bb2c34 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 4 Jun 2010 11:29:54 +0200 Subject: get rid of nobh_write_begin_newtrunc Move the call to vmtruncate to get rid of accessive blocks to the only remaining caller and rename the non-truncating version to nobh_write_begin. Get rid of the superflous file argument to it while we're at it. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/ext2/inode.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'fs/ext2/inode.c') diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index f36e967e4fde..348805cd4109 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -806,13 +806,8 @@ ext2_nobh_write_begin(struct file *file, struct address_space *mapping, { int ret; - /* - * Dir-in-pagecache still uses ext2_write_begin. Would have to rework - * directory handling code to pass around offsets rather than struct - * pages in order to make this work easily. - */ - ret = nobh_write_begin_newtrunc(file, mapping, pos, len, flags, pagep, - fsdata, ext2_get_block); + ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata, + ext2_get_block); if (ret < 0) ext2_write_failed(mapping, pos + len); return ret; -- cgit v1.2.2 From f4e420dc423148fba637af1ab618fa8896dfb2d6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 4 Jun 2010 11:29:56 +0200 Subject: clean up write_begin usage for directories in pagecache For filesystem that implement directories in pagecache we call block_write_begin with an already allocated page for this code, while the normal regular file write path uses the default block_write_begin behaviour. Get rid of the __foofs_write_begin helper and opencode the normal write_begin call in foofs_write_begin, while adding a new foofs_prepare_chunk helper for the directory code. The added benefit is that foofs_prepare_chunk has a much saner calling convention. Note that the interruptible flag passed into block_write_begin is always ignored if we already pass in a page (see next patch for details), and we never were doing truncations of exessive blocks for this case either so we can switch directly to block_write_begin_newtrunc. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/ext2/inode.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'fs/ext2/inode.c') diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 348805cd4109..2f4dfbcd7696 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -765,14 +765,6 @@ ext2_readpages(struct file *file, struct address_space *mapping, return mpage_readpages(mapping, pages, nr_pages, ext2_get_block); } -int __ext2_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -{ - return block_write_begin_newtrunc(file, mapping, pos, len, flags, - pagep, fsdata, ext2_get_block); -} - static int ext2_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, @@ -781,7 +773,8 @@ ext2_write_begin(struct file *file, struct address_space *mapping, int ret; *pagep = NULL; - ret = __ext2_write_begin(file, mapping, pos, len, flags, pagep, fsdata); + ret = block_write_begin_newtrunc(file, mapping, pos, len, flags, + pagep, fsdata, ext2_get_block); if (ret < 0) ext2_write_failed(mapping, pos + len); return ret; -- cgit v1.2.2 From 155130a4f7848b1aac439cab6bda1a175507c71c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 4 Jun 2010 11:29:58 +0200 Subject: get rid of block_write_begin_newtrunc Move the call to vmtruncate to get rid of accessive blocks to the callers in preparation of the new truncate sequence and rename the non-truncating version to block_write_begin. While we're at it also remove several unused arguments to block_write_begin. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/ext2/inode.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'fs/ext2/inode.c') diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 2f4dfbcd7696..74dfe5f73330 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -772,9 +772,8 @@ ext2_write_begin(struct file *file, struct address_space *mapping, { int ret; - *pagep = NULL; - ret = block_write_begin_newtrunc(file, mapping, pos, len, flags, - pagep, fsdata, ext2_get_block); + ret = block_write_begin(mapping, pos, len, flags, pagep, + ext2_get_block); if (ret < 0) ext2_write_failed(mapping, pos + len); return ret; -- cgit v1.2.2 From 6a1a90ad1b0edb556a7550a6ef8a8756f0304dd5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 4 Jun 2010 11:30:00 +0200 Subject: rename generic_setattr Despite its name it's now a generic implementation of ->setattr, but rather a helper to copy attributes from a struct iattr to the inode. Rename it to setattr_copy to reflect this fact. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/ext2/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/ext2/inode.c') diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 74dfe5f73330..7dee7b3f3688 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1544,7 +1544,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) if (error) return error; } - generic_setattr(inode, iattr); + setattr_copy(inode, iattr); if (iattr->ia_valid & ATTR_MODE) error = ext2_acl_chmod(inode); mark_inode_dirty(inode); -- cgit v1.2.2 From 2c27c65ed0696f0b5df2dad2cf6462d72164d547 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 4 Jun 2010 11:30:04 +0200 Subject: check ATTR_SIZE contraints in inode_change_ok Make sure we check the truncate constraints early on in ->setattr by adding those checks to inode_change_ok. Also clean up and document inode_change_ok to make this obvious. As a fallout we don't have to call inode_newsize_ok from simple_setsize and simplify it down to a truncate_setsize which doesn't return an error. This simplifies a lot of setattr implementations and means we use truncate_setsize almost everywhere. Get rid of fat_setsize now that it's trivial and mark ext2_setsize static to make the calling convention obvious. Keep the inode_newsize_ok in vmtruncate for now as all callers need an audit for its removal anyway. Note: setattr code in ecryptfs doesn't call inode_change_ok at all and needs a deeper audit, but that is left for later. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/ext2/inode.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'fs/ext2/inode.c') diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 7dee7b3f3688..069620b30d4d 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1156,15 +1156,10 @@ static void ext2_truncate_blocks(struct inode *inode, loff_t offset) __ext2_truncate_blocks(inode, offset); } -int ext2_setsize(struct inode *inode, loff_t newsize) +static int ext2_setsize(struct inode *inode, loff_t newsize) { - loff_t oldsize; int error; - error = inode_newsize_ok(inode, newsize); - if (error) - return error; - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) return -EINVAL; @@ -1184,10 +1179,7 @@ int ext2_setsize(struct inode *inode, loff_t newsize) if (error) return error; - oldsize = inode->i_size; - i_size_write(inode, newsize); - truncate_pagecache(inode, oldsize, newsize); - + truncate_setsize(inode, newsize); __ext2_truncate_blocks(inode, newsize); inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; -- cgit v1.2.2 From addacc7d6f0f0bcce12adf9fe9e6455e1dfd74da Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 22 Jul 2010 01:19:42 +0400 Subject: Take dirtying the inode to callers of ext2_free_blocks() Signed-off-by: Al Viro --- fs/ext2/inode.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'fs/ext2/inode.c') diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 069620b30d4d..e8af26dd6715 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -423,6 +423,8 @@ static int ext2_alloc_blocks(struct inode *inode, failed_out: for (i = 0; i 0) { - mark_inode_dirty(inode); ext2_free_blocks (inode, block_to_free, count); + mark_inode_dirty(inode); } } -- cgit v1.2.2 From 72edc4d0873ba5165c0759264298bf5f55351c7a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 4 Jun 2010 23:32:28 -0400 Subject: merge ext2 delete_inode and clear_inode, switch to ->evict_inode() Signed-off-by: Al Viro --- fs/ext2/inode.c | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) (limited to 'fs/ext2/inode.c') diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index e8af26dd6715..940c96168868 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -69,26 +69,42 @@ static void ext2_write_failed(struct address_space *mapping, loff_t to) /* * Called at the last iput() if i_nlink is zero. */ -void ext2_delete_inode (struct inode * inode) +void ext2_evict_inode(struct inode * inode) { - if (!is_bad_inode(inode)) + struct ext2_block_alloc_info *rsv; + int want_delete = 0; + + if (!inode->i_nlink && !is_bad_inode(inode)) { + want_delete = 1; dquot_initialize(inode); + } else { + dquot_drop(inode); + } + truncate_inode_pages(&inode->i_data, 0); - if (is_bad_inode(inode)) - goto no_delete; - EXT2_I(inode)->i_dtime = get_seconds(); - mark_inode_dirty(inode); - __ext2_write_inode(inode, inode_needs_sync(inode)); + if (want_delete) { + /* set dtime */ + EXT2_I(inode)->i_dtime = get_seconds(); + mark_inode_dirty(inode); + __ext2_write_inode(inode, inode_needs_sync(inode)); + /* truncate to 0 */ + inode->i_size = 0; + if (inode->i_blocks) + ext2_truncate_blocks(inode, 0); + } - inode->i_size = 0; - if (inode->i_blocks) - ext2_truncate_blocks(inode, 0); - ext2_free_inode (inode); + invalidate_inode_buffers(inode); + end_writeback(inode); + + ext2_discard_reservation(inode); + rsv = EXT2_I(inode)->i_block_alloc_info; + EXT2_I(inode)->i_block_alloc_info = NULL; + if (unlikely(rsv)) + kfree(rsv); - return; -no_delete: - clear_inode(inode); /* We must guarantee clearing of inode... */ + if (want_delete) + ext2_free_inode(inode); } typedef struct { -- cgit v1.2.2