1
0
Files
linux/fs
Nick Piggin 72ed3d0358 [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 <npiggin@suse.de>
Signed-off-by: Mingming Cao <cmm@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-02-11 11:15:24 -08:00
..
2007-01-05 23:55:22 -08:00
2007-02-06 20:43:30 +00:00
2007-02-11 10:51:34 -08:00
2006-12-08 08:28:45 -08:00
2007-01-30 08:26:44 -08:00
2006-12-08 08:28:45 -08:00
2006-12-08 08:28:45 -08:00
2007-01-26 10:14:36 -06:00
2006-12-08 08:28:47 -08:00
2006-11-16 11:43:38 -08:00
2007-02-11 10:51:31 -08:00
2006-12-08 08:28:48 -08:00
2006-12-08 08:28:49 -08:00
2006-12-08 08:28:50 -08:00
2006-11-16 11:43:38 -08:00
2006-10-04 06:51:26 -06:00
2007-02-11 11:15:24 -08:00
2006-12-07 08:39:25 -08:00
2006-12-07 08:39:25 -08:00
2006-10-01 00:39:19 -07:00
2006-12-13 09:05:47 -08:00
2006-12-22 08:55:48 -08:00