diff mbox series

writeback: Add asserts for adding freed inode to lists

Message ID 20221124141806.6194-1-jack@suse.cz (mailing list archive)
State New, archived
Headers show
Series writeback: Add asserts for adding freed inode to lists | expand

Commit Message

Jan Kara Nov. 24, 2022, 2:18 p.m. UTC
In the past we had several use-after-free issues with inodes getting
added to writeback lists after evict() removed them. These are painful
to debug so add some asserts to catch the problem earlier.

CC: Svyatoslav Feldsherov <feldsherov@google.com>
Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/fs-writeback.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

As we discussed with Svyatoslav who was debugging latest incarnation of this
use-after-free issue, let's add some safety WARN_ONs. Jens, would you take
care of merging this please?

Comments

Jens Axboe Nov. 24, 2022, 2:22 p.m. UTC | #1
On Thu, 24 Nov 2022 15:18:06 +0100, Jan Kara wrote:
> In the past we had several use-after-free issues with inodes getting
> added to writeback lists after evict() removed them. These are painful
> to debug so add some asserts to catch the problem earlier.
> 
> 

Applied, thanks!

[1/1] writeback: Add asserts for adding freed inode to lists
      commit: d6798bc243fabfcb86c1d39168f1619304d2b9f9

Best regards,
diff mbox series

Patch

diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 443f83382b9b..49f045f2e458 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -121,6 +121,7 @@  static bool inode_io_list_move_locked(struct inode *inode,
 {
 	assert_spin_locked(&wb->list_lock);
 	assert_spin_locked(&inode->i_lock);
+	WARN_ON_ONCE(inode->i_state & I_FREEING);
 
 	list_move(&inode->i_io_list, head);
 
@@ -280,6 +281,7 @@  static void inode_cgwb_move_to_attached(struct inode *inode,
 {
 	assert_spin_locked(&wb->list_lock);
 	assert_spin_locked(&inode->i_lock);
+	WARN_ON_ONCE(inode->i_state & I_FREEING);
 
 	inode->i_state &= ~I_SYNC_QUEUED;
 	if (wb != &wb->bdi->wb)
@@ -1129,6 +1131,7 @@  static void inode_cgwb_move_to_attached(struct inode *inode,
 {
 	assert_spin_locked(&wb->list_lock);
 	assert_spin_locked(&inode->i_lock);
+	WARN_ON_ONCE(inode->i_state & I_FREEING);
 
 	inode->i_state &= ~I_SYNC_QUEUED;
 	list_del_init(&inode->i_io_list);
@@ -1294,6 +1297,12 @@  static void redirty_tail_locked(struct inode *inode, struct bdi_writeback *wb)
 {
 	assert_spin_locked(&inode->i_lock);
 
+	inode->i_state &= ~I_SYNC_QUEUED;
+	if (inode->i_state & I_FREEING) {
+		list_del_init(&inode->i_io_list);
+		wb_io_lists_depopulated(wb);
+		return;
+	}
 	if (!list_empty(&wb->b_dirty)) {
 		struct inode *tail;
 
@@ -1302,7 +1311,6 @@  static void redirty_tail_locked(struct inode *inode, struct bdi_writeback *wb)
 			inode->dirtied_when = jiffies;
 	}
 	inode_io_list_move_locked(inode, wb, &wb->b_dirty);
-	inode->i_state &= ~I_SYNC_QUEUED;
 }
 
 static void redirty_tail(struct inode *inode, struct bdi_writeback *wb)