From f1d043f61e6bf34a2cfc4f927a3f3a4a0411f4d5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 27 Oct 2022 10:54:08 +0200 Subject: [PATCH] drop fs/writeback series. needs to be reviewed on the list. --- ...fs-clean-up-__mark_inode_dirty-a-bit.patch | 120 --------- ...ectly-document-the-inode-dirty-flags.patch | 65 ----- ...rty_inode-for-lazytime-timestamp-upd.patch | 119 --------- ...y-i_dirty_inode-flags-to-dirty_inode.patch | 66 ----- ...y_time-even-if-inode-already-has-i_d.patch | 196 --------------- queue-5.10/series | 9 - ...eback-avoid-skipping-inode-writeback.patch | 74 ------ ...-keep-list-of-inodes-attached-to-bdi.patch | 231 ------------------ ...warn-on-an-unregistered-bdi-in-__mar.patch | 41 ---- ...ode-i_io_list-not-be-protected-by-in.patch | 171 ------------- 10 files changed, 1092 deletions(-) delete mode 100644 queue-5.10/fs-clean-up-__mark_inode_dirty-a-bit.patch delete mode 100644 queue-5.10/fs-correctly-document-the-inode-dirty-flags.patch delete mode 100644 queue-5.10/fs-don-t-call-dirty_inode-for-lazytime-timestamp-upd.patch delete mode 100644 queue-5.10/fs-pass-only-i_dirty_inode-flags-to-dirty_inode.patch delete mode 100644 queue-5.10/fs-record-i_dirty_time-even-if-inode-already-has-i_d.patch delete mode 100644 queue-5.10/writeback-avoid-skipping-inode-writeback.patch delete mode 100644 queue-5.10/writeback-cgroup-keep-list-of-inodes-attached-to-bdi.patch delete mode 100644 queue-5.10/writeback-don-t-warn-on-an-unregistered-bdi-in-__mar.patch delete mode 100644 queue-5.10/writeback-fix-inode-i_io_list-not-be-protected-by-in.patch diff --git a/queue-5.10/fs-clean-up-__mark_inode_dirty-a-bit.patch b/queue-5.10/fs-clean-up-__mark_inode_dirty-a-bit.patch deleted file mode 100644 index 9ccdb4b021e..00000000000 --- a/queue-5.10/fs-clean-up-__mark_inode_dirty-a-bit.patch +++ /dev/null @@ -1,120 +0,0 @@ -From 14e2488e7853fd96ed92fd5443a4e3a5e6cf2174 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Tue, 12 Jan 2021 11:02:49 -0800 -Subject: fs: clean up __mark_inode_dirty() a bit - -From: Eric Biggers - -[ Upstream commit 35d14f278e530ecb635ab00de984065ed90ee12f ] - -Improve some comments, and don't bother checking for the I_DIRTY_TIME -flag in the case where we just cleared it. - -Also, warn if I_DIRTY_TIME and I_DIRTY_PAGES are passed to -__mark_inode_dirty() at the same time, as this case isn't handled. - -Link: https://lore.kernel.org/r/20210112190253.64307-8-ebiggers@kernel.org -Reviewed-by: Christoph Hellwig -Reviewed-by: Jan Kara -Signed-off-by: Eric Biggers -Signed-off-by: Jan Kara -Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE") -Signed-off-by: Sasha Levin ---- - fs/fs-writeback.c | 49 +++++++++++++++++++++++++++++------------------ - 1 file changed, 30 insertions(+), 19 deletions(-) - -diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c -index b6d572a519fa..71043e847e7c 100644 ---- a/fs/fs-writeback.c -+++ b/fs/fs-writeback.c -@@ -2206,23 +2206,24 @@ int dirtytime_interval_handler(struct ctl_table *table, int write, - } - - /** -- * __mark_inode_dirty - internal function -+ * __mark_inode_dirty - internal function to mark an inode dirty - * - * @inode: inode to mark -- * @flags: what kind of dirty (i.e. I_DIRTY_SYNC) -+ * @flags: what kind of dirty, e.g. I_DIRTY_SYNC. This can be a combination of -+ * multiple I_DIRTY_* flags, except that I_DIRTY_TIME can't be combined -+ * with I_DIRTY_PAGES. - * -- * Mark an inode as dirty. Callers should use mark_inode_dirty or -- * mark_inode_dirty_sync. -+ * Mark an inode as dirty. We notify the filesystem, then update the inode's -+ * dirty flags. Then, if needed we add the inode to the appropriate dirty list. - * -- * Put the inode on the super block's dirty list. -+ * Most callers should use mark_inode_dirty() or mark_inode_dirty_sync() -+ * instead of calling this directly. - * -- * CAREFUL! We mark it dirty unconditionally, but move it onto the -- * dirty list only if it is hashed or if it refers to a blockdev. -- * If it was not hashed, it will never be added to the dirty list -- * even if it is later hashed, as it will have been marked dirty already. -+ * CAREFUL! We only add the inode to the dirty list if it is hashed or if it -+ * refers to a blockdev. Unhashed inodes will never be added to the dirty list -+ * even if they are later hashed, as they will have been marked dirty already. - * -- * In short, make sure you hash any inodes _before_ you start marking -- * them dirty. -+ * In short, ensure you hash any inodes _before_ you start marking them dirty. - * - * Note that for blockdevs, inode->dirtied_when represents the dirtying time of - * the block-special inode (/dev/hda1) itself. And the ->dirtied_when field of -@@ -2234,25 +2235,34 @@ int dirtytime_interval_handler(struct ctl_table *table, int write, - void __mark_inode_dirty(struct inode *inode, int flags) - { - struct super_block *sb = inode->i_sb; -- int dirtytime; -+ int dirtytime = 0; - - trace_writeback_mark_inode_dirty(inode, flags); - -- /* -- * Don't do this for I_DIRTY_PAGES - that doesn't actually -- * dirty the inode itself -- */ - if (flags & I_DIRTY_INODE) { -+ /* -+ * Notify the filesystem about the inode being dirtied, so that -+ * (if needed) it can update on-disk fields and journal the -+ * inode. This is only needed when the inode itself is being -+ * dirtied now. I.e. it's only needed for I_DIRTY_INODE, not -+ * for just I_DIRTY_PAGES or I_DIRTY_TIME. -+ */ - trace_writeback_dirty_inode_start(inode, flags); -- - if (sb->s_op->dirty_inode) - sb->s_op->dirty_inode(inode, flags & I_DIRTY_INODE); -- - trace_writeback_dirty_inode(inode, flags); - -+ /* I_DIRTY_INODE supersedes I_DIRTY_TIME. */ - flags &= ~I_DIRTY_TIME; -+ } else { -+ /* -+ * Else it's either I_DIRTY_PAGES, I_DIRTY_TIME, or nothing. -+ * (We don't support setting both I_DIRTY_PAGES and I_DIRTY_TIME -+ * in one call to __mark_inode_dirty().) -+ */ -+ dirtytime = flags & I_DIRTY_TIME; -+ WARN_ON_ONCE(dirtytime && flags != I_DIRTY_TIME); - } -- dirtytime = flags & I_DIRTY_TIME; - - /* - * Paired with smp_mb() in __writeback_single_inode() for the -@@ -2272,6 +2282,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) - - inode_attach_wb(inode, NULL); - -+ /* I_DIRTY_INODE supersedes I_DIRTY_TIME. */ - if (flags & I_DIRTY_INODE) - inode->i_state &= ~I_DIRTY_TIME; - inode->i_state |= flags; --- -2.35.1 - diff --git a/queue-5.10/fs-correctly-document-the-inode-dirty-flags.patch b/queue-5.10/fs-correctly-document-the-inode-dirty-flags.patch deleted file mode 100644 index 137acab293f..00000000000 --- a/queue-5.10/fs-correctly-document-the-inode-dirty-flags.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 5aa02147cd3d8e2a637fb16a091ff7e784f74ecd Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Tue, 12 Jan 2021 11:02:44 -0800 -Subject: fs: correctly document the inode dirty flags - -From: Eric Biggers - -[ Upstream commit 1e9d63331f8fa556f31e1406ab12f2a1e5cdb495 ] - -The documentation for I_DIRTY_SYNC and I_DIRTY_DATASYNC is a bit -misleading, and I_DIRTY_TIME isn't documented at all. Fix this. - -Link: https://lore.kernel.org/r/20210112190253.64307-3-ebiggers@kernel.org -Reviewed-by: Christoph Hellwig -Reviewed-by: Jan Kara -Signed-off-by: Eric Biggers -Signed-off-by: Jan Kara -Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE") -Signed-off-by: Sasha Levin ---- - include/linux/fs.h | 18 +++++++++++++----- - 1 file changed, 13 insertions(+), 5 deletions(-) - -diff --git a/include/linux/fs.h b/include/linux/fs.h -index c8f887641878..8ee26322a527 100644 ---- a/include/linux/fs.h -+++ b/include/linux/fs.h -@@ -2087,8 +2087,8 @@ static inline void kiocb_clone(struct kiocb *kiocb, struct kiocb *kiocb_src, - /* - * Inode state bits. Protected by inode->i_lock - * -- * Three bits determine the dirty state of the inode, I_DIRTY_SYNC, -- * I_DIRTY_DATASYNC and I_DIRTY_PAGES. -+ * Four bits determine the dirty state of the inode: I_DIRTY_SYNC, -+ * I_DIRTY_DATASYNC, I_DIRTY_PAGES, and I_DIRTY_TIME. - * - * Four bits define the lifetime of an inode. Initially, inodes are I_NEW, - * until that flag is cleared. I_WILL_FREE, I_FREEING and I_CLEAR are set at -@@ -2097,12 +2097,20 @@ static inline void kiocb_clone(struct kiocb *kiocb, struct kiocb *kiocb_src, - * Two bits are used for locking and completion notification, I_NEW and I_SYNC. - * - * I_DIRTY_SYNC Inode is dirty, but doesn't have to be written on -- * fdatasync(). i_atime is the usual cause. -- * I_DIRTY_DATASYNC Data-related inode changes pending. We keep track of -+ * fdatasync() (unless I_DIRTY_DATASYNC is also set). -+ * Timestamp updates are the usual cause. -+ * I_DIRTY_DATASYNC Data-related inode changes pending. We keep track of - * these changes separately from I_DIRTY_SYNC so that we - * don't have to write inode on fdatasync() when only -- * mtime has changed in it. -+ * e.g. the timestamps have changed. - * I_DIRTY_PAGES Inode has dirty pages. Inode itself may be clean. -+ * I_DIRTY_TIME The inode itself only has dirty timestamps, and the -+ * lazytime mount option is enabled. We keep track of this -+ * separately from I_DIRTY_SYNC in order to implement -+ * lazytime. This gets cleared if I_DIRTY_INODE -+ * (I_DIRTY_SYNC and/or I_DIRTY_DATASYNC) gets set. I.e. -+ * either I_DIRTY_TIME *or* I_DIRTY_INODE can be set in -+ * i_state, but not both. I_DIRTY_PAGES may still be set. - * I_NEW Serves as both a mutex and completion notification. - * New inodes set I_NEW. If two processes both create - * the same inode, one of them will release its inode and --- -2.35.1 - diff --git a/queue-5.10/fs-don-t-call-dirty_inode-for-lazytime-timestamp-upd.patch b/queue-5.10/fs-don-t-call-dirty_inode-for-lazytime-timestamp-upd.patch deleted file mode 100644 index 57f784dde61..00000000000 --- a/queue-5.10/fs-don-t-call-dirty_inode-for-lazytime-timestamp-upd.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 81815952d81efbb44aab514f0eaa765a0abf9744 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Tue, 12 Jan 2021 11:02:47 -0800 -Subject: fs: don't call ->dirty_inode for lazytime timestamp updates - -From: Eric Biggers - -[ Upstream commit e2728c5621fd9c68c65a6647875a1d1c67b9f257 ] - -There is no need to call ->dirty_inode for lazytime timestamp updates -(i.e. for __mark_inode_dirty(I_DIRTY_TIME)), since by the definition of -lazytime, filesystems must ignore these updates. Filesystems only need -to care about the updated timestamps when they expire. - -Therefore, only call ->dirty_inode when I_DIRTY_INODE is set. - -Based on a patch from Christoph Hellwig: -https://lore.kernel.org/r/20200325122825.1086872-4-hch@lst.de - -Link: https://lore.kernel.org/r/20210112190253.64307-6-ebiggers@kernel.org -Reviewed-by: Christoph Hellwig -Reviewed-by: Jan Kara -Signed-off-by: Eric Biggers -Signed-off-by: Jan Kara -Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE") -Signed-off-by: Sasha Levin ---- - fs/ext4/inode.c | 12 +----------- - fs/f2fs/super.c | 3 --- - fs/fs-writeback.c | 6 +++--- - fs/gfs2/super.c | 2 -- - 4 files changed, 4 insertions(+), 19 deletions(-) - -diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c -index 45f31dc1e66f..2a9ce6826d6b 100644 ---- a/fs/ext4/inode.c -+++ b/fs/ext4/inode.c -@@ -6003,26 +6003,16 @@ int __ext4_mark_inode_dirty(handle_t *handle, struct inode *inode, - * If the inode is marked synchronous, we don't honour that here - doing - * so would cause a commit on atime updates, which we don't bother doing. - * We handle synchronous inodes at the highest possible level. -- * -- * If only the I_DIRTY_TIME flag is set, we can skip everything. If -- * I_DIRTY_TIME and I_DIRTY_SYNC is set, the only inode fields we need -- * to copy into the on-disk inode structure are the timestamp files. - */ - void ext4_dirty_inode(struct inode *inode, int flags) - { - handle_t *handle; - -- if (flags == I_DIRTY_TIME) -- return; - handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); - if (IS_ERR(handle)) -- goto out; -- -+ return; - ext4_mark_inode_dirty(handle, inode); -- - ext4_journal_stop(handle); --out: -- return; - } - - int ext4_change_inode_journal_flag(struct inode *inode, int val) -diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c -index fba413ced982..b6a33935528c 100644 ---- a/fs/f2fs/super.c -+++ b/fs/f2fs/super.c -@@ -1213,9 +1213,6 @@ static void f2fs_dirty_inode(struct inode *inode, int flags) - inode->i_ino == F2FS_META_INO(sbi)) - return; - -- if (flags == I_DIRTY_TIME) -- return; -- - if (is_inode_flag_set(inode, FI_AUTO_RECOVER)) - clear_inode_flag(inode, FI_AUTO_RECOVER); - -diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c -index 2011199476ea..2088046de4ef 100644 ---- a/fs/fs-writeback.c -+++ b/fs/fs-writeback.c -@@ -2242,16 +2242,16 @@ void __mark_inode_dirty(struct inode *inode, int flags) - * Don't do this for I_DIRTY_PAGES - that doesn't actually - * dirty the inode itself - */ -- if (flags & (I_DIRTY_INODE | I_DIRTY_TIME)) { -+ if (flags & I_DIRTY_INODE) { - trace_writeback_dirty_inode_start(inode, flags); - - if (sb->s_op->dirty_inode) - sb->s_op->dirty_inode(inode, flags); - - trace_writeback_dirty_inode(inode, flags); -- } -- if (flags & I_DIRTY_INODE) -+ - flags &= ~I_DIRTY_TIME; -+ } - dirtytime = flags & I_DIRTY_TIME; - - /* -diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c -index d14b98aa1c3e..21bb02dc3aed 100644 ---- a/fs/gfs2/super.c -+++ b/fs/gfs2/super.c -@@ -506,8 +506,6 @@ static void gfs2_dirty_inode(struct inode *inode, int flags) - int need_endtrans = 0; - int ret; - -- if (!(flags & I_DIRTY_INODE)) -- return; - if (unlikely(gfs2_withdrawn(sdp))) - return; - if (!gfs2_glock_is_locked_by_me(ip->i_gl)) { --- -2.35.1 - diff --git a/queue-5.10/fs-pass-only-i_dirty_inode-flags-to-dirty_inode.patch b/queue-5.10/fs-pass-only-i_dirty_inode-flags-to-dirty_inode.patch deleted file mode 100644 index da6a913a043..00000000000 --- a/queue-5.10/fs-pass-only-i_dirty_inode-flags-to-dirty_inode.patch +++ /dev/null @@ -1,66 +0,0 @@ -From a0b3b58097f66aa6b33340b0962ff0ee41da9c60 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Tue, 12 Jan 2021 11:02:48 -0800 -Subject: fs: pass only I_DIRTY_INODE flags to ->dirty_inode - -From: Eric Biggers - -[ Upstream commit a38ed483a72672ee6bdb5d8cf17fc0838377baa0 ] - -->dirty_inode is now only called when I_DIRTY_INODE (I_DIRTY_SYNC and/or -I_DIRTY_DATASYNC) is set. However it may still be passed other dirty -flags at the same time, provided that these other flags happened to be -passed to __mark_inode_dirty() at the same time as I_DIRTY_INODE. - -This doesn't make sense because there is no reason for filesystems to -care about these extra flags. Nor are filesystems notified about all -updates to these other flags. - -Therefore, mask the flags before passing them to ->dirty_inode. - -Also properly document ->dirty_inode in vfs.rst. - -Link: https://lore.kernel.org/r/20210112190253.64307-7-ebiggers@kernel.org -Reviewed-by: Christoph Hellwig -Reviewed-by: Jan Kara -Signed-off-by: Eric Biggers -Signed-off-by: Jan Kara -Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE") -Signed-off-by: Sasha Levin ---- - Documentation/filesystems/vfs.rst | 5 ++++- - fs/fs-writeback.c | 2 +- - 2 files changed, 5 insertions(+), 2 deletions(-) - -diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst -index ca52c82e5bb5..287b80948a40 100644 ---- a/Documentation/filesystems/vfs.rst -+++ b/Documentation/filesystems/vfs.rst -@@ -270,7 +270,10 @@ or bottom half). - ->alloc_inode. - - ``dirty_inode`` -- this method is called by the VFS to mark an inode dirty. -+ this method is called by the VFS when an inode is marked dirty. -+ This is specifically for the inode itself being marked dirty, -+ not its data. If the update needs to be persisted by fdatasync(), -+ then I_DIRTY_DATASYNC will be set in the flags argument. - - ``write_inode`` - this method is called when the VFS needs to write an inode to -diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c -index 2088046de4ef..b6d572a519fa 100644 ---- a/fs/fs-writeback.c -+++ b/fs/fs-writeback.c -@@ -2246,7 +2246,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) - trace_writeback_dirty_inode_start(inode, flags); - - if (sb->s_op->dirty_inode) -- sb->s_op->dirty_inode(inode, flags); -+ sb->s_op->dirty_inode(inode, flags & I_DIRTY_INODE); - - trace_writeback_dirty_inode(inode, flags); - --- -2.35.1 - diff --git a/queue-5.10/fs-record-i_dirty_time-even-if-inode-already-has-i_d.patch b/queue-5.10/fs-record-i_dirty_time-even-if-inode-already-has-i_d.patch deleted file mode 100644 index 93e4a9b2340..00000000000 --- a/queue-5.10/fs-record-i_dirty_time-even-if-inode-already-has-i_d.patch +++ /dev/null @@ -1,196 +0,0 @@ -From 8139a7d3a79e5c63d33a578821e0cc2785e0d377 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Thu, 25 Aug 2022 12:06:57 +0200 -Subject: fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE - -From: Lukas Czerner - -[ Upstream commit cbfecb927f429a6fa613d74b998496bd71e4438a ] - -Currently the I_DIRTY_TIME will never get set if the inode already has -I_DIRTY_INODE with assumption that it supersedes I_DIRTY_TIME. That's -true, however ext4 will only update the on-disk inode in -->dirty_inode(), not on actual writeback. As a result if the inode -already has I_DIRTY_INODE state by the time we get to -__mark_inode_dirty() only with I_DIRTY_TIME, the time was already filled -into on-disk inode and will not get updated until the next I_DIRTY_INODE -update, which might never come if we crash or get a power failure. - -The problem can be reproduced on ext4 by running xfstest generic/622 -with -o iversion mount option. - -Fix it by allowing I_DIRTY_TIME to be set even if the inode already has -I_DIRTY_INODE. Also make sure that the case is properly handled in -writeback_single_inode() as well. Additionally changes in -xfs_fs_dirty_inode() was made to accommodate for I_DIRTY_TIME in flag. - -Thanks Jan Kara for suggestions on how to make this work properly. - -Cc: Dave Chinner -Cc: Christoph Hellwig -Cc: stable@kernel.org -Signed-off-by: Lukas Czerner -Suggested-by: Jan Kara -Reviewed-by: Jan Kara -Link: https://lore.kernel.org/r/20220825100657.44217-1-lczerner@redhat.com -Signed-off-by: Theodore Ts'o -Signed-off-by: Sasha Levin ---- - Documentation/filesystems/vfs.rst | 3 +++ - fs/fs-writeback.c | 37 +++++++++++++++++++++---------- - fs/xfs/xfs_super.c | 10 +++++++-- - include/linux/fs.h | 9 ++++---- - 4 files changed, 41 insertions(+), 18 deletions(-) - -diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst -index 287b80948a40..ee69d60818b5 100644 ---- a/Documentation/filesystems/vfs.rst -+++ b/Documentation/filesystems/vfs.rst -@@ -274,6 +274,9 @@ or bottom half). - This is specifically for the inode itself being marked dirty, - not its data. If the update needs to be persisted by fdatasync(), - then I_DIRTY_DATASYNC will be set in the flags argument. -+ I_DIRTY_TIME will be set in the flags in case lazytime is enabled -+ and struct inode has times updated since the last ->dirty_inode -+ call. - - ``write_inode`` - this method is called when the VFS needs to write an inode to -diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c -index 4c667662a4d9..f47797e15685 100644 ---- a/fs/fs-writeback.c -+++ b/fs/fs-writeback.c -@@ -1618,9 +1618,14 @@ static int writeback_single_inode(struct inode *inode, - */ - if (!(inode->i_state & I_DIRTY_ALL)) - inode_cgwb_move_to_attached(inode, wb); -- else if (!(inode->i_state & I_SYNC_QUEUED) && -- (inode->i_state & I_DIRTY)) -- redirty_tail_locked(inode, wb); -+ else if (!(inode->i_state & I_SYNC_QUEUED)) { -+ if ((inode->i_state & I_DIRTY)) -+ redirty_tail_locked(inode, wb); -+ else if (inode->i_state & I_DIRTY_TIME) { -+ inode->dirtied_when = jiffies; -+ inode_io_list_move_locked(inode, wb, &wb->b_dirty_time); -+ } -+ } - - spin_unlock(&wb->list_lock); - inode_sync_complete(inode); -@@ -2276,6 +2281,20 @@ void __mark_inode_dirty(struct inode *inode, int flags) - trace_writeback_mark_inode_dirty(inode, flags); - - if (flags & I_DIRTY_INODE) { -+ /* -+ * Inode timestamp update will piggback on this dirtying. -+ * We tell ->dirty_inode callback that timestamps need to -+ * be updated by setting I_DIRTY_TIME in flags. -+ */ -+ if (inode->i_state & I_DIRTY_TIME) { -+ spin_lock(&inode->i_lock); -+ if (inode->i_state & I_DIRTY_TIME) { -+ inode->i_state &= ~I_DIRTY_TIME; -+ flags |= I_DIRTY_TIME; -+ } -+ spin_unlock(&inode->i_lock); -+ } -+ - /* - * Notify the filesystem about the inode being dirtied, so that - * (if needed) it can update on-disk fields and journal the -@@ -2285,7 +2304,8 @@ void __mark_inode_dirty(struct inode *inode, int flags) - */ - trace_writeback_dirty_inode_start(inode, flags); - if (sb->s_op->dirty_inode) -- sb->s_op->dirty_inode(inode, flags & I_DIRTY_INODE); -+ sb->s_op->dirty_inode(inode, -+ flags & (I_DIRTY_INODE | I_DIRTY_TIME)); - trace_writeback_dirty_inode(inode, flags); - - /* I_DIRTY_INODE supersedes I_DIRTY_TIME. */ -@@ -2306,21 +2326,15 @@ void __mark_inode_dirty(struct inode *inode, int flags) - */ - smp_mb(); - -- if (((inode->i_state & flags) == flags) || -- (dirtytime && (inode->i_state & I_DIRTY_INODE))) -+ if ((inode->i_state & flags) == flags) - return; - - spin_lock(&inode->i_lock); -- if (dirtytime && (inode->i_state & I_DIRTY_INODE)) -- goto out_unlock_inode; - if ((inode->i_state & flags) != flags) { - const int was_dirty = inode->i_state & I_DIRTY; - - inode_attach_wb(inode, NULL); - -- /* I_DIRTY_INODE supersedes I_DIRTY_TIME. */ -- if (flags & I_DIRTY_INODE) -- inode->i_state &= ~I_DIRTY_TIME; - inode->i_state |= flags; - - /* -@@ -2393,7 +2407,6 @@ void __mark_inode_dirty(struct inode *inode, int flags) - out_unlock: - if (wb) - spin_unlock(&wb->list_lock); --out_unlock_inode: - spin_unlock(&inode->i_lock); - } - EXPORT_SYMBOL(__mark_inode_dirty); -diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c -index 434c87cc9fbf..3cc20640b3da 100644 ---- a/fs/xfs/xfs_super.c -+++ b/fs/xfs/xfs_super.c -@@ -668,7 +668,7 @@ xfs_fs_destroy_inode( - static void - xfs_fs_dirty_inode( - struct inode *inode, -- int flag) -+ int flags) - { - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; -@@ -676,7 +676,13 @@ xfs_fs_dirty_inode( - - if (!(inode->i_sb->s_flags & SB_LAZYTIME)) - return; -- if (flag != I_DIRTY_SYNC || !(inode->i_state & I_DIRTY_TIME)) -+ -+ /* -+ * Only do the timestamp update if the inode is dirty (I_DIRTY_SYNC) -+ * and has dirty timestamp (I_DIRTY_TIME). I_DIRTY_TIME can be passed -+ * in flags possibly together with I_DIRTY_SYNC. -+ */ -+ if ((flags & ~I_DIRTY_TIME) != I_DIRTY_SYNC || !(flags & I_DIRTY_TIME)) - return; - - if (xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp)) -diff --git a/include/linux/fs.h b/include/linux/fs.h -index 8ee26322a527..ae7cd6ee1142 100644 ---- a/include/linux/fs.h -+++ b/include/linux/fs.h -@@ -2104,13 +2104,14 @@ static inline void kiocb_clone(struct kiocb *kiocb, struct kiocb *kiocb_src, - * don't have to write inode on fdatasync() when only - * e.g. the timestamps have changed. - * I_DIRTY_PAGES Inode has dirty pages. Inode itself may be clean. -- * I_DIRTY_TIME The inode itself only has dirty timestamps, and the -+ * I_DIRTY_TIME The inode itself has dirty timestamps, and the - * lazytime mount option is enabled. We keep track of this - * separately from I_DIRTY_SYNC in order to implement - * lazytime. This gets cleared if I_DIRTY_INODE -- * (I_DIRTY_SYNC and/or I_DIRTY_DATASYNC) gets set. I.e. -- * either I_DIRTY_TIME *or* I_DIRTY_INODE can be set in -- * i_state, but not both. I_DIRTY_PAGES may still be set. -+ * (I_DIRTY_SYNC and/or I_DIRTY_DATASYNC) gets set. But -+ * I_DIRTY_TIME can still be set if I_DIRTY_SYNC is already -+ * in place because writeback might already be in progress -+ * and we don't want to lose the time update - * I_NEW Serves as both a mutex and completion notification. - * New inodes set I_NEW. If two processes both create - * the same inode, one of them will release its inode and --- -2.35.1 - diff --git a/queue-5.10/series b/queue-5.10/series index 0b3c9308434..306f6490c74 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -55,15 +55,6 @@ iommu-vt-d-clean-up-si_domain-in-the-init_dmars-erro.patch drm-virtio-use-appropriate-atomic-state-in-virtio_gp.patch dmaengine-mxs-dma-remove-the-unused-.id_table.patch dmaengine-mxs-use-platform_driver_register.patch -writeback-don-t-warn-on-an-unregistered-bdi-in-__mar.patch -fs-correctly-document-the-inode-dirty-flags.patch -fs-don-t-call-dirty_inode-for-lazytime-timestamp-upd.patch -fs-pass-only-i_dirty_inode-flags-to-dirty_inode.patch -fs-clean-up-__mark_inode_dirty-a-bit.patch -writeback-cgroup-keep-list-of-inodes-attached-to-bdi.patch -writeback-avoid-skipping-inode-writeback.patch -writeback-fix-inode-i_io_list-not-be-protected-by-in.patch -fs-record-i_dirty_time-even-if-inode-already-has-i_d.patch tracing-simplify-conditional-compilation-code-in-tra.patch tracing-do-not-free-snapshot-if-tracer-is-on-cmdline.patch xen-assume-xenfeat_gnttab_map_avail_bits-being-set-f.patch diff --git a/queue-5.10/writeback-avoid-skipping-inode-writeback.patch b/queue-5.10/writeback-avoid-skipping-inode-writeback.patch deleted file mode 100644 index 9286c51a9b3..00000000000 --- a/queue-5.10/writeback-avoid-skipping-inode-writeback.patch +++ /dev/null @@ -1,74 +0,0 @@ -From c48b354b20bb7b07b2e92f5e3a77a4a22cec038e Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Tue, 10 May 2022 10:35:14 +0800 -Subject: writeback: Avoid skipping inode writeback - -From: Jing Xia - -[ Upstream commit 846a3351ddfe4a86eede4bb26a205c3f38ef84d3 ] - -We have run into an issue that a task gets stuck in -balance_dirty_pages_ratelimited() when perform I/O stress testing. -The reason we observed is that an I_DIRTY_PAGES inode with lots -of dirty pages is in b_dirty_time list and standard background -writeback cannot writeback the inode. -After studing the relevant code, the following scenario may lead -to the issue: - -task1 task2 ------ ----- -fuse_flush - write_inode_now //in b_dirty_time - writeback_single_inode - __writeback_single_inode - fuse_write_end - filemap_dirty_folio - __xa_set_mark:PAGECACHE_TAG_DIRTY - lock inode->i_lock - if mapping tagged PAGECACHE_TAG_DIRTY - inode->i_state |= I_DIRTY_PAGES - unlock inode->i_lock - __mark_inode_dirty:I_DIRTY_PAGES - lock inode->i_lock - -was dirty,inode stays in - -b_dirty_time - unlock inode->i_lock - - if(!(inode->i_state & I_DIRTY_All)) - -not true,so nothing done - -This patch moves the dirty inode to b_dirty list when the inode -currently is not queued in b_io or b_more_io list at the end of -writeback_single_inode. - -Reviewed-by: Jan Kara -Reviewed-by: Christoph Hellwig -CC: stable@vger.kernel.org -Fixes: 0ae45f63d4ef ("vfs: add support for a lazytime mount option") -Signed-off-by: Jing Xia -Signed-off-by: Jan Kara -Link: https://lore.kernel.org/r/20220510023514.27399-1-jing.xia@unisoc.com -Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE") -Signed-off-by: Sasha Levin ---- - fs/fs-writeback.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c -index 489514bcd7e1..645e3f6ffe44 100644 ---- a/fs/fs-writeback.c -+++ b/fs/fs-writeback.c -@@ -1612,6 +1612,10 @@ static int writeback_single_inode(struct inode *inode, - */ - if (!(inode->i_state & I_DIRTY_ALL)) - inode_cgwb_move_to_attached(inode, wb); -+ else if (!(inode->i_state & I_SYNC_QUEUED) && -+ (inode->i_state & I_DIRTY)) -+ redirty_tail_locked(inode, wb); -+ - spin_unlock(&wb->list_lock); - inode_sync_complete(inode); - out: --- -2.35.1 - diff --git a/queue-5.10/writeback-cgroup-keep-list-of-inodes-attached-to-bdi.patch b/queue-5.10/writeback-cgroup-keep-list-of-inodes-attached-to-bdi.patch deleted file mode 100644 index 8ae3779898a..00000000000 --- a/queue-5.10/writeback-cgroup-keep-list-of-inodes-attached-to-bdi.patch +++ /dev/null @@ -1,231 +0,0 @@ -From 6ebfdd72f515b6ccb3f7f3900a4f12c715dd8290 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Mon, 28 Jun 2021 19:35:53 -0700 -Subject: writeback, cgroup: keep list of inodes attached to bdi_writeback - -From: Roman Gushchin - -[ Upstream commit f3b6a6df38aa514d97e8c6fcc748be1d4142bec9 ] - -Currently there is no way to iterate over inodes attached to a specific -cgwb structure. It limits the ability to efficiently reclaim the -writeback structure itself and associated memory and block cgroup -structures without scanning all inodes belonging to a sb, which can be -prohibitively expensive. - -While dirty/in-active-writeback an inode belongs to one of the -bdi_writeback's io lists: b_dirty, b_io, b_more_io and b_dirty_time. Once -cleaned up, it's removed from all io lists. So the inode->i_io_list can -be reused to maintain the list of inodes, attached to a bdi_writeback -structure. - -This patch introduces a new wb->b_attached list, which contains all inodes -which were dirty at least once and are attached to the given cgwb. Inodes -attached to the root bdi_writeback structures are never placed on such -list. The following patch will use this list to try to release cgwbs -structures more efficiently. - -Link: https://lkml.kernel.org/r/20210608230225.2078447-6-guro@fb.com -Signed-off-by: Roman Gushchin -Suggested-by: Jan Kara -Reviewed-by: Jan Kara -Acked-by: Tejun Heo -Acked-by: Dennis Zhou -Cc: Alexander Viro -Cc: Dave Chinner -Cc: Jan Kara -Cc: Jens Axboe -Signed-off-by: Andrew Morton -Signed-off-by: Linus Torvalds -Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE") -Signed-off-by: Sasha Levin ---- - fs/fs-writeback.c | 93 ++++++++++++++++++++------------ - include/linux/backing-dev-defs.h | 1 + - mm/backing-dev.c | 2 + - 3 files changed, 62 insertions(+), 34 deletions(-) - -diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c -index 71043e847e7c..489514bcd7e1 100644 ---- a/fs/fs-writeback.c -+++ b/fs/fs-writeback.c -@@ -131,25 +131,6 @@ static bool inode_io_list_move_locked(struct inode *inode, - return false; - } - --/** -- * inode_io_list_del_locked - remove an inode from its bdi_writeback IO list -- * @inode: inode to be removed -- * @wb: bdi_writeback @inode is being removed from -- * -- * Remove @inode which may be on one of @wb->b_{dirty|io|more_io} lists and -- * clear %WB_has_dirty_io if all are empty afterwards. -- */ --static void inode_io_list_del_locked(struct inode *inode, -- struct bdi_writeback *wb) --{ -- assert_spin_locked(&wb->list_lock); -- assert_spin_locked(&inode->i_lock); -- -- inode->i_state &= ~I_SYNC_QUEUED; -- list_del_init(&inode->i_io_list); -- wb_io_lists_depopulated(wb); --} -- - static void wb_wakeup(struct bdi_writeback *wb) - { - spin_lock_bh(&wb->work_lock); -@@ -278,6 +259,28 @@ void __inode_attach_wb(struct inode *inode, struct page *page) - } - EXPORT_SYMBOL_GPL(__inode_attach_wb); - -+/** -+ * inode_cgwb_move_to_attached - put the inode onto wb->b_attached list -+ * @inode: inode of interest with i_lock held -+ * @wb: target bdi_writeback -+ * -+ * Remove the inode from wb's io lists and if necessarily put onto b_attached -+ * list. Only inodes attached to cgwb's are kept on this list. -+ */ -+static void inode_cgwb_move_to_attached(struct inode *inode, -+ struct bdi_writeback *wb) -+{ -+ assert_spin_locked(&wb->list_lock); -+ assert_spin_locked(&inode->i_lock); -+ -+ inode->i_state &= ~I_SYNC_QUEUED; -+ if (wb != &wb->bdi->wb) -+ list_move(&inode->i_io_list, &wb->b_attached); -+ else -+ list_del_init(&inode->i_io_list); -+ wb_io_lists_depopulated(wb); -+} -+ - /** - * locked_inode_to_wb_and_lock_list - determine a locked inode's wb and lock it - * @inode: inode of interest with i_lock held -@@ -419,21 +422,28 @@ static void inode_switch_wbs_work_fn(struct work_struct *work) - wb_get(new_wb); - - /* -- * Transfer to @new_wb's IO list if necessary. The specific list -- * @inode was on is ignored and the inode is put on ->b_dirty which -- * is always correct including from ->b_dirty_time. The transfer -- * preserves @inode->dirtied_when ordering. -+ * Transfer to @new_wb's IO list if necessary. If the @inode is dirty, -+ * the specific list @inode was on is ignored and the @inode is put on -+ * ->b_dirty which is always correct including from ->b_dirty_time. -+ * The transfer preserves @inode->dirtied_when ordering. If the @inode -+ * was clean, it means it was on the b_attached list, so move it onto -+ * the b_attached list of @new_wb. - */ - if (!list_empty(&inode->i_io_list)) { -- struct inode *pos; -- -- inode_io_list_del_locked(inode, old_wb); - inode->i_wb = new_wb; -- list_for_each_entry(pos, &new_wb->b_dirty, i_io_list) -- if (time_after_eq(inode->dirtied_when, -- pos->dirtied_when)) -- break; -- inode_io_list_move_locked(inode, new_wb, pos->i_io_list.prev); -+ -+ if (inode->i_state & I_DIRTY_ALL) { -+ struct inode *pos; -+ -+ list_for_each_entry(pos, &new_wb->b_dirty, i_io_list) -+ if (time_after_eq(inode->dirtied_when, -+ pos->dirtied_when)) -+ break; -+ inode_io_list_move_locked(inode, new_wb, -+ pos->i_io_list.prev); -+ } else { -+ inode_cgwb_move_to_attached(inode, new_wb); -+ } - } else { - inode->i_wb = new_wb; - } -@@ -1030,6 +1040,17 @@ fs_initcall(cgroup_writeback_init); - static void bdi_down_write_wb_switch_rwsem(struct backing_dev_info *bdi) { } - static void bdi_up_write_wb_switch_rwsem(struct backing_dev_info *bdi) { } - -+static void inode_cgwb_move_to_attached(struct inode *inode, -+ struct bdi_writeback *wb) -+{ -+ assert_spin_locked(&wb->list_lock); -+ assert_spin_locked(&inode->i_lock); -+ -+ inode->i_state &= ~I_SYNC_QUEUED; -+ list_del_init(&inode->i_io_list); -+ wb_io_lists_depopulated(wb); -+} -+ - static struct bdi_writeback * - locked_inode_to_wb_and_lock_list(struct inode *inode) - __releases(&inode->i_lock) -@@ -1130,7 +1151,11 @@ void inode_io_list_del(struct inode *inode) - - wb = inode_to_wb_and_lock_list(inode); - spin_lock(&inode->i_lock); -- inode_io_list_del_locked(inode, wb); -+ -+ inode->i_state &= ~I_SYNC_QUEUED; -+ list_del_init(&inode->i_io_list); -+ wb_io_lists_depopulated(wb); -+ - spin_unlock(&inode->i_lock); - spin_unlock(&wb->list_lock); - } -@@ -1443,7 +1468,7 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb, - inode->i_state &= ~I_SYNC_QUEUED; - } else { - /* The inode is clean. Remove from writeback lists. */ -- inode_io_list_del_locked(inode, wb); -+ inode_cgwb_move_to_attached(inode, wb); - } - } - -@@ -1586,7 +1611,7 @@ static int writeback_single_inode(struct inode *inode, - * touch it. See comment above for explanation. - */ - if (!(inode->i_state & I_DIRTY_ALL)) -- inode_io_list_del_locked(inode, wb); -+ inode_cgwb_move_to_attached(inode, wb); - spin_unlock(&wb->list_lock); - inode_sync_complete(inode); - out: -diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h -index fff9367a6348..e5dc238ebe4f 100644 ---- a/include/linux/backing-dev-defs.h -+++ b/include/linux/backing-dev-defs.h -@@ -154,6 +154,7 @@ struct bdi_writeback { - struct cgroup_subsys_state *blkcg_css; /* and blkcg */ - struct list_head memcg_node; /* anchored at memcg->cgwb_list */ - struct list_head blkcg_node; /* anchored at blkcg->cgwb_list */ -+ struct list_head b_attached; /* attached inodes, protected by list_lock */ - - union { - struct work_struct release_work; -diff --git a/mm/backing-dev.c b/mm/backing-dev.c -index ca770a783a9f..1c1b44fcaf7d 100644 ---- a/mm/backing-dev.c -+++ b/mm/backing-dev.c -@@ -397,6 +397,7 @@ static void cgwb_release_workfn(struct work_struct *work) - fprop_local_destroy_percpu(&wb->memcg_completions); - percpu_ref_exit(&wb->refcnt); - wb_exit(wb); -+ WARN_ON_ONCE(!list_empty(&wb->b_attached)); - kfree_rcu(wb, rcu); - } - -@@ -473,6 +474,7 @@ static int cgwb_create(struct backing_dev_info *bdi, - - wb->memcg_css = memcg_css; - wb->blkcg_css = blkcg_css; -+ INIT_LIST_HEAD(&wb->b_attached); - INIT_WORK(&wb->release_work, cgwb_release_workfn); - set_bit(WB_registered, &wb->state); - --- -2.35.1 - diff --git a/queue-5.10/writeback-don-t-warn-on-an-unregistered-bdi-in-__mar.patch b/queue-5.10/writeback-don-t-warn-on-an-unregistered-bdi-in-__mar.patch deleted file mode 100644 index ccfd10ecfdf..00000000000 --- a/queue-5.10/writeback-don-t-warn-on-an-unregistered-bdi-in-__mar.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 4854300901e994f74b1801192c89cbab97d1a9da Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Mon, 28 Sep 2020 14:26:13 +0200 -Subject: writeback: don't warn on an unregistered BDI in __mark_inode_dirty - -From: Christoph Hellwig - -[ Upstream commit f7387170339afb473a0d95b7732f904346f9795e ] - -BDIs get unregistered during device removal, and this WARN can be -trivially triggered by hot-removing a NVMe device while running fsx -It is otherwise harmless as we still hold a BDI reference, and the -writeback has been shut down already. - -Link: https://lore.kernel.org/r/20200928122613.434820-1-hch@lst.de -Signed-off-by: Christoph Hellwig -Signed-off-by: Jan Kara -Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE") -Signed-off-by: Sasha Levin ---- - fs/fs-writeback.c | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c -index 46c15dd2405c..2011199476ea 100644 ---- a/fs/fs-writeback.c -+++ b/fs/fs-writeback.c -@@ -2307,10 +2307,6 @@ void __mark_inode_dirty(struct inode *inode, int flags) - - wb = locked_inode_to_wb_and_lock_list(inode); - -- WARN((wb->bdi->capabilities & BDI_CAP_WRITEBACK) && -- !test_bit(WB_registered, &wb->state), -- "bdi-%s not registered\n", bdi_dev_name(wb->bdi)); -- - inode->dirtied_when = jiffies; - if (dirtytime) - inode->dirtied_time_when = jiffies; --- -2.35.1 - diff --git a/queue-5.10/writeback-fix-inode-i_io_list-not-be-protected-by-in.patch b/queue-5.10/writeback-fix-inode-i_io_list-not-be-protected-by-in.patch deleted file mode 100644 index e96e2a80e94..00000000000 --- a/queue-5.10/writeback-fix-inode-i_io_list-not-be-protected-by-in.patch +++ /dev/null @@ -1,171 +0,0 @@ -From a6d977e8d36035d60883d72a9a881a77520bfc03 Mon Sep 17 00:00:00 2001 -From: Sasha Levin -Date: Tue, 24 May 2022 08:05:40 -0700 -Subject: writeback: Fix inode->i_io_list not be protected by inode->i_lock - error - -From: Jchao Sun - -[ Upstream commit 10e14073107dd0b6d97d9516a02845a8e501c2c9 ] - -Commit b35250c0816c ("writeback: Protect inode->i_io_list with -inode->i_lock") made inode->i_io_list not only protected by -wb->list_lock but also inode->i_lock, but inode_io_list_move_locked() -was missed. Add lock there and also update comment describing -things protected by inode->i_lock. This also fixes a race where -__mark_inode_dirty() could move inode under flush worker's hands -and thus sync(2) could miss writing some inodes. - -Fixes: b35250c0816c ("writeback: Protect inode->i_io_list with inode->i_lock") -Link: https://lore.kernel.org/r/20220524150540.12552-1-sunjunchao2870@gmail.com -CC: stable@vger.kernel.org -Signed-off-by: Jchao Sun -Signed-off-by: Jan Kara -Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE") -Signed-off-by: Sasha Levin ---- - fs/fs-writeback.c | 37 ++++++++++++++++++++++++++++--------- - fs/inode.c | 2 +- - 2 files changed, 29 insertions(+), 10 deletions(-) - -diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c -index 645e3f6ffe44..4c667662a4d9 100644 ---- a/fs/fs-writeback.c -+++ b/fs/fs-writeback.c -@@ -120,6 +120,7 @@ static bool inode_io_list_move_locked(struct inode *inode, - struct list_head *head) - { - assert_spin_locked(&wb->list_lock); -+ assert_spin_locked(&inode->i_lock); - - list_move(&inode->i_io_list, head); - -@@ -1282,9 +1283,9 @@ static int move_expired_inodes(struct list_head *delaying_queue, - inode = wb_inode(delaying_queue->prev); - if (inode_dirtied_after(inode, dirtied_before)) - break; -+ spin_lock(&inode->i_lock); - list_move(&inode->i_io_list, &tmp); - moved++; -- spin_lock(&inode->i_lock); - inode->i_state |= I_SYNC_QUEUED; - spin_unlock(&inode->i_lock); - if (sb_is_blkdev_sb(inode->i_sb)) -@@ -1300,7 +1301,12 @@ static int move_expired_inodes(struct list_head *delaying_queue, - goto out; - } - -- /* Move inodes from one superblock together */ -+ /* -+ * Although inode's i_io_list is moved from 'tmp' to 'dispatch_queue', -+ * we don't take inode->i_lock here because it is just a pointless overhead. -+ * Inode is already marked as I_SYNC_QUEUED so writeback list handling is -+ * fully under our control. -+ */ - while (!list_empty(&tmp)) { - sb = wb_inode(tmp.prev)->i_sb; - list_for_each_prev_safe(pos, node, &tmp) { -@@ -1726,8 +1732,8 @@ static long writeback_sb_inodes(struct super_block *sb, - * We'll have another go at writing back this inode - * when we completed a full scan of b_io. - */ -- spin_unlock(&inode->i_lock); - requeue_io(inode, wb); -+ spin_unlock(&inode->i_lock); - trace_writeback_sb_inodes_requeue(inode); - continue; - } -@@ -2265,6 +2271,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) - { - struct super_block *sb = inode->i_sb; - int dirtytime = 0; -+ struct bdi_writeback *wb = NULL; - - trace_writeback_mark_inode_dirty(inode, flags); - -@@ -2316,6 +2323,17 @@ void __mark_inode_dirty(struct inode *inode, int flags) - inode->i_state &= ~I_DIRTY_TIME; - inode->i_state |= flags; - -+ /* -+ * Grab inode's wb early because it requires dropping i_lock and we -+ * need to make sure following checks happen atomically with dirty -+ * list handling so that we don't move inodes under flush worker's -+ * hands. -+ */ -+ if (!was_dirty) { -+ wb = locked_inode_to_wb_and_lock_list(inode); -+ spin_lock(&inode->i_lock); -+ } -+ - /* - * If the inode is queued for writeback by flush worker, just - * update its dirty state. Once the flush worker is done with -@@ -2323,7 +2341,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) - * list, based upon its state. - */ - if (inode->i_state & I_SYNC_QUEUED) -- goto out_unlock_inode; -+ goto out_unlock; - - /* - * Only add valid (hashed) inodes to the superblock's -@@ -2331,22 +2349,19 @@ void __mark_inode_dirty(struct inode *inode, int flags) - */ - if (!S_ISBLK(inode->i_mode)) { - if (inode_unhashed(inode)) -- goto out_unlock_inode; -+ goto out_unlock; - } - if (inode->i_state & I_FREEING) -- goto out_unlock_inode; -+ goto out_unlock; - - /* - * If the inode was already on b_dirty/b_io/b_more_io, don't - * reposition it (that would break b_dirty time-ordering). - */ - if (!was_dirty) { -- struct bdi_writeback *wb; - struct list_head *dirty_list; - bool wakeup_bdi = false; - -- wb = locked_inode_to_wb_and_lock_list(inode); -- - inode->dirtied_when = jiffies; - if (dirtytime) - inode->dirtied_time_when = jiffies; -@@ -2360,6 +2375,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) - dirty_list); - - spin_unlock(&wb->list_lock); -+ spin_unlock(&inode->i_lock); - trace_writeback_dirty_inode_enqueue(inode); - - /* -@@ -2374,6 +2390,9 @@ void __mark_inode_dirty(struct inode *inode, int flags) - return; - } - } -+out_unlock: -+ if (wb) -+ spin_unlock(&wb->list_lock); - out_unlock_inode: - spin_unlock(&inode->i_lock); - } -diff --git a/fs/inode.c b/fs/inode.c -index 9f49e0bdc2f7..51726f2ad994 100644 ---- a/fs/inode.c -+++ b/fs/inode.c -@@ -28,7 +28,7 @@ - * Inode locking rules: - * - * inode->i_lock protects: -- * inode->i_state, inode->i_hash, __iget() -+ * inode->i_state, inode->i_hash, __iget(), inode->i_io_list - * Inode LRU list locks protect: - * inode->i_sb->s_inode_lru, inode->i_lru - * inode->i_sb->s_inode_list_lock protects: --- -2.35.1 - -- 2.47.3