aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2
diff options
context:
space:
mode:
authorAndreas Rohner <andreas.rohner@gmx.net>2014-10-13 18:53:22 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-13 20:18:20 -0400
commitb9f6614072687f1ea9bf09a99789c976cbe89714 (patch)
tree938284793390ed8d05ad3be57c721e9d4e53faf7 /fs/nilfs2
parente2c7617ae36b27f97643bfa08aabe27e630c1a76 (diff)
nilfs2: improve the performance of fdatasync()
Support for fdatasync() has been implemented in NILFS2 for a long time, but whenever the corresponding inode is dirty the implementation falls back to a full-flegded sync(). Since every write operation has to update the modification time of the file, the inode will almost always be dirty and fdatasync() will fall back to sync() most of the time. But this fallback is only necessary for a change of the file size and not for a change of the various timestamps. This patch adds a new flag NILFS_I_INODE_SYNC to differentiate between those two situations. * If it is set the file size was changed and a full sync is necessary. * If it is not set then only the timestamps were updated and fdatasync() can go ahead. There is already a similar flag I_DIRTY_DATASYNC on the VFS layer with the exact same semantics. Unfortunately it cannot be used directly, because NILFS2 doesn't implement write_inode() and doesn't clear the VFS flags when inodes are written out. So the VFS writeback thread can clear I_DIRTY_DATASYNC at any time without notifying NILFS2. So I_DIRTY_DATASYNC has to be mapped onto NILFS_I_INODE_SYNC in nilfs_update_inode(). Signed-off-by: Andreas Rohner <andreas.rohner@gmx.net> Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/nilfs2')
-rw-r--r--fs/nilfs2/inode.c13
-rw-r--r--fs/nilfs2/nilfs.h14
-rw-r--r--fs/nilfs2/segment.c4
3 files changed, 20 insertions, 11 deletions
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index d071e7f23de2..e1fa69b341b9 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -126,7 +126,7 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,
126 nilfs_transaction_abort(inode->i_sb); 126 nilfs_transaction_abort(inode->i_sb);
127 goto out; 127 goto out;
128 } 128 }
129 nilfs_mark_inode_dirty(inode); 129 nilfs_mark_inode_dirty_sync(inode);
130 nilfs_transaction_commit(inode->i_sb); /* never fails */ 130 nilfs_transaction_commit(inode->i_sb); /* never fails */
131 /* Error handling should be detailed */ 131 /* Error handling should be detailed */
132 set_buffer_new(bh_result); 132 set_buffer_new(bh_result);
@@ -672,7 +672,7 @@ void nilfs_write_inode_common(struct inode *inode,
672 for substitutions of appended fields */ 672 for substitutions of appended fields */
673} 673}
674 674
675void nilfs_update_inode(struct inode *inode, struct buffer_head *ibh) 675void nilfs_update_inode(struct inode *inode, struct buffer_head *ibh, int flags)
676{ 676{
677 ino_t ino = inode->i_ino; 677 ino_t ino = inode->i_ino;
678 struct nilfs_inode_info *ii = NILFS_I(inode); 678 struct nilfs_inode_info *ii = NILFS_I(inode);
@@ -683,7 +683,8 @@ void nilfs_update_inode(struct inode *inode, struct buffer_head *ibh)
683 683
684 if (test_and_clear_bit(NILFS_I_NEW, &ii->i_state)) 684 if (test_and_clear_bit(NILFS_I_NEW, &ii->i_state))
685 memset(raw_inode, 0, NILFS_MDT(ifile)->mi_entry_size); 685 memset(raw_inode, 0, NILFS_MDT(ifile)->mi_entry_size);
686 set_bit(NILFS_I_INODE_DIRTY, &ii->i_state); 686 if (flags & I_DIRTY_DATASYNC)
687 set_bit(NILFS_I_INODE_SYNC, &ii->i_state);
687 688
688 nilfs_write_inode_common(inode, raw_inode, 0); 689 nilfs_write_inode_common(inode, raw_inode, 0);
689 /* XXX: call with has_bmap = 0 is a workaround to avoid 690 /* XXX: call with has_bmap = 0 is a workaround to avoid
@@ -939,7 +940,7 @@ int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty)
939 return 0; 940 return 0;
940} 941}
941 942
942int nilfs_mark_inode_dirty(struct inode *inode) 943int __nilfs_mark_inode_dirty(struct inode *inode, int flags)
943{ 944{
944 struct buffer_head *ibh; 945 struct buffer_head *ibh;
945 int err; 946 int err;
@@ -950,7 +951,7 @@ int nilfs_mark_inode_dirty(struct inode *inode)
950 "failed to reget inode block.\n"); 951 "failed to reget inode block.\n");
951 return err; 952 return err;
952 } 953 }
953 nilfs_update_inode(inode, ibh); 954 nilfs_update_inode(inode, ibh, flags);
954 mark_buffer_dirty(ibh); 955 mark_buffer_dirty(ibh);
955 nilfs_mdt_mark_dirty(NILFS_I(inode)->i_root->ifile); 956 nilfs_mdt_mark_dirty(NILFS_I(inode)->i_root->ifile);
956 brelse(ibh); 957 brelse(ibh);
@@ -983,7 +984,7 @@ void nilfs_dirty_inode(struct inode *inode, int flags)
983 return; 984 return;
984 } 985 }
985 nilfs_transaction_begin(inode->i_sb, &ti, 0); 986 nilfs_transaction_begin(inode->i_sb, &ti, 0);
986 nilfs_mark_inode_dirty(inode); 987 __nilfs_mark_inode_dirty(inode, flags);
987 nilfs_transaction_commit(inode->i_sb); /* never fails */ 988 nilfs_transaction_commit(inode->i_sb); /* never fails */
988} 989}
989 990
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h
index 0696161bf59d..91093cd74f0d 100644
--- a/fs/nilfs2/nilfs.h
+++ b/fs/nilfs2/nilfs.h
@@ -104,7 +104,7 @@ enum {
104 constructor */ 104 constructor */
105 NILFS_I_COLLECTED, /* All dirty blocks are collected */ 105 NILFS_I_COLLECTED, /* All dirty blocks are collected */
106 NILFS_I_UPDATED, /* The file has been written back */ 106 NILFS_I_UPDATED, /* The file has been written back */
107 NILFS_I_INODE_DIRTY, /* write_inode is requested */ 107 NILFS_I_INODE_SYNC, /* dsync is not allowed for inode */
108 NILFS_I_BMAP, /* has bmap and btnode_cache */ 108 NILFS_I_BMAP, /* has bmap and btnode_cache */
109 NILFS_I_GCINODE, /* inode for GC, on memory only */ 109 NILFS_I_GCINODE, /* inode for GC, on memory only */
110}; 110};
@@ -273,7 +273,7 @@ struct inode *nilfs_iget(struct super_block *sb, struct nilfs_root *root,
273 unsigned long ino); 273 unsigned long ino);
274extern struct inode *nilfs_iget_for_gc(struct super_block *sb, 274extern struct inode *nilfs_iget_for_gc(struct super_block *sb,
275 unsigned long ino, __u64 cno); 275 unsigned long ino, __u64 cno);
276extern void nilfs_update_inode(struct inode *, struct buffer_head *); 276extern void nilfs_update_inode(struct inode *, struct buffer_head *, int);
277extern void nilfs_truncate(struct inode *); 277extern void nilfs_truncate(struct inode *);
278extern void nilfs_evict_inode(struct inode *); 278extern void nilfs_evict_inode(struct inode *);
279extern int nilfs_setattr(struct dentry *, struct iattr *); 279extern int nilfs_setattr(struct dentry *, struct iattr *);
@@ -282,10 +282,18 @@ int nilfs_permission(struct inode *inode, int mask);
282int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh); 282int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh);
283extern int nilfs_inode_dirty(struct inode *); 283extern int nilfs_inode_dirty(struct inode *);
284int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty); 284int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty);
285extern int nilfs_mark_inode_dirty(struct inode *); 285extern int __nilfs_mark_inode_dirty(struct inode *, int);
286extern void nilfs_dirty_inode(struct inode *, int flags); 286extern void nilfs_dirty_inode(struct inode *, int flags);
287int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, 287int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
288 __u64 start, __u64 len); 288 __u64 start, __u64 len);
289static inline int nilfs_mark_inode_dirty(struct inode *inode)
290{
291 return __nilfs_mark_inode_dirty(inode, I_DIRTY);
292}
293static inline int nilfs_mark_inode_dirty_sync(struct inode *inode)
294{
295 return __nilfs_mark_inode_dirty(inode, I_DIRTY_SYNC);
296}
289 297
290/* super.c */ 298/* super.c */
291extern struct inode *nilfs_alloc_inode(struct super_block *); 299extern struct inode *nilfs_alloc_inode(struct super_block *);
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
index 0b7d2cad0426..7ef18fc656c2 100644
--- a/fs/nilfs2/segment.c
+++ b/fs/nilfs2/segment.c
@@ -930,7 +930,7 @@ static void nilfs_drop_collected_inodes(struct list_head *head)
930 if (!test_and_clear_bit(NILFS_I_COLLECTED, &ii->i_state)) 930 if (!test_and_clear_bit(NILFS_I_COLLECTED, &ii->i_state))
931 continue; 931 continue;
932 932
933 clear_bit(NILFS_I_INODE_DIRTY, &ii->i_state); 933 clear_bit(NILFS_I_INODE_SYNC, &ii->i_state);
934 set_bit(NILFS_I_UPDATED, &ii->i_state); 934 set_bit(NILFS_I_UPDATED, &ii->i_state);
935 } 935 }
936} 936}
@@ -2195,7 +2195,7 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode,
2195 nilfs_transaction_lock(sb, &ti, 0); 2195 nilfs_transaction_lock(sb, &ti, 0);
2196 2196
2197 ii = NILFS_I(inode); 2197 ii = NILFS_I(inode);
2198 if (test_bit(NILFS_I_INODE_DIRTY, &ii->i_state) || 2198 if (test_bit(NILFS_I_INODE_SYNC, &ii->i_state) ||
2199 nilfs_test_opt(nilfs, STRICT_ORDER) || 2199 nilfs_test_opt(nilfs, STRICT_ORDER) ||
2200 test_bit(NILFS_SC_UNCLOSED, &sci->sc_flags) || 2200 test_bit(NILFS_SC_UNCLOSED, &sci->sc_flags) ||
2201 nilfs_discontinued(nilfs)) { 2201 nilfs_discontinued(nilfs)) {