Commit 54710f60 authored by Nick Piggin's avatar Nick Piggin Committed by Greg Kroah-Hartman

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
parent 5556eaff
...@@ -78,6 +78,7 @@ EXPORT_SYMBOL(__lock_buffer); ...@@ -78,6 +78,7 @@ EXPORT_SYMBOL(__lock_buffer);
void fastcall unlock_buffer(struct buffer_head *bh) void fastcall unlock_buffer(struct buffer_head *bh)
{ {
smp_mb__before_clear_bit();
clear_buffer_locked(bh); clear_buffer_locked(bh);
smp_mb__after_clear_bit(); smp_mb__after_clear_bit();
wake_up_bit(&bh->b_state, BH_Lock); wake_up_bit(&bh->b_state, BH_Lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment