From 35b09dfda9bb0202c83fb4a496794eade014b72d Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 27 Nov 2014 09:28:29 -0500 Subject: [PATCH] Add lazytime cover-letter to track changes. Remove need to iput/iget ext4 inode times. --- add-find-active-inode-nowait | 163 +++++++++++++++++++++++------------------ cover-letter | 102 ++++++++++++++++++++++++++ ext4-add-lazytime-mount-option | 97 +++++++++++++----------- timestamps | 26 ++++--- vfs-add-lazytime-mount-option | 72 +++++++++++++++++- 5 files changed, 331 insertions(+), 129 deletions(-) rewrite add-find-active-inode-nowait (60%) create mode 100644 cover-letter diff --git a/add-find-active-inode-nowait b/add-find-active-inode-nowait dissimilarity index 60% index f0bf1a90..17afe669 100644 --- a/add-find-active-inode-nowait +++ b/add-find-active-inode-nowait @@ -1,73 +1,90 @@ -vfs: add find_active_inode_nowait() function - -Add a new function find_active_inode_nowait() which will never block. -If there is an inode being freed or is still being initialized, this -function will return NULL instead of blocking waiting for an inode to -be freed or to finish initializing. Hence, a negative return from -this function does not mean that inode number is free for use. It is -useful for callers that want to opportunistically do some work on an -inode only if it is present and available in the cache, and where -blocking is not an option. - -Signed-off-by: Theodore Ts'o ---- -diff --git a/fs/inode.c b/fs/inode.c -index 8ceaa09..f9ad3fa 100644 ---- a/fs/inode.c -+++ b/fs/inode.c -@@ -1283,6 +1283,42 @@ struct inode *ilookup(struct super_block *sb, unsigned long ino) - } - EXPORT_SYMBOL(ilookup); - -+/** -+ * find_active_inode_nowait - find an active inode in the inode cache -+ * @sb: super block of file system to search -+ * @ino: inode number to search for -+ * -+ * Search for an active inode @ino in the inode cache, and if the -+ * inode is in the cache, the inode is returned with an incremented -+ * reference count. If the inode is being freed or is newly -+ * initialized, return nothing instead of trying to wait for the inode -+ * initialization or destruction to be complete. -+ */ -+struct inode *find_active_inode_nowait(struct super_block *sb, -+ unsigned long ino) -+{ -+ struct hlist_head *head = inode_hashtable + hash(sb, ino); -+ struct inode *inode, *ret_inode = NULL; -+ -+ spin_lock(&inode_hash_lock); -+ hlist_for_each_entry(inode, head, i_hash) { -+ if ((inode->i_ino != ino) || -+ (inode->i_sb != sb)) -+ continue; -+ spin_lock(&inode->i_lock); -+ if ((inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW)) == 0) { -+ __iget(inode); -+ ret_inode = inode; -+ } -+ spin_unlock(&inode->i_lock); -+ goto out; -+ } -+out: -+ spin_unlock(&inode_hash_lock); -+ return ret_inode; -+} -+EXPORT_SYMBOL(find_active_inode_nowait); -+ - int insert_inode_locked(struct inode *inode) - { - struct super_block *sb = inode->i_sb; -diff --git a/include/linux/fs.h b/include/linux/fs.h -index ff252cb..b24ad99 100644 ---- a/include/linux/fs.h -+++ b/include/linux/fs.h -@@ -2414,6 +2414,8 @@ extern struct inode *ilookup(struct super_block *sb, unsigned long ino); - - extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *); - extern struct inode * iget_locked(struct super_block *, unsigned long); -+extern struct inode *find_active_inode_nowait(struct super_block *, -+ unsigned long); - extern int insert_inode_locked4(struct inode *, unsigned long, int (*test)(struct inode *, void *), void *); - extern int insert_inode_locked(struct inode *); - #ifdef CONFIG_DEBUG_LOCK_ALLOC +vfs: add find_inode_nowait() function + +Add a new function find_inode_nowait() which is an even more general +version of ilookup5_nowait(). It is designed for callers which need +very fine grained control over when the function is allowed to block +or increment the inode's reference count. + +Signed-off-by: Theodore Ts'o +--- + fs/inode.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ + include/linux/fs.h | 5 +++++ + 2 files changed, 55 insertions(+) + +diff --git a/fs/inode.c b/fs/inode.c +index b2fea60..2c160b9 100644 +--- a/fs/inode.c ++++ b/fs/inode.c +@@ -1283,6 +1283,56 @@ struct inode *ilookup(struct super_block *sb, unsigned long ino) + } + EXPORT_SYMBOL(ilookup); + ++/** ++ * find_inode_nowait - find an inode in the inode cache ++ * @sb: super block of file system to search ++ * @hashval: hash value (usually inode number) to search for ++ * @match: callback used for comparisons between inodes ++ * @data: opaque data pointer to pass to @match ++ * ++ * Search for the inode specified by @hashval and @data in the inode ++ * cache, where the helper function @match will return 0 if the inode ++ * does not match, 1 if the inode does match, and -1 if the search ++ * should be stopped. The @match function must be responsible for ++ * taking the i_lock spin_lock and checking i_state for an inode being ++ * freed or being initialized, and incrementing the reference count ++ * before returning 1. It must also not sleep, since it is held with ++ * the inode_hash_lock spinlock held. ++ * ++ * This is a even more generalized version of ilookup5() when the ++ * function must never block --- find_inode() can block in ++ * __wait_on_freeing_inode() --- or when the caller can not increment ++ * the reference count because the resulting iput() might cause an ++ * inode eviction(). The tradeoff is that the @match funtion must be ++ * very carefully implemented. ++ */ ++struct inode *find_inode_nowait(struct super_block *sb, ++ unsigned long hashval, ++ int (*match)(struct inode *, unsigned long, ++ void *), ++ void *data) ++{ ++ struct hlist_head *head = inode_hashtable + hash(sb, hashval); ++ struct inode *inode, *ret_inode = NULL; ++ int mval; ++ ++ spin_lock(&inode_hash_lock); ++ hlist_for_each_entry(inode, head, i_hash) { ++ if (inode->i_sb != sb) ++ continue; ++ mval = match(inode, hashval, data); ++ if (mval == 0) ++ continue; ++ if (mval == 1) ++ ret_inode = inode; ++ goto out; ++ } ++out: ++ spin_unlock(&inode_hash_lock); ++ return ret_inode; ++} ++EXPORT_SYMBOL(find_inode_nowait); ++ + int insert_inode_locked(struct inode *inode) + { + struct super_block *sb = inode->i_sb; +diff --git a/include/linux/fs.h b/include/linux/fs.h +index d0a2181..831dbee 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -2419,6 +2419,11 @@ extern struct inode *ilookup(struct super_block *sb, unsigned long ino); + + extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *); + extern struct inode * iget_locked(struct super_block *, unsigned long); ++extern struct inode *find_inode_nowait(struct super_block *, ++ unsigned long, ++ int (*match)(struct inode *, ++ unsigned long, void *), ++ void *data); + extern int insert_inode_locked4(struct inode *, unsigned long, int (*test)(struct inode *, void *), void *); + extern int insert_inode_locked(struct inode *); + #ifdef CONFIG_DEBUG_LOCK_ALLOC diff --git a/cover-letter b/cover-letter new file mode 100644 index 00000000..91bfa7b8 --- /dev/null +++ b/cover-letter @@ -0,0 +1,102 @@ +Subject: [PATCH-v4 0/7] add support for a lazytime mount option + +This is an updated version of what had originally been an +ext4-specific patch which significantly improves performance by lazily +writing timestamp updates (and in particular, mtime updates) to disk. +The in-memory timestamps are always correct, but they are only written +to disk when required for correctness. + +This provides a huge performance boost for ext4 due to how it handles +journalling, but it's valuable for all file systems running on flash +storage or drive-managed SMR disks by reducing the metadata write +load. So upon request, I've moved the functionality to the VFS layer. +Once the /sbin/mount program adds support for MS_LAZYTIME, all file +systems should be able to benefit from this optimization. + +There is still an ext4-specific optimization, which may be applicable +for other file systems which store more than one inode in a block, but +it will require file system specific code. It is purely optional, +however. + +Please note the changes to update_time() and the new write_time() inode +operations functions, which impact btrfs and xfs. The changes are +fairly simple, but I would appreciate confirmation from the btrfs and +xfs teams that I got things right. Thanks!! + +Any objections to my carrying these patches in the ext4 git tree? + +TODO before next version + - Improve ext4 optimization to avoid extra leakage + - Move btrfs is_readonly patch around + - Check on xfs update_time + - fix up lazytime day staleness + +Changes since -v4: + - Fix ext4 optimization so it does not need to increment (and more + problematically, decrement) the inode reference count + +Changes since -v3: + - inodes with I_DIRTY_TIME set are placed on a new bdi list, + b_dirty_time. This allows filesystem-level syncs to more + easily iterate over those inodes that need to have their + timestamps written to disk. + - dirty timestamps will be written out asynchronously on the final + iput, instead of when the inode gets evicted. + - separate the definition of the new function + find_active_inode_nowait() to a separate patch + - create separate flag masks: I_DIRTY_WB and I_DIRTY_INODE, which + indicate whether the inode needs to be on the write back lists, + or whether the inode itself is dirty, while I_DIRTY means any one + of the inode dirty flags are set. This simplifies the fs + writeback logic which needs to test for different combinations of + the inode dirty flags in different places. + +Changes since -v2: + - If update_time() updates i_version, it will not use lazytime (i..e, + the inode will be marked dirty so the change will be persisted on to + disk sooner rather than later). Yes, this eliminates the + benefits of lazytime if the user is experting the file system via + NFSv4. Sad, but NFS's requirements seem to mandate this. + - Fix time wrapping bug 49 days after the system boots (on a system + with a 32-bit jiffies). Use get_monotonic_boottime() instead. + - Clean up type warning in include/tracing/ext4.h + - Added explicit parenthesis for stylistic reasons + - Added an is_readonly() inode operations method so btrfs doesn't + have to duplicate code in update_time(). + +Changes since -v1: + - Added explanatory comments in update_time() regarding i_ts_dirty_days + - Fix type used for days_since_boot + - Improve SMP scalability in update_time and ext4_update_other_inodes_time + - Added tracepoints to help test and characterize how often and under + what circumstances inodes have their timestamps lazily updated + + +Theodore Ts'o (7): + vfs: split update_time() into update_time() and write_time() + vfs: add support for a lazytime mount option + vfs: don't let the dirty time inodes get more than a day stale + vfs: add lazytime tracepoints for better debugging + vfs: add find_active_inode_nowait() function + ext4: add support for a lazytime mount option + btrfs: add an is_readonly() so btrfs can use common code for + update_time() + + Documentation/filesystems/Locking | 2 + + fs/btrfs/inode.c | 34 +++++------- + fs/ext4/inode.c | 49 ++++++++++++++++- + fs/ext4/super.c | 9 +++ + fs/fs-writeback.c | 57 +++++++++++++++++-- + fs/inode.c | 113 +++++++++++++++++++++++++++++++++++--- + fs/proc_namespace.c | 1 + + fs/sync.c | 8 +++ + fs/xfs/xfs_iops.c | 39 ++++++------- + include/linux/backing-dev.h | 1 + + include/linux/fs.h | 17 +++++- + include/trace/events/ext4.h | 30 ++++++++++ + include/uapi/linux/fs.h | 1 + + mm/backing-dev.c | 9 ++- + 14 files changed, 306 insertions(+), 64 deletions(-) + +---------- + diff --git a/ext4-add-lazytime-mount-option b/ext4-add-lazytime-mount-option index 7392e695..e412ec67 100644 --- a/ext4-add-lazytime-mount-option +++ b/ext4-add-lazytime-mount-option @@ -1,4 +1,4 @@ -ext4: add support for a lazytime mount option +ext4: add optimization for the lazytime mount option Add an optimization for the MS_LAZYTIME mount option so that we will opportunistically write out any inodes with the I_DIRTY_TIME flag set @@ -14,70 +14,81 @@ Google-Bug-Id: 18297052 Signed-off-by: Theodore Ts'o --- - fs/ext4/inode.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- - fs/ext4/super.c | 9 +++++++++ - fs/inode.c | 36 ++++++++++++++++++++++++++++++++++++ - include/linux/fs.h | 2 ++ - include/trace/events/ext4.h | 30 ++++++++++++++++++++++++++++++ - 5 files changed, 123 insertions(+), 3 deletions(-) + fs/ext4/inode.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++--- + fs/ext4/super.c | 9 ++++++++ + include/trace/events/ext4.h | 30 ++++++++++++++++++++++++++ + 3 files changed, 98 insertions(+), 3 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c -index 5653fa4..8308c82 100644 +index 5653fa4..1d11920 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c -@@ -4140,6 +4140,51 @@ static int ext4_inode_blocks_set(handle_t *handle, +@@ -4139,6 +4139,64 @@ static int ext4_inode_blocks_set(handle_t *handle, + return 0; } - /* ++struct other_inode { ++ unsigned long orig_ino; ++ struct ext4_inode *raw_inode; ++}; ++ ++static int other_inode_match(struct inode * inode, unsigned long ino, ++ void *data) ++{ ++ struct other_inode *oi = (struct other_inode *) data; ++ ++ if (inode->i_ino != ino) ++ return 0; ++ spin_lock(&inode->i_lock); ++ if (((inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW)) == 0) && ++ (inode->i_state & I_DIRTY_TIME)) { ++ struct ext4_inode_info *ei = EXT4_I(inode); ++ ++ inode->i_state &= ~I_DIRTY_TIME; ++ inode->i_ts_dirty_day = 0; ++ spin_unlock(&inode->i_lock); ++ inode_requeue_dirtytime(inode); ++ ++ spin_lock(&ei->i_raw_lock); ++ EXT4_INODE_SET_XTIME(i_ctime, inode, oi->raw_inode); ++ EXT4_INODE_SET_XTIME(i_mtime, inode, oi->raw_inode); ++ EXT4_INODE_SET_XTIME(i_atime, inode, oi->raw_inode); ++ ext4_inode_csum_set(inode, oi->raw_inode, ei); ++ spin_unlock(&ei->i_raw_lock); ++ trace_ext4_other_inode_update_time(inode, oi->orig_ino); ++ return -1; ++ } ++ spin_unlock(&inode->i_lock); ++ return -1; ++} ++ ++/* + * Opportunistically update the other time fields for other inodes in + * the same inode table block. + */ +static void ext4_update_other_inodes_time(struct super_block *sb, + unsigned long orig_ino, char *buf) +{ -+ struct ext4_inode_info *ei; -+ struct ext4_inode *raw_inode; -+ unsigned long ino; -+ struct inode *inode; -+ int i, inodes_per_block = EXT4_SB(sb)->s_inodes_per_block; -+ int inode_size = EXT4_INODE_SIZE(sb); ++ struct other_inode oi; ++ unsigned long ino; ++ int i, inodes_per_block = EXT4_SB(sb)->s_inodes_per_block; ++ int inode_size = EXT4_INODE_SIZE(sb); + ++ oi.orig_ino = orig_ino; + ino = orig_ino & ~(inodes_per_block - 1); + for (i = 0; i < inodes_per_block; i++, ino++, buf += inode_size) { + if (ino == orig_ino) + continue; -+ inode = find_active_inode_nowait(sb, ino); -+ if (!inode || -+ (inode->i_state & I_DIRTY_TIME) == 0 || -+ !spin_trylock(&inode->i_lock)) { -+ iput(inode); -+ continue; -+ } -+ inode->i_state &= ~I_DIRTY_TIME; -+ inode->i_ts_dirty_day = 0; -+ spin_unlock(&inode->i_lock); -+ inode_requeue_dirtytime(inode); -+ -+ ei = EXT4_I(inode); -+ raw_inode = (struct ext4_inode *) buf; -+ -+ spin_lock(&ei->i_raw_lock); -+ EXT4_INODE_SET_XTIME(i_ctime, inode, raw_inode); -+ EXT4_INODE_SET_XTIME(i_mtime, inode, raw_inode); -+ EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode); -+ ext4_inode_csum_set(inode, raw_inode, ei); -+ spin_unlock(&ei->i_raw_lock); -+ trace_ext4_other_inode_update_time(inode, orig_ino); -+ iput(inode); ++ oi.raw_inode = (struct ext4_inode *) buf; ++ (void) find_inode_nowait(sb, ino, other_inode_match, &oi); + } +} + + -+/* + /* * Post the struct inode info into an on-disk inode location in the * buffer-cache. This gobbles the caller's reference to the - * buffer_head in the inode location struct. -@@ -4237,7 +4282,6 @@ static int ext4_do_update_inode(handle_t *handle, +@@ -4237,7 +4295,6 @@ static int ext4_do_update_inode(handle_t *handle, for (block = 0; block < EXT4_N_BLOCKS; block++) raw_inode->i_block[block] = ei->i_data[block]; } @@ -85,7 +96,7 @@ index 5653fa4..8308c82 100644 if (likely(!test_opt2(inode->i_sb, HURD_COMPAT))) { raw_inode->i_disk_version = cpu_to_le32(inode->i_version); if (ei->i_extra_isize) { -@@ -4248,10 +4292,9 @@ static int ext4_do_update_inode(handle_t *handle, +@@ -4248,10 +4305,9 @@ static int ext4_do_update_inode(handle_t *handle, cpu_to_le16(ei->i_extra_isize); } } diff --git a/timestamps b/timestamps index 1bb8f492..3228b26c 100755 --- a/timestamps +++ b/timestamps @@ -1,5 +1,5 @@ touch -d @1289246085 use-discard-if-possible-in-blkdev_issue_zeroout -touch -d @1289862704 add-lazytime-mount-option +touch -d @1372293995 deletion-of-an-unnecessary-check-before-the-function-call-iput touch -d @1398102654 save-patch touch -d @1402323175 archive touch -d @1402890388 fix-buffer-double-free-in-ext4_alloc_branch @@ -10,9 +10,9 @@ touch -d @1406642254 save-goal-location-struct-ext4_allocation_context.ac_g_ex touch -d @1409965630 return-error-code-on-key-retrieval-failure-and-retry-crypto-after-interrupted touch -d @1410055965 move-read-page-functions-to-new-file touch -d @1410060348 include-mpage-functions-into-readpage.c -touch -d @1410060352 inline-ext4_get_block-into-readpage touch -d @1410111565 dont-use-io-end-if-not-needed touch -d @1410467342 akpm-jbd2-locking-fix +touch -d @1411496083 add-lazytime-mount-option touch -d @1413721175 implement-the-ext4-encryption-write-path touch -d @1414970511 add-blkdiscard-ioctl touch -d @1414970571 block-dio-during-truncate @@ -32,12 +32,6 @@ touch -d @1416722142 fix-partial-cluster-initialization touch -d @1416722291 fix-end-of-leaf-partial-cluster-handling touch -d @1416722379 miscellaneous-partial-cluster-cleanups touch -d @1416722619 fix-end-of-region-partial-cluster-handling -touch -d @1416722679 split-update_time-into-update_time-and-write_time -touch -d @1416890846 vfs-add-lazytime-mount-option -touch -d @1416890847 dont-let-dirty-time-inodes-get-more-than-a-day-stale -touch -d @1416890980 add-lazytime-tracepoints -touch -d @1416891093 ext4-add-lazytime-mount-option -touch -d @1416892137 btrfs-drop-update_time touch -d @1416933709 fix-block-reservation-for-bigalloc-filesystems touch -d @1416933877 cache-extent-hole-in-extent-status-tree-for-ext4_da_map_blocks touch -d @1416934021 change-lru-to-round-rubin-in-extent-status-tree @@ -47,7 +41,6 @@ touch -d @1416934427 cleanup-flag-definitions-for-extent-status-tree touch -d @1416934524 introduce-aging-to-extent-status-tree touch -d @1416938884 cleanup-gfp-flags-inside-resize-path touch -d @1416939519 fix-potential-use-after-free-during-resize -touch -d @1416939579 stable-boundary touch -d @1416949136 fix-suboptimal-seek_datahole_extents_traversal touch -d @1416950249 update-comments-regarding-ext4_delete_inode touch -d @1416950450 create-nojournal_checksum-mount-option @@ -55,9 +48,18 @@ touch -d @1416950628 remove-never-taken-branch-from-ext4_ext_shift_path_extents touch -d @1416950864 dont-count-external-journal-blocks-as-overhead touch -d @1416951278 remove-unneeded-code-in-ext4_unlink touch -d @1416963637 use-the-shash-api-correctly-for-crc32c -touch -d @1416964545 deletion-of-an-unnecessary-check-before-the-function-call-iput touch -d @1416964682 jbd2-remove-unnecessary-NULL-check-before-iput touch -d @1416964757 forbid-journal_async_commit-in-data-ordered-mode touch -d @1416964779 series -touch -d @1416964781 status -touch -d @1416972772 timestamps +touch -d @1416964817 split-update_time-into-update_time-and-write_time +touch -d @1417065876 stable-boundary +touch -d @1417066312 inline-ext4_get_block-into-readpage +touch -d @1417070414 vfs-add-lazytime-mount-option +touch -d @1417070418 add-lazytime-tracepoints +touch -d @1417070418 dont-let-dirty-time-inodes-get-more-than-a-day-stale +touch -d @1417070419 add-find-active-inode-nowait +touch -d @1417070420 ext4-add-lazytime-mount-option +touch -d @1417070421 btrfs-drop-update_time +touch -d @1417070421 status +touch -d @1417098458 cover-letter +touch -d @1417098500 timestamps diff --git a/vfs-add-lazytime-mount-option b/vfs-add-lazytime-mount-option index 85c7d630..998080cf 100644 --- a/vfs-add-lazytime-mount-option +++ b/vfs-add-lazytime-mount-option @@ -25,13 +25,18 @@ Signed-off-by: Theodore Ts'o --- fs/fs-writeback.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++------ fs/inode.c | 43 +++++++++++++++++++++++++++++++++++++------ + fs/libfs.c | 2 +- + fs/logfs/readwrite.c | 2 +- + fs/nfsd/vfs.c | 2 +- + fs/pipe.c | 2 +- fs/proc_namespace.c | 1 + fs/sync.c | 8 ++++++++ + fs/ufs/truncate.c | 2 +- include/linux/backing-dev.h | 1 + include/linux/fs.h | 11 +++++++++-- include/uapi/linux/fs.h | 1 + mm/backing-dev.c | 9 +++++++-- - 8 files changed, 113 insertions(+), 16 deletions(-) + 13 files changed, 118 insertions(+), 21 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index ef9bef1..ef8c5d8 100644 @@ -217,6 +222,58 @@ index 8f5c4b5..9e464cc 100644 if (inode->i_op->write_time) return inode->i_op->write_time(inode); mark_inode_dirty_sync(inode); +diff --git a/fs/libfs.c b/fs/libfs.c +index 171d284..b9923b2 100644 +--- a/fs/libfs.c ++++ b/fs/libfs.c +@@ -1066,7 +1066,7 @@ struct inode *alloc_anon_inode(struct super_block *s) + * list because mark_inode_dirty() will think + * that it already _is_ on the dirty list. + */ +- inode->i_state = I_DIRTY; ++ inode->i_state = I_DIRTY_WB; + inode->i_mode = S_IRUSR | S_IWUSR; + inode->i_uid = current_fsuid(); + inode->i_gid = current_fsgid(); +diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c +index 380d86e..5521842 100644 +--- a/fs/logfs/readwrite.c ++++ b/fs/logfs/readwrite.c +@@ -2187,7 +2187,7 @@ void logfs_evict_inode(struct inode *inode) + * aliases, which are moved back. No write to the medium happens. + */ + /* Only deleted files may be dirty at this point */ +- BUG_ON(inode->i_state & I_DIRTY && inode->i_nlink); ++ BUG_ON(inode->i_state & I_DIRTY_WB && inode->i_nlink); + if (!block) + return; + if ((logfs_super(sb)->s_flags & LOGFS_SB_FLAG_SHUTDOWN)) { +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 989129e..818c6fa 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -915,7 +915,7 @@ static int wait_for_concurrent_writes(struct file *file) + dprintk("nfsd: write resume %d\n", task_pid_nr(current)); + } + +- if (inode->i_state & I_DIRTY) { ++ if (inode->i_state & I_DIRTY_WB) { + dprintk("nfsd: write sync %d\n", task_pid_nr(current)); + err = vfs_fsync(file, 0); + } +diff --git a/fs/pipe.c b/fs/pipe.c +index 21981e5..fc9b923 100644 +--- a/fs/pipe.c ++++ b/fs/pipe.c +@@ -660,7 +660,7 @@ static struct inode * get_pipe_inode(void) + * list because "mark_inode_dirty()" will think + * that it already _is_ on the dirty list. + */ +- inode->i_state = I_DIRTY; ++ inode->i_state = I_DIRTY_WB; + inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR; + inode->i_uid = current_fsuid(); + inode->i_gid = current_fsgid(); diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c index 73ca174..f98234a 100644 --- a/fs/proc_namespace.c @@ -250,6 +307,19 @@ index bdc729d..6ac7bf0 100644 return file->f_op->fsync(file, start, end, datasync); } EXPORT_SYMBOL(vfs_fsync_range); +diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c +index f04f89f..1d00a09 100644 +--- a/fs/ufs/truncate.c ++++ b/fs/ufs/truncate.c +@@ -477,7 +477,7 @@ int ufs_truncate(struct inode *inode, loff_t old_i_size) + retry |= ufs_trunc_tindirect (inode); + if (!retry) + break; +- if (IS_SYNC(inode) && (inode->i_state & I_DIRTY)) ++ if (IS_SYNC(inode) && (inode->i_state & I_DIRTY_WB)) + ufs_sync_inode (inode); + yield(); + } diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 5da6012..4cdf733 100644 --- a/include/linux/backing-dev.h -- 2.11.4.GIT