Comment 11 for bug 1086680

Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote :

I have a theory based on instrumented runs.

We need two threads, one at buf_page_get_gen and another at
buf_flush_flush_list_batch, trying to work on the same dirty
compressed (i.e. state = BUF_BLOCK_ZIP_DIRTY) page.

1) buf_flush_flush_list_batch acquires flush_list_mutex, gets a
   page from the flush list, releases flush_list_mutex.
2) buf_page_get_gen attempts to read the same page, acquires
   zip_mutex, gets the dirty compressed page descriptor, allocates
   an uncompressed page, and replaces the descriptor with the page in
   the flush_list by a buf_flush_relocate_on_flush_list() call. That
   call acquires flush_list_mutex, sets in_flush_list = FALSE; but
   leaves oldest_modification alone, releases the flush_list_mutex.
   Caller then invalidates the descriptor memory, releases zip_mutex,
   frees its memory.
3) buf_flush_flush_list_batch attempts to read from the deallocated
   compressed page descriptor. Assuming that the memory was not
   overwritten since deallocation, the code reads oldest_modification
   != 0 and then trips on !in_flush_list.