summaryrefslogtreecommitdiff
path: root/fs/buffer.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-04-17 23:56:30 -0700
committerDavid S. Miller <davem@davemloft.net>2008-04-17 23:56:30 -0700
commit1e42198609d73ed1a9adcba2af275c24c2678420 (patch)
tree32fd4d9073bfc0f3909af8f9fb4bcff38951d01a /fs/buffer.c
parent794eb6bf20ebf992c040ea831cd3a9c64b0c1f7a (diff)
parent4b119e21d0c66c22e8ca03df05d9de623d0eb50f (diff)
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'fs/buffer.c')
-rw-r--r--fs/buffer.c15
1 files changed, 14 insertions, 1 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index 98196327ddf0..39ff14403d13 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1181,7 +1181,20 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)
void mark_buffer_dirty(struct buffer_head *bh)
{
WARN_ON_ONCE(!buffer_uptodate(bh));
- if (!buffer_dirty(bh) && !test_set_buffer_dirty(bh))
+
+ /*
+ * Very *carefully* optimize the it-is-already-dirty case.
+ *
+ * Don't let the final "is it dirty" escape to before we
+ * perhaps modified the buffer.
+ */
+ if (buffer_dirty(bh)) {
+ smp_mb();
+ if (buffer_dirty(bh))
+ return;
+ }
+
+ if (!test_set_buffer_dirty(bh))
__set_page_dirty(bh->b_page, page_mapping(bh->b_page), 0);
}