• Nick Piggin's avatar
    [PATCH] __block_write_full_page race fix · ad576e63
    Nick Piggin authored
    When running
    	fsstress -v -d $DIR/tmp -n 1000 -p 1000 -l 2
    on an ext2 filesystem with 1024 byte block size, on SMP i386 with 4096 byte
    page size over loopback to an image file on a tmpfs filesystem, I would
    very quickly hit
    	BUG_ON(!buffer_async_write(bh));
    in fs/buffer.c:end_buffer_async_write
    
    It seems that more than one request would be submitted for a given bh
    at a time.
    
    What would happen is the following:
    2 threads doing __mpage_writepages on the same page.
    Thread 1 - lock the page first, and enter __block_write_full_page.
    Thread 1 - (eg.) mark_buffer_async_write on the first 2 buffers.
    Thread 1 - set page writeback, unlock page.
    Thread 2 - lock page, wait on page writeback
    Thread 1 - submit_bh on the first 2 buffers.
    => both requests complete, none of the page buffers are async_write,
       end_page_writeback is called.
    Thread 2 - wakes up. enters __block_write_full_page.
    Thread 2 - mark_buffer_async_write on (eg.) the last buffer
    Thread 1 - finds the last buffer has async_write set, submit_bh on that.
    Thread 2 - submit_bh on the last buffer.
    => oops.
    
    So change __block_write_full_page to explicitly keep track of the last bh
    we need to issue, so we don't touch anything after issuing the last
    request.
    Signed-off-by: default avatarNick Piggin <nickpiggin@yahoo.com.au>
    Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
    ad576e63
buffer.c 82 KB