diff options
Diffstat (limited to 'fs/nilfs2/inode.c')
| -rw-r--r-- | fs/nilfs2/inode.c | 78 | 
1 files changed, 64 insertions, 14 deletions
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 39e038ac8fc..eccb2f2e231 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -27,6 +27,7 @@  #include <linux/writeback.h>  #include <linux/uio.h>  #include "nilfs.h" +#include "btnode.h"  #include "segment.h"  #include "page.h"  #include "mdt.h" @@ -197,11 +198,15 @@ static int nilfs_write_begin(struct file *file, struct address_space *mapping,  	if (unlikely(err))  		return err; -	*pagep = NULL; -	err = block_write_begin(file, mapping, pos, len, flags, pagep, -				fsdata, nilfs_get_block); -	if (unlikely(err)) +	err = block_write_begin(mapping, pos, len, flags, pagep, +				nilfs_get_block); +	if (unlikely(err)) { +		loff_t isize = mapping->host->i_size; +		if (pos + len > isize) +			vmtruncate(mapping->host, isize); +  		nilfs_transaction_abort(inode->i_sb); +	}  	return err;  } @@ -237,6 +242,19 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,  	/* Needs synchronization with the cleaner */  	size = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,  				  offset, nr_segs, nilfs_get_block, NULL); + +	/* +	 * In case of error extending write may have instantiated a few +	 * blocks outside i_size. Trim these off again. +	 */ +	if (unlikely((rw & WRITE) && size < 0)) { +		loff_t isize = i_size_read(inode); +		loff_t end = offset + iov_length(iov, nr_segs); + +		if (end > isize) +			vmtruncate(inode, isize); +	} +  	return size;  } @@ -337,7 +355,6 @@ void nilfs_free_inode(struct inode *inode)  	struct super_block *sb = inode->i_sb;  	struct nilfs_sb_info *sbi = NILFS_SB(sb); -	clear_inode(inode);  	/* XXX: check error code? Is there any thing I can do? */  	(void) nilfs_ifile_delete_inode(sbi->s_ifile, inode->i_ino);  	atomic_dec(&sbi->s_inodes_count); @@ -597,16 +614,34 @@ void nilfs_truncate(struct inode *inode)  	   But truncate has no return value. */  } -void nilfs_delete_inode(struct inode *inode) +static void nilfs_clear_inode(struct inode *inode) +{ +	struct nilfs_inode_info *ii = NILFS_I(inode); + +	/* +	 * Free resources allocated in nilfs_read_inode(), here. +	 */ +	BUG_ON(!list_empty(&ii->i_dirty)); +	brelse(ii->i_bh); +	ii->i_bh = NULL; + +	if (test_bit(NILFS_I_BMAP, &ii->i_state)) +		nilfs_bmap_clear(ii->i_bmap); + +	nilfs_btnode_cache_clear(&ii->i_btnode_cache); +} + +void nilfs_evict_inode(struct inode *inode)  {  	struct nilfs_transaction_info ti;  	struct super_block *sb = inode->i_sb;  	struct nilfs_inode_info *ii = NILFS_I(inode); -	if (unlikely(is_bad_inode(inode))) { +	if (inode->i_nlink || unlikely(is_bad_inode(inode))) {  		if (inode->i_data.nrpages)  			truncate_inode_pages(&inode->i_data, 0); -		clear_inode(inode); +		end_writeback(inode); +		nilfs_clear_inode(inode);  		return;  	}  	nilfs_transaction_begin(sb, &ti, 0); /* never fails */ @@ -616,6 +651,8 @@ void nilfs_delete_inode(struct inode *inode)  	nilfs_truncate_bmap(ii, 0);  	nilfs_mark_inode_dirty(inode); +	end_writeback(inode); +	nilfs_clear_inode(inode);  	nilfs_free_inode(inode);  	/* nilfs_free_inode() marks inode buffer dirty */  	if (IS_SYNC(inode)) @@ -639,14 +676,27 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr)  	err = nilfs_transaction_begin(sb, &ti, 0);  	if (unlikely(err))  		return err; -	err = inode_setattr(inode, iattr); -	if (!err && (iattr->ia_valid & ATTR_MODE)) + +	if ((iattr->ia_valid & ATTR_SIZE) && +	    iattr->ia_size != i_size_read(inode)) { +		err = vmtruncate(inode, iattr->ia_size); +		if (unlikely(err)) +			goto out_err; +	} + +	setattr_copy(inode, iattr); +	mark_inode_dirty(inode); + +	if (iattr->ia_valid & ATTR_MODE) {  		err = nilfs_acl_chmod(inode); -	if (likely(!err)) -		err = nilfs_transaction_commit(sb); -	else -		nilfs_transaction_abort(sb); +		if (unlikely(err)) +			goto out_err; +	} + +	return nilfs_transaction_commit(sb); +out_err: +	nilfs_transaction_abort(sb);  	return err;  }  |