[Yaffs] [PATCH] yaffs: fix spinning when flush inodes

Top Page
Attachments:
Message as email
+ (text/plain)
Delete this message
Reply to this message
Author: Stefan Agner
Date:  
To: yaffs
Subject: [Yaffs] [PATCH] yaffs: fix spinning when flush inodes
While in list_for_each_entry() of yaffs_flush_inodes, the fs code
can delete inodes. This leads to an endless loop which causes a
softlockup. Typically this happend in sync_supers when creating
and deleting files while under CPU load.

This fix checks whether we get twice the same inode. If this is
true, we just retry again.

This is an alternative fix to the proposed fix Jisheng Zhang:
yaffs: fix softlockup cauesed by inode deleted when scanning s_inodes list
http://www.aleph1.co.uk/lurker/message/20110831.075307.3cfeacdf.fr.html
---
Hi,

I sent this email already some weeks ago, however it did not make it
through to the list. Hence this resend.

I can see Jisheng's issue (see link above) on a Tegra 2 device (Colibri
T20) using 3.1 L4T (Linux for Tegra) Kernel. The devices which show the
error had multiple YAFFS2 partitions. I could successfully reproduce the
issue by using bonnie++ on two independent partitions formatted YAFFS2.
After some hours (3-5) the sync_supers kernel thread starts to loop in
the list_for_each_entry of the yaffs_flush_inodes function.

I also set the dirty_writeback_centiseconds to 1, but I'm not sure if
this really forces the error to happen more often.
echo 1 > /proc/sys/vm/dirty_writeback_centisecs

However, JiSheng's patch leads to different errors on my setup, e.g.
kernel BUG at ../fs/inode.c:1359!
kernel BUG at ../fs/inode.c:431!

This is a rather ugly fix which just works around the actual symptoms,
but it solved the problem for me so far.

--
Stefan

fs/yaffs2/yaffs_vfs.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/fs/yaffs2/yaffs_vfs.c b/fs/yaffs2/yaffs_vfs.c
index 6d4136d..16502e6 100644
--- a/fs/yaffs2/yaffs_vfs.c
+++ b/fs/yaffs2/yaffs_vfs.c
@@ -1520,9 +1520,11 @@ static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)

 static void yaffs_flush_inodes(struct super_block *sb)
 {
-    struct inode *iptr;
+    struct inode *iptr, *iptr_tmp;
     struct yaffs_obj *obj;


+retry:
+    iptr_tmp = NULL;
     list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) {
         obj = yaffs_inode_to_obj(iptr);
         if (obj) {
@@ -1530,6 +1532,18 @@ static void yaffs_flush_inodes(struct super_block *sb)
                 "flushing obj %d", obj->obj_id);
             yaffs_flush_file(obj, 1, 0);
         }
+
+        /*
+         * HACK: if we get the same iptr twice, someone removed (?)
+         * this inode while we are iterating. Start over again
+         */
+        if (iptr_tmp == iptr) {
+            printk(KERN_ERR "yaffs: Got twice the same inode %p\n",
+                   iptr);
+            goto retry;
+        }
+
+        iptr_tmp = iptr;
     }
 }


--
2.1.2