Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Andreas Rohner and committed by
Linus Torvalds
b9f66140 e2c7617a

+20 -11
+7 -6
fs/nilfs2/inode.c
··· 126 126 nilfs_transaction_abort(inode->i_sb); 127 127 goto out; 128 128 } 129 - nilfs_mark_inode_dirty(inode); 129 + nilfs_mark_inode_dirty_sync(inode); 130 130 nilfs_transaction_commit(inode->i_sb); /* never fails */ 131 131 /* Error handling should be detailed */ 132 132 set_buffer_new(bh_result); ··· 672 672 for substitutions of appended fields */ 673 673 } 674 674 675 - void nilfs_update_inode(struct inode *inode, struct buffer_head *ibh) 675 + void nilfs_update_inode(struct inode *inode, struct buffer_head *ibh, int flags) 676 676 { 677 677 ino_t ino = inode->i_ino; 678 678 struct nilfs_inode_info *ii = NILFS_I(inode); ··· 683 683 684 684 if (test_and_clear_bit(NILFS_I_NEW, &ii->i_state)) 685 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 689 nilfs_write_inode_common(inode, raw_inode, 0); 689 690 /* XXX: call with has_bmap = 0 is a workaround to avoid ··· 940 939 return 0; 941 940 } 942 941 943 - int nilfs_mark_inode_dirty(struct inode *inode) 942 + int __nilfs_mark_inode_dirty(struct inode *inode, int flags) 944 943 { 945 944 struct buffer_head *ibh; 946 945 int err; ··· 951 950 "failed to reget inode block.\n"); 952 951 return err; 953 952 } 954 - nilfs_update_inode(inode, ibh); 953 + nilfs_update_inode(inode, ibh, flags); 955 954 mark_buffer_dirty(ibh); 956 955 nilfs_mdt_mark_dirty(NILFS_I(inode)->i_root->ifile); 957 956 brelse(ibh); ··· 984 983 return; 985 984 } 986 985 nilfs_transaction_begin(inode->i_sb, &ti, 0); 987 - nilfs_mark_inode_dirty(inode); 986 + __nilfs_mark_inode_dirty(inode, flags); 988 987 nilfs_transaction_commit(inode->i_sb); /* never fails */ 989 988 } 990 989
+11 -3
fs/nilfs2/nilfs.h
··· 104 104 constructor */ 105 105 NILFS_I_COLLECTED, /* All dirty blocks are collected */ 106 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 108 NILFS_I_BMAP, /* has bmap and btnode_cache */ 109 109 NILFS_I_GCINODE, /* inode for GC, on memory only */ 110 110 }; ··· 273 273 unsigned long ino); 274 274 extern struct inode *nilfs_iget_for_gc(struct super_block *sb, 275 275 unsigned long ino, __u64 cno); 276 - extern void nilfs_update_inode(struct inode *, struct buffer_head *); 276 + extern void nilfs_update_inode(struct inode *, struct buffer_head *, int); 277 277 extern void nilfs_truncate(struct inode *); 278 278 extern void nilfs_evict_inode(struct inode *); 279 279 extern int nilfs_setattr(struct dentry *, struct iattr *); ··· 282 282 int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh); 283 283 extern int nilfs_inode_dirty(struct inode *); 284 284 int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty); 285 - extern int nilfs_mark_inode_dirty(struct inode *); 285 + extern int __nilfs_mark_inode_dirty(struct inode *, int); 286 286 extern void nilfs_dirty_inode(struct inode *, int flags); 287 287 int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, 288 288 __u64 start, __u64 len); 289 + static inline int nilfs_mark_inode_dirty(struct inode *inode) 290 + { 291 + return __nilfs_mark_inode_dirty(inode, I_DIRTY); 292 + } 293 + static 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 298 /* super.c */ 291 299 extern struct inode *nilfs_alloc_inode(struct super_block *);
+2 -2
fs/nilfs2/segment.c
··· 930 930 if (!test_and_clear_bit(NILFS_I_COLLECTED, &ii->i_state)) 931 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 934 set_bit(NILFS_I_UPDATED, &ii->i_state); 935 935 } 936 936 } ··· 2195 2195 nilfs_transaction_lock(sb, &ti, 0); 2196 2196 2197 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 2199 nilfs_test_opt(nilfs, STRICT_ORDER) || 2200 2200 test_bit(NILFS_SC_UNCLOSED, &sci->sc_flags) || 2201 2201 nilfs_discontinued(nilfs)) {