diff options
| author | Andrew Morton <akpm@digeo.com> | 2003-02-02 06:06:29 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2003-02-02 06:06:29 -0800 |
| commit | 5f44f4a9ee66ba0232ee55fc7456b24aeb448149 (patch) | |
| tree | 0a9f18b230240fe7d3c073c37a5f058e5930642a | |
| parent | 6a3354a951d40d2f8e98317626eb3f88a4952818 (diff) | |
[PATCH] Fix data loss problem due to sys_sync
In 2.5.52 I broke sys_sync() for ext2 in subtle ways.
sys_sync() will set mapping->dirtied_when non-zero against a clean inode.
Later, in (say) __iget(), that inode gets moved over to inode_unused or
inode_in_use. But because it has non-zero ->dirtied_when,
__mark_inode_dirty() thinks that the inode must still be on sb->s_dirty.
But it isn't. It's on inode_in_use. It (and its pages) never get written
out and the data gets thrown away on unmount.
The patch ceases to use ->dirtied_when as an indicator of inode dirtiness.
Not sure why I even did that :(
| -rw-r--r-- | fs/fs-writeback.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index bd1f2ded1449..a7eda58424bf 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -67,6 +67,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) spin_lock(&inode_lock); if ((inode->i_state & flags) != flags) { + const int was_dirty = inode->i_state & I_DIRTY; struct address_space *mapping = inode->i_mapping; inode->i_state |= flags; @@ -90,7 +91,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) * If the inode was already on s_dirty or s_io, don't * reposition it (that would break s_dirty time-ordering). */ - if (!mapping->dirtied_when) { + if (!was_dirty) { mapping->dirtied_when = jiffies|1; /* 0 is special */ list_move(&inode->i_list, &sb->s_dirty); } @@ -280,7 +281,7 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc) __iget(inode); __writeback_single_inode(inode, really_sync, wbc); if (wbc->sync_mode == WB_SYNC_HOLD) { - mapping->dirtied_when = jiffies; + mapping->dirtied_when = jiffies|1; list_move(&inode->i_list, &sb->s_dirty); } if (current_is_pdflush()) |
