Commit:     6610a0bc8dcc120daa1d93807d470d5cbf777c39
Parent:     2b0172e1c6e6aea0a4efcfaaab38d4a02046f45a
Author:     Andrew Morton <[EMAIL PROTECTED]>
AuthorDate: Tue Oct 16 23:30:32 2007 -0700
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Wed Oct 17 08:43:01 2007 -0700

    writeback: fix time-ordering of the per-superblock dirty-inode lists
    When writeback has finished writing back an inode it looks to see if that
    inode is still dirty.  If it is, that means that a process redirtied the 
    while its writeback was in progress.
    What we need to do here is to refile the redirtied inode onto the s_dirty
    But we're doing that wrongly: it could be that this inode was redirtied
    _before_ the last inode on s_dirty.  We're blindly appending this inode to 
    list, after an inode which might be less-recently-dirtied, thus violating 
    list's ordering.
    So we must either insertion-sort this inode into the correct place, or we 
    update this inode's dirtied_when field when appending it to the 
    s_dirty list, to preserve the reverse-time-ordering.
    This patch does the latter: if this inode was dirtied less recently than the
    tail inode then copy the tail inode's timestamp into this inode.
    This means that in rare circumstances, some inodes will be writen back later
    than they should have been.  But the time slip will be small.
    Cc: Mike Waychison <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
 fs/fs-writeback.c |   26 +++++++++++++++++++++++++-
 1 files changed, 25 insertions(+), 1 deletions(-)

diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 8d23b0b..08b9f83 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -141,6 +141,30 @@ static int write_inode(struct inode *inode, int sync)
+ * Redirty an inode: set its when-it-was dirtied timestamp and move it to the
+ * furthest end of its superblock's dirty-inode list.
+ *
+ * Before stamping the inode's ->dirtied_when, we check to see whether it is
+ * already the most-recently-dirtied inode on the s_dirty list.  If that is
+ * the case then the inode must have been redirtied while it was being written
+ * out and we don't reset its dirtied_when.
+ */
+static void redirty_tail(struct inode *inode)
+       struct super_block *sb = inode->i_sb;
+       if (!list_empty(&sb->s_dirty)) {
+               struct inode *tail_inode;
+               tail_inode = list_entry(sb->, struct inode, i_list);
+               if (!time_after_eq(inode->dirtied_when,
+                               tail_inode->dirtied_when))
+                       inode->dirtied_when = jiffies;
+       }
+       list_move(&inode->i_list, &sb->s_dirty);
  * Write a single inode's dirty pages and inode data out to disk.
  * If `wait' is set, wait on the writeout.
@@ -219,7 +243,7 @@ __sync_single_inode(struct inode *inode, struct 
writeback_control *wbc)
                         * Someone redirtied the inode while were writing back
                         * the pages.
-                       list_move(&inode->i_list, &sb->s_dirty);
+                       redirty_tail(inode);
                } else if (atomic_read(&inode->i_count)) {
                         * The inode is clean, inuse
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at

Reply via email to