On Tue, Nov 27, 2012 at 03:52:01PM -0800, Andrew Morton wrote: > On Tue, 27 Nov 2012 21:31:10 -0200 > Rafael Aquini <aquini@xxxxxxxxxx> wrote: > > > This patch fixes the following crash by fixing and enhancing the way > > page->flags are tested to identify a ballooned page. > > > > ---8<--- > > BUG: unable to handle kernel NULL pointer dereference at 0000000000000194 > > IP: [<ffffffff8122b354>] isolate_migratepages_range+0x344/0x7b0 > > --->8--- > > > > The NULL pointer deref was taking place because balloon_page_movable() > > page->flags tests were incomplete and we ended up > > inadvertently poking at private pages. > > > > .... > > > > /* > > + * __balloon_page_flags - helper to perform balloon @page ->flags tests. > > + * > > + * As balloon pages are got from Buddy, and we do not play with page->flags > > + * at driver level (exception made when we get the page lock for compaction), > > + * therefore we can safely identify a ballooned page by checking if the > > + * NR_PAGEFLAGS rightmost bits from the page->flags are all cleared. > > + * This approach also helps on skipping ballooned pages that are locked for > > + * compaction or release, thus mitigating their racy check at > > + * balloon_page_movable() > > + */ > > +#define BALLOON_PAGE_FLAGS_MASK ((1UL << NR_PAGEFLAGS) - 1) > > hm, this seems a bit fragile. > > What's actually going on here? You're assuming that a page fresh from > buddy has all flags 0..NR_PAGEFLAGS cleared? > Yes, thats the idea, as when we get pages from freelists, they are all checked by prep_new_page()->check_new_page() before buffered_rmqueue() returns them. By the path we use to get balloon pages, if the page has any of 0..NR_PAGEFLAGS flags set at the alloc time it's regarded as bad_page by check_new_page(), and we go after another victim. > That may be true, I'm unsure. Please take a look at > PAGE_FLAGS_CHECK_AT_FREE and PAGE_FLAGS_CHECK_AT_PREP and work out why > the heck these aren't the same thing! Humm, I can't think of why, either... As I've followed the prep path, I didn't notice that difference. I'll look at it closer, though. > > Either way around, doing > > #define BALLOON_PAGE_FLAGS_MASK PAGE_FLAGS_CHECK_AT_PREP > > seems rather more maintainable. As usual, your suggestion is far way better than my orinal proposal :) > > > +static inline bool __balloon_page_flags(struct page *page) > > +{ > > + return page->flags & BALLOON_PAGE_FLAGS_MASK ? false : true; > > We have a neater way of doing the scalar-to-boolean conversion: > > return !(page->flags & BALLOON_PAGE_FLAGS_MASK); > ditto! :) Do you want me to resubmit this patch with the changes you suggested? Cheers! Rafael > > +} > > + > > +/* > > * __is_movable_balloon_page - helper to perform @page mapping->flags tests > > */ > > static inline bool __is_movable_balloon_page(struct page *page) > > @@ -135,8 +152,8 @@ static inline bool balloon_page_movable(struct page *page) > > * Before dereferencing and testing mapping->flags, lets make sure > > * this is not a page that uses ->mapping in a different way > > */ > > - if (!PageSlab(page) && !PageSwapCache(page) && !PageAnon(page) && > > - !page_mapped(page)) > > + if (__balloon_page_flags(page) && !page_mapped(page) && > > + page_count(page) == 1) > > return __is_movable_balloon_page(page); > > > > return false; > > > > ... > > -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxx. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@xxxxxxxxx"> email@xxxxxxxxx </a>