Another VM race? (was: page_launder() bug)

Mikulas Patocka
2001-05-13T21:03:08Z

> > > + if (!dead_swap_page &&
> > > + (PageTestandClearReferenced(page) || page->age > 0 ||
> > > + (!page->buffers && page_count(page) > 1) ||
> > > + page_ramdisk(page))) {
> > ^^^^^^^^^^^^^^^^^^^^^^
> > > del_page_from_inactive_dirty_list(page);
> > > add_page_to_active_list(page);
> > > continue;
> >
> > #define page_ramdisk(page) \
> > (page->buffers && (MAJOR(page->buffers->b_dev) == RAMDISK_MAJOR))
> >
> > Are you sure that no one will release buffers under your hands?
>
> Two things can happen:
>
> 1) the page gets ramdisk buffers _after_ we look at it first,
> in this case the page isn't freeable and will be moved to
> the active list on the next page_launder() loop
>
> 2) the page loses its ramdisk buffers after we look at it,
> now the page is freeable, but we won't see it again until
> it is moved from the active list to the inactive_dirty
> list again
>
> Any side effects harmful enough to warrant complicating this
> test ?

I mean this: Let's have a page with buffers. It does not care whether the
buffers are on ramdisk or not.

CPU 0 CPU 1
is executing the code marked is executing try_to_free_buffers on
above with ^^^^^^^: the same page (it can be, because CPU 0
did not lock the page)

(page->buffers &&

page->buffers = NULL

MAJOR(page->buffers->b_dev) ==
RAMDISK_MAJOR)) ===> Oops, NULL pointer dereference!

Maybe compiler CSE optimization will eliminate the double load of
page->buffers, but we must not rely on it. If the compiler doesn't
optimize it, it can produce random oopses.

Mikulas