address_spaces have a `dirtied_when' jiffies field which records the time at which the mapping was first dirtied. This is used for the periodic writeback (kupdate) function. It is also used to prevent livelocks in the writeback code: don't try to write back objects which were dirtied after sync_sb_inodes() was called. It used to be the case that dirtied_when == 0 had magical properties, so there is code in there which avoids accidentally setting dirtied_when to zero at jiffy wrap time. We just set it to jiffies|1. Unfortunately, jiffies|1 is in the future. So under some rare timing circumstances (inode dirtied within one jiffy of umount) the livelock avoidance code in sync_sb_inodes() can accidentally trigger and we fail to write an inode out, resulting in filesytem corruption on ext2-style filesystems. Normally, nobody dirties a file within a millisecond of umount, so it was not noticed. It is no longer the case that address_space.dirtied_when has special meaning, so we can just remove all that code and fix the bug. --- fs/fs-writeback.c | 10 ++++------ 1 files changed, 4 insertions(+), 6 deletions(-) diff -puN fs/fs-writeback.c~umount-dataloss-fix fs/fs-writeback.c --- 25/fs/fs-writeback.c~umount-dataloss-fix 2004-02-26 02:16:17.000000000 -0800 +++ 25-akpm/fs/fs-writeback.c 2004-02-26 02:18:00.000000000 -0800 @@ -99,7 +99,7 @@ void __mark_inode_dirty(struct inode *in * reposition it (that would break s_dirty time-ordering). */ if (!was_dirty) { - mapping->dirtied_when = jiffies|1; /* 0 is special */ + mapping->dirtied_when = jiffies; list_move(&inode->i_list, &sb->s_dirty); } } @@ -176,17 +176,15 @@ __sync_single_inode(struct inode *inode, } else if (!list_empty(&mapping->dirty_pages)) { /* Redirtied */ inode->i_state |= I_DIRTY_PAGES; - mapping->dirtied_when = jiffies|1; + mapping->dirtied_when = jiffies; list_move(&inode->i_list, &sb->s_dirty); } else if (inode->i_state & I_DIRTY) { /* Redirtied */ - mapping->dirtied_when = jiffies|1; + mapping->dirtied_when = jiffies; list_move(&inode->i_list, &sb->s_dirty); } else if (atomic_read(&inode->i_count)) { - mapping->dirtied_when = 0; list_move(&inode->i_list, &inode_in_use); } else { - mapping->dirtied_when = 0; list_move(&inode->i_list, &inode_unused); } } @@ -310,7 +308,7 @@ sync_sb_inodes(struct super_block *sb, s __iget(inode); __writeback_single_inode(inode, wbc); if (wbc->sync_mode == WB_SYNC_HOLD) { - mapping->dirtied_when = jiffies|1; + mapping->dirtied_when = jiffies; list_move(&inode->i_list, &sb->s_dirty); } if (current_is_pdflush()) _