[PATCH v2 07/54] fs: hold an i_obj_count reference for the i_io_list
From: Josef Bacik <josef@toxicpanda.com>
Date: 2025-08-26 15:40:59
Also in:
linux-btrfs, linux-fsdevel, linux-xfs
Subsystem:
filesystems (vfs and infrastructure), the rest · Maintainers:
Alexander Viro, Christian Brauner, Linus Torvalds
While the inode is attached to a list with its i_io_list member we need to hold a reference on the object. The put is under the i_lock in some cases which could potentially be unsafe. It isn't currently because we're holding the i_obj_count throughout the entire lifetime of the inode, so it won't be the last currently. Subsequent patches will make sure we're holding an i_obj_count reference while we're manipulating this list to ensure this continues to be safe. Signed-off-by: Josef Bacik <josef@toxicpanda.com> --- fs/fs-writeback.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index cb5e22169808..cf7fab59e4d5 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c@@ -72,6 +72,14 @@ static inline struct inode *wb_inode(struct list_head *head) return list_entry(head, struct inode, i_io_list); } +static inline void inode_delete_from_io_list(struct inode *inode) +{ + if (!list_empty(&inode->i_io_list)) { + list_del_init(&inode->i_io_list); + iobj_put(inode); + } +} + /* * Include the creation of the trace points after defining the * wb_writeback_work structure and inline functions so that the definition
@@ -123,6 +131,8 @@ static bool inode_io_list_move_locked(struct inode *inode, assert_spin_locked(&inode->i_lock); WARN_ON_ONCE(inode->i_state & I_FREEING); + if (list_empty(&inode->i_io_list)) + iobj_get(inode); list_move(&inode->i_io_list, head); /* dirty_time doesn't count as dirty_io until expiration */
@@ -310,7 +320,7 @@ static void inode_cgwb_move_to_attached(struct inode *inode, if (wb != &wb->bdi->wb) list_move(&inode->i_io_list, &wb->b_attached); else - list_del_init(&inode->i_io_list); + inode_delete_from_io_list(inode); wb_io_lists_depopulated(wb); }
@@ -1200,7 +1210,7 @@ static void inode_cgwb_move_to_attached(struct inode *inode, WARN_ON_ONCE(inode->i_state & I_FREEING); inode->i_state &= ~I_SYNC_QUEUED; - list_del_init(&inode->i_io_list); + inode_delete_from_io_list(inode); wb_io_lists_depopulated(wb); }
@@ -1308,16 +1318,23 @@ void wb_start_background_writeback(struct bdi_writeback *wb) void inode_io_list_del(struct inode *inode) { struct bdi_writeback *wb; + bool drop = false; wb = inode_to_wb_and_lock_list(inode); spin_lock(&inode->i_lock); inode->i_state &= ~I_SYNC_QUEUED; - list_del_init(&inode->i_io_list); + if (!list_empty(&inode->i_io_list)) { + drop = true; + list_del_init(&inode->i_io_list); + } wb_io_lists_depopulated(wb); spin_unlock(&inode->i_lock); spin_unlock(&wb->list_lock); + + if (drop) + iobj_put(inode); } EXPORT_SYMBOL(inode_io_list_del);
@@ -1389,7 +1406,7 @@ static void redirty_tail_locked(struct inode *inode, struct bdi_writeback *wb) * trigger assertions in inode_io_list_move_locked(). */ if (inode->i_state & I_FREEING) { - list_del_init(&inode->i_io_list); + inode_delete_from_io_list(inode); wb_io_lists_depopulated(wb); return; }
--
2.49.0