Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=72ed3d035855841ad611ee48b20909e9619d4a79
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 
the
      lock bit being cleared, resulting in possible concurrent h_refcounter 
update.
      That causes a reference counter leak, then later leads to the double free 
that
      we have seen.
    
      Inside unlock_buffer(), there is a memory barrier is placed *after* the 
lock
      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 
re-entered.
    
      The race is like this: For example, if the h_refcount is initialized as 1,
    
      cpu 0:                                   cpu1
      --------------------------------------   
-----------------------------------
      lock_buffer() /* test_and_set_bit */
      clear_buffer_locked(bh);
                                              lock_buffer() /* test_and_set_bit 
*/
      h_refcount = h_refcount+1; /* = 2*/     h_refcount = h_refcount + 1; /*= 
2 */
                                              clear_buffer_locked(bh);
      ....                                    ......
    
      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();
        clear_buffer_locked(bh);
        smp_mb__after_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  http://vger.kernel.org/majordomo-info.html

Reply via email to