+++ /dev/null
-From 14e2488e7853fd96ed92fd5443a4e3a5e6cf2174 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 12 Jan 2021 11:02:49 -0800
-Subject: fs: clean up __mark_inode_dirty() a bit
-
-From: Eric Biggers <ebiggers@google.com>
-
-[ 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 <hch@lst.de>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Signed-off-by: Eric Biggers <ebiggers@google.com>
-Signed-off-by: Jan Kara <jack@suse.cz>
-Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From 5aa02147cd3d8e2a637fb16a091ff7e784f74ecd Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 12 Jan 2021 11:02:44 -0800
-Subject: fs: correctly document the inode dirty flags
-
-From: Eric Biggers <ebiggers@google.com>
-
-[ 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 <hch@lst.de>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Signed-off-by: Eric Biggers <ebiggers@google.com>
-Signed-off-by: Jan Kara <jack@suse.cz>
-Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From 81815952d81efbb44aab514f0eaa765a0abf9744 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 12 Jan 2021 11:02:47 -0800
-Subject: fs: don't call ->dirty_inode for lazytime timestamp updates
-
-From: Eric Biggers <ebiggers@google.com>
-
-[ 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 <hch@lst.de>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Signed-off-by: Eric Biggers <ebiggers@google.com>
-Signed-off-by: Jan Kara <jack@suse.cz>
-Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From a0b3b58097f66aa6b33340b0962ff0ee41da9c60 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 12 Jan 2021 11:02:48 -0800
-Subject: fs: pass only I_DIRTY_INODE flags to ->dirty_inode
-
-From: Eric Biggers <ebiggers@google.com>
-
-[ 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 <hch@lst.de>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Signed-off-by: Eric Biggers <ebiggers@google.com>
-Signed-off-by: Jan Kara <jack@suse.cz>
-Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From 8139a7d3a79e5c63d33a578821e0cc2785e0d377 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-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 <lczerner@redhat.com>
-
-[ 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 <david@fromorbit.com>
-Cc: Christoph Hellwig <hch@infradead.org>
-Cc: stable@kernel.org
-Signed-off-by: Lukas Czerner <lczerner@redhat.com>
-Suggested-by: Jan Kara <jack@suse.cz>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Link: https://lore.kernel.org/r/20220825100657.44217-1-lczerner@redhat.com
-Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
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
+++ /dev/null
-From c48b354b20bb7b07b2e92f5e3a77a4a22cec038e Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Tue, 10 May 2022 10:35:14 +0800
-Subject: writeback: Avoid skipping inode writeback
-
-From: Jing Xia <jing.xia@unisoc.com>
-
-[ 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 <jack@suse.cz>
-Reviewed-by: Christoph Hellwig <hch@lst.de>
-CC: stable@vger.kernel.org
-Fixes: 0ae45f63d4ef ("vfs: add support for a lazytime mount option")
-Signed-off-by: Jing Xia <jing.xia@unisoc.com>
-Signed-off-by: Jan Kara <jack@suse.cz>
-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 <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From 6ebfdd72f515b6ccb3f7f3900a4f12c715dd8290 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Mon, 28 Jun 2021 19:35:53 -0700
-Subject: writeback, cgroup: keep list of inodes attached to bdi_writeback
-
-From: Roman Gushchin <guro@fb.com>
-
-[ 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 <guro@fb.com>
-Suggested-by: Jan Kara <jack@suse.cz>
-Reviewed-by: Jan Kara <jack@suse.cz>
-Acked-by: Tejun Heo <tj@kernel.org>
-Acked-by: Dennis Zhou <dennis@kernel.org>
-Cc: Alexander Viro <viro@zeniv.linux.org.uk>
-Cc: Dave Chinner <dchinner@redhat.com>
-Cc: Jan Kara <jack@suse.com>
-Cc: Jens Axboe <axboe@kernel.dk>
-Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
-Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From 4854300901e994f74b1801192c89cbab97d1a9da Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-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 <hch@lst.de>
-
-[ 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 <hch@lst.de>
-Signed-off-by: Jan Kara <jack@suse.cz>
-Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-
+++ /dev/null
-From a6d977e8d36035d60883d72a9a881a77520bfc03 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-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 <sunjunchao2870@gmail.com>
-
-[ 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 <sunjunchao2870@gmail.com>
-Signed-off-by: Jan Kara <jack@suse.cz>
-Stable-dep-of: cbfecb927f42 ("fs: record I_DIRTY_TIME even if inode already has I_DIRTY_INODE")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- 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
-