Commit:     72ed3d035855841ad611ee48b20909e9619d4a79
Parent:     c742b53114f8d1535608dafb6a5690103a0748b5
Author:     Nick Piggin <[EMAIL PROTECTED]>
AuthorDate: Sat Feb 10 01:46:22 2007 -0800
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Sun Feb 11 11:15:24 2007 -0800

    [PATCH] buffer: memorder fix
    unlock_buffer(), like unlock_page(), must not clear the lock without
    ensuring that the critical section is closed.
    Mingming later sent the same patch, saying:
      We are running SDET benchmark and saw double free issue for ext3 extended
      attributes block, which complains the same xattr block already being 
freed (in
      ext3_xattr_release_block()).  The problem could also been triggered by
      multiple threads loop untar/rm a kernel tree.
      The race is caused by missing a memory barrier at unlock_buffer() before 
      lock bit being cleared, resulting in possible concurrent h_refcounter 
      That causes a reference counter leak, then later leads to the double free 
      we have seen.
      Inside unlock_buffer(), there is a memory barrier is placed *after* the 
      bit is being cleared, however, there is no memory barrier *before* the 
bit is
      cleared.  On some arch the h_refcount update instruction and the clear bit
      instruction could be reordered, thus leave the critical section 
      The race is like this: For example, if the h_refcount is initialized as 1,
      cpu 0:                                   cpu1
      lock_buffer() /* test_and_set_bit */
                                              lock_buffer() /* test_and_set_bit 
      h_refcount = h_refcount+1; /* = 2*/     h_refcount = h_refcount + 1; /*= 
2 */
      ....                                    ......
      We lost a h_refcount here. We need a memory barrier before the buffer 
head lock
      bit being cleared to force the order of the two writes.  Please apply.
    Signed-off-by: Nick Piggin <[EMAIL PROTECTED]>
    Signed-off-by: Mingming Cao <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
 fs/buffer.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/fs/buffer.c b/fs/buffer.c
index 763c5b5..7ff6e93 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -78,6 +78,7 @@ EXPORT_SYMBOL(__lock_buffer);
 void fastcall unlock_buffer(struct buffer_head *bh)
+       smp_mb__before_clear_bit();
        wake_up_bit(&bh->b_state, BH_Lock);
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