From 7b6d91daee5cac6402186ff224c3af39d79f4a0e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 7 Aug 2010 18:20:39 +0200 Subject: block: unify flags for struct bio and struct request Remove the current bio flags and reuse the request flags for the bio, too. This allows to more easily trace the type of I/O from the filesystem down to the block driver. There were two flags in the bio that were missing in the requests: BIO_RW_UNPLUG and BIO_RW_AHEAD. Also I've renamed two request flags that had a superflous RW in them. Note that the flags are in bio.h despite having the REQ_ name - as blkdev.h includes bio.h that is the only way to go for now. Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe --- fs/nilfs2/segbuf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index 2e6a2723b8fa..4588fb9e93df 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c @@ -508,7 +508,7 @@ static int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf, * Last BIO is always sent through the following * submission. */ - rw |= (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG); + rw |= REQ_SYNC | REQ_UNPLUG; res = nilfs_segbuf_submit_bio(segbuf, &wi, rw); } -- cgit v1.2.1 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/nilfs2/inode.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 39e038ac8fcb..1dd9e6a7d787 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -237,6 +237,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; } -- cgit v1.2.1 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/nilfs2/dir.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c index 85c89dfc71f0..fc2bcfa599a3 100644 --- a/fs/nilfs2/dir.c +++ b/fs/nilfs2/dir.c @@ -80,23 +80,11 @@ static unsigned nilfs_last_byte(struct inode *inode, unsigned long page_nr) return last_byte; } -static int nilfs_prepare_chunk_uninterruptible(struct page *page, - struct address_space *mapping, - unsigned from, unsigned to) +static int nilfs_prepare_chunk(struct page *page, unsigned from, unsigned to) { loff_t pos = page_offset(page) + from; - return block_write_begin(NULL, mapping, pos, to - from, - AOP_FLAG_UNINTERRUPTIBLE, &page, - NULL, nilfs_get_block); -} - -static int nilfs_prepare_chunk(struct page *page, - struct address_space *mapping, - unsigned from, unsigned to) -{ - loff_t pos = page_offset(page) + from; - return block_write_begin(NULL, mapping, pos, to - from, 0, &page, - NULL, nilfs_get_block); + return block_write_begin_newtrunc(NULL, page->mapping, pos, to - from, + 0, &page, NULL, nilfs_get_block); } static void nilfs_commit_chunk(struct page *page, @@ -449,7 +437,7 @@ void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de, int err; lock_page(page); - err = nilfs_prepare_chunk_uninterruptible(page, mapping, from, to); + err = nilfs_prepare_chunk(page, from, to); BUG_ON(err); de->inode = cpu_to_le64(inode->i_ino); nilfs_set_de_type(de, inode); @@ -530,7 +518,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode) got_it: from = (char *)de - (char *)page_address(page); to = from + rec_len; - err = nilfs_prepare_chunk(page, page->mapping, from, to); + err = nilfs_prepare_chunk(page, from, to); if (err) goto out_unlock; if (de->inode) { @@ -587,7 +575,7 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page) if (pde) from = (char *)pde - (char *)page_address(page); lock_page(page); - err = nilfs_prepare_chunk(page, mapping, from, to); + err = nilfs_prepare_chunk(page, from, to); BUG_ON(err); if (pde) pde->rec_len = cpu_to_le16(to - from); @@ -615,7 +603,7 @@ int nilfs_make_empty(struct inode *inode, struct inode *parent) if (!page) return -ENOMEM; - err = nilfs_prepare_chunk(page, mapping, 0, chunk_size); + err = nilfs_prepare_chunk(page, 0, chunk_size); if (unlikely(err)) { unlock_page(page); goto fail; -- cgit v1.2.1 From 6e1db88d536adcbbfe562b2d4b7d6425784fff12 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 4 Jun 2010 11:29:57 +0200 Subject: introduce __block_write_begin Split up the block_write_begin implementation - __block_write_begin is a new trivial wrapper for block_prepare_write that always takes an already allocated page and can be either called from block_write_begin or filesystem code that already has a page allocated. Remove the handling of already allocated pages from block_write_begin after switching all callers that do it to __block_write_begin. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/nilfs2/dir.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c index fc2bcfa599a3..d14e3b94d81f 100644 --- a/fs/nilfs2/dir.c +++ b/fs/nilfs2/dir.c @@ -83,8 +83,7 @@ static unsigned nilfs_last_byte(struct inode *inode, unsigned long page_nr) static int nilfs_prepare_chunk(struct page *page, unsigned from, unsigned to) { loff_t pos = page_offset(page) + from; - return block_write_begin_newtrunc(NULL, page->mapping, pos, to - from, - 0, &page, NULL, nilfs_get_block); + return __block_write_begin(page, pos, to - from, nilfs_get_block); } static void nilfs_commit_chunk(struct page *page, -- cgit v1.2.1 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/nilfs2/inode.c | 12 ++++++++---- fs/nilfs2/recovery.c | 11 +++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 1dd9e6a7d787..5c694ece172e 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -197,11 +197,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; } diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index bae2a516b4ee..2f11f0868d87 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c @@ -505,11 +505,14 @@ static int recover_dsync_blocks(struct nilfs_sb_info *sbi, } pos = rb->blkoff << inode->i_blkbits; - page = NULL; - err = block_write_begin(NULL, inode->i_mapping, pos, blocksize, - 0, &page, NULL, nilfs_get_block); - if (unlikely(err)) + err = block_write_begin(inode->i_mapping, pos, blocksize, + 0, &page, nilfs_get_block); + if (unlikely(err)) { + loff_t isize = inode->i_size; + if (pos + blocksize > isize) + vmtruncate(inode, isize); goto failed_inode; + } err = nilfs_recovery_copy_block(sbi, rb, page); if (unlikely(err)) -- cgit v1.2.1 From 1025774ce411f2bd4b059ad7b53f0003569b74fa Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 4 Jun 2010 11:30:02 +0200 Subject: remove inode_setattr Replace inode_setattr with opencoded variants of it in all callers. This moves the remaining call to vmtruncate into the filesystem methods where it can be replaced with the proper truncate sequence. In a few cases it was obvious that we would never end up calling vmtruncate so it was left out in the opencoded variant: spufs: explicitly checks for ATTR_SIZE earlier btrfs,hugetlbfs,logfs,dlmfs: explicitly clears ATTR_SIZE earlier ufs: contains an opencoded simple_seattr + truncate that sets the filesize just above In addition to that ncpfs called inode_setattr with handcrafted iattrs, which allowed to trim down the opencoded variant. Signed-off-by: Christoph Hellwig Signed-off-by: Al Viro --- fs/nilfs2/inode.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 5c694ece172e..051d279abb37 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -656,14 +656,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; } -- cgit v1.2.1 From a4ffdde6e56fdf8c34ddadc2674d6eb978083369 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 Jun 2010 17:38:30 -0400 Subject: simplify checks for I_CLEAR/I_FREEING add I_CLEAR instead of replacing I_FREEING with it. I_CLEAR is equivalent to I_FREEING for almost all code looking at either; it's there to keep track of having called clear_inode() exactly once per inode lifetime, at some point after having set I_FREEING. I_CLEAR and I_FREEING never get set at the same time with the current code, so we can switch to setting i_flags to I_FREEING | I_CLEAR instead of I_CLEAR without loss of information. As the result of such change, checks become simpler and the amount of code that needs to know about I_CLEAR shrinks a lot. Signed-off-by: Al Viro --- fs/nilfs2/gcdat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/gcdat.c b/fs/nilfs2/gcdat.c index dd5f7e0a95f6..84a45d1d5464 100644 --- a/fs/nilfs2/gcdat.c +++ b/fs/nilfs2/gcdat.c @@ -78,7 +78,7 @@ void nilfs_clear_gcdat_inode(struct the_nilfs *nilfs) struct inode *gcdat = nilfs->ns_gc_dat; struct nilfs_inode_info *gii = NILFS_I(gcdat); - gcdat->i_state = I_CLEAR; + gcdat->i_state = I_FREEING | I_CLEAR; gii->i_flags = 0; nilfs_palloc_clear_cache(gcdat); -- cgit v1.2.1 From 6fd1e5c994c392ebdbe45600051b2a32ec4860f1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 7 Jun 2010 11:55:00 -0400 Subject: convert nilfs2 to ->evict_inode() [folded build fix from sfr] Signed-off-by: Al Viro --- fs/nilfs2/inode.c | 28 ++++++++++++++++++++++++---- fs/nilfs2/nilfs.h | 2 +- fs/nilfs2/super.c | 20 +------------------- 3 files changed, 26 insertions(+), 24 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 051d279abb37..eccb2f2e2315 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -27,6 +27,7 @@ #include #include #include "nilfs.h" +#include "btnode.h" #include "segment.h" #include "page.h" #include "mdt.h" @@ -354,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); @@ -614,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 */ @@ -633,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)) diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 47d6d7928122..f03279748099 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -245,7 +245,7 @@ extern void nilfs_write_inode_common(struct inode *, struct nilfs_inode *, int); extern struct inode *nilfs_iget(struct super_block *, unsigned long); extern void nilfs_update_inode(struct inode *, struct buffer_head *); extern void nilfs_truncate(struct inode *); -extern void nilfs_delete_inode(struct inode *); +extern void nilfs_evict_inode(struct inode *); extern int nilfs_setattr(struct dentry *, struct iattr *); extern int nilfs_load_inode_block(struct nilfs_sb_info *, struct inode *, struct buffer_head **); diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 414ef68931cf..7c7572a4e138 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -159,23 +159,6 @@ void nilfs_destroy_inode(struct inode *inode) kmem_cache_free(nilfs_inode_cachep, NILFS_I(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); -} - static int nilfs_sync_super(struct nilfs_sb_info *sbi, int dupsb) { struct the_nilfs *nilfs = sbi->s_nilfs; @@ -467,7 +450,7 @@ static const struct super_operations nilfs_sops = { /* .write_inode = nilfs_write_inode, */ /* .put_inode = nilfs_put_inode, */ /* .drop_inode = nilfs_drop_inode, */ - .delete_inode = nilfs_delete_inode, + .evict_inode = nilfs_evict_inode, .put_super = nilfs_put_super, /* .write_super = nilfs_write_super, */ .sync_fs = nilfs_sync_fs, @@ -475,7 +458,6 @@ static const struct super_operations nilfs_sops = { /* .unlockfs */ .statfs = nilfs_statfs, .remount_fs = nilfs_remount, - .clear_inode = nilfs_clear_inode, /* .umount_begin */ .show_options = nilfs_show_options }; -- cgit v1.2.1