diff mbox series

[11/11] fs: fix potential soft lockup when 'sb->s_inodes' has large number of inodes

Message ID 20241118114508.1405494-12-yebin@huaweicloud.com (mailing list archive)
State New
Headers show
Series fix hungtask due to repeated traversal of inodes list | expand

Commit Message

Ye Bin Nov. 18, 2024, 11:45 a.m. UTC
From: Ye Bin <yebin10@huawei.com>

If the memory is sufficient, a large number of inodes that do not
meet the conditions may exist in the 'sb->s_inodes' list when
evict_inodes()/invalidate_inodes() traverse the 'sb->s_inodes' list.
Then it maybe trigger soft lockup.
To solve potential soft lockup, move need_resched() check from tail
to head when traverse the 'sb->s_inodes' list.

Signed-off-by: Ye Bin <yebin10@huawei.com>
---
 fs/inode.c | 49 +++++++++++++++++++++++++------------------------
 1 file changed, 25 insertions(+), 24 deletions(-)
diff mbox series

Patch

diff --git a/fs/inode.c b/fs/inode.c
index b78895af8779..e865fc1f5a95 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -867,6 +867,21 @@  void evict_inodes(struct super_block *sb)
 again:
 	spin_lock(&sb->s_inode_list_lock);
 	sb_for_each_inodes_continue_safe(inode, next, &sb->s_inodes) {
+		/*
+		 * We can have a ton of inodes to evict at unmount time given
+		 * enough memory, check to see if we need to go to sleep for a
+		 * bit so we don't livelock.
+		 */
+		if (need_resched()) {
+			list_del(&cursor.i_sb_list);
+			list_add_tail(&cursor.i_sb_list, &inode->i_sb_list);
+			inode = &cursor;
+			spin_unlock(&sb->s_inode_list_lock);
+			cond_resched();
+			dispose_list(&dispose);
+			goto again;
+		}
+
 		if (atomic_read(&inode->i_count))
 			continue;
 
@@ -884,21 +899,6 @@  void evict_inodes(struct super_block *sb)
 		inode_lru_list_del(inode);
 		spin_unlock(&inode->i_lock);
 		list_add(&inode->i_lru, &dispose);
-
-		/*
-		 * We can have a ton of inodes to evict at unmount time given
-		 * enough memory, check to see if we need to go to sleep for a
-		 * bit so we don't livelock.
-		 */
-		if (need_resched()) {
-			list_del(&cursor.i_sb_list);
-			list_add(&cursor.i_sb_list, &inode->i_sb_list);
-			inode = &cursor;
-			spin_unlock(&sb->s_inode_list_lock);
-			cond_resched();
-			dispose_list(&dispose);
-			goto again;
-		}
 	}
 	list_del(&cursor.i_sb_list);
 	spin_unlock(&sb->s_inode_list_lock);
@@ -926,6 +926,16 @@  void invalidate_inodes(struct super_block *sb)
 again:
 	spin_lock(&sb->s_inode_list_lock);
 	sb_for_each_inodes_continue_safe(inode, next, &sb->s_inodes) {
+		if (need_resched()) {
+			list_del(&cursor.i_sb_list);
+			list_add_tail(&cursor.i_sb_list, &inode->i_sb_list);
+			inode = &cursor;
+			spin_unlock(&sb->s_inode_list_lock);
+			cond_resched();
+			dispose_list(&dispose);
+			goto again;
+		}
+
 		spin_lock(&inode->i_lock);
 		if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
 			spin_unlock(&inode->i_lock);
@@ -940,15 +950,6 @@  void invalidate_inodes(struct super_block *sb)
 		inode_lru_list_del(inode);
 		spin_unlock(&inode->i_lock);
 		list_add(&inode->i_lru, &dispose);
-		if (need_resched()) {
-			list_del(&cursor.i_sb_list);
-			list_add(&cursor.i_sb_list, &inode->i_sb_list);
-			inode = &cursor;
-			spin_unlock(&sb->s_inode_list_lock);
-			cond_resched();
-			dispose_list(&dispose);
-			goto again;
-		}
 	}
 	list_del(&cursor.i_sb_list);
 	spin_unlock(&sb->s_inode_list_lock);