--- 2.4.21pre4aa1/fs/inode.c.~1~ 2003-01-31 02:38:47.000000000 +0100 +++ 2.4.21pre4aa1/fs/inode.c 2003-02-03 17:48:25.000000000 +0100 @@ -199,6 +199,9 @@ void __mark_inode_dirty(struct inode *in sb->s_op->dirty_inode(inode); } + /* make sure that changes are seen by all cpus before we test i_state */ + smp_mb(); + /* avoid the locking if we can */ if ((inode->i_state & flags) == flags) return; @@ -273,6 +276,23 @@ static inline void __sync_one(struct ino inode->i_state &= ~I_DIRTY; spin_unlock(&inode_lock); + /* + * mark_inode_dirty() doesn't take spinlock, make sure + * that the data is not read speculatively by this cpu + * before &= ~I_DIRTY is flushed to ram. + * + * We depend on the inode->i_state &= ~I_DIRTY not passing + * the smp_rmb() because of the implicit one-way memory + * barrier of the spinlock that avoids the critical section + * to pass the spin_unlock(). Shall this dependency break + * (i.e. if the spin_unlock goes away), this has to be + * converted to a smp_mb() (note: if I_DIRTY would + * become a bitop, a test_and_set_bit just has to provide + * implicity smp_mb() semantics for the non contention + * branch). + */ + smp_rmb(); + filemap_fdatasync(inode->i_mapping); /* Don't write the inode if only I_DIRTY_PAGES was set */