]> git.hungrycats.org Git - linux/commitdiff
[PATCH] fix inode state incoherency
authorMiklos Szeredi <miklos@szeredi.hu>
Fri, 16 Jul 2004 11:44:49 +0000 (04:44 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Fri, 16 Jul 2004 11:44:49 +0000 (04:44 -0700)
This patch fixes a hard-to-trigger condition, where the inode is on the
inode_in_use list while it's state is dirty.  In this state dirty pages are
not written back in sync() or from kupdate, only from direct page reclaim.
And this causes a livelock in balance_dirty_pages after a while.

The actual sequence of events required to get into this state is:

thread   function                             inode state         inode list
----------------------------------------------------------------------------
1 __sync_single_inode (background)            I_DIRTY             sb->s_io
1 do_writepages ...                           I_LOCKED
2 __writeback_single_inode (sync) sleeps      I_LOCKED
1 __sync_single_inode (background) finish     0                   inode_in_use
2 __writeback_single_inode (sync) wakeup      0
2 __sync_single_inode (sync)                  0
2 do_writepages ...                           I_LOCKED
3 __mark_inode_dirty                          I_LOCKED | I_DIRTY
2 __sync_single_inode (sync) finish           I_DIRTY             left on
                                                                  inode_in_use

Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/fs-writeback.c

index 2aac26e9f1beee211c868ae4141e3d8ce66c6491..430afc37dec4ca946e8b4a7426dfcf744e63ffbb 100644 (file)
@@ -213,8 +213,9 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc)
                } else if (inode->i_state & I_DIRTY) {
                        /*
                         * Someone redirtied the inode while were writing back
-                        * the pages: nothing to do.
+                        * the pages.
                         */
+                       list_move(&inode->i_list, &sb->s_dirty);
                } else if (atomic_read(&inode->i_count)) {
                        /*
                         * The inode is clean, inuse