On 05/30/2016 03:33 AM, Minchan Kim wrote: >> >> >>> + page->mapping = (void *)((unsigned long)page->mapping & >>> + PAGE_MAPPING_MOVABLE); >> >> This should be negated to clear... use ~PAGE_MAPPING_MOVABLE ? > > No. > > The intention is to clear only mapping value but PAGE_MAPPING_MOVABLE > flag. So, any new migration trial will be failed because PageMovable > checks page's mapping value but ongoing migraion handling can catch > whether it's movable page or not with the type bit.
Oh, OK, I got that wrong. I'll point out in the reply to the v6v2 what misled me :) >> >> So this effectively prevents movable compound pages from being >> migrated. Are you sure no users of this functionality are going to >> have compound pages? I assumed that they could, and so made the code >> like this, with the is_lru variable (which is redundant after your >> change). > > This implementation at the moment disables effectively non-lru compound > page migration but I'm not a god so I can't make sure no one doesn't want > it in future. If someone want it, we can support it then because this work > doesn't prevent it by design. Oh well. As long as the balloon pages or zsmalloc don't already use compound pages... > > I thouht PageCompound check right before isolate_movable_page in > isolate_migratepages_block will filter it out mostly but yeah > it is racy without zone->lru_lock so it could reach to isolate_movable_page. > However, PageMovable check in there investigates mapping, mapping->a_ops, > and a_ops->isolate_page to verify whether it's movable page or not. > > I thought it's sufficient to filter THP page. I guess, yeah. >> >> [...] >> >>> @@ -755,33 +844,69 @@ static int move_to_new_page(struct page *newpage, >>> struct page *page, >>> enum migrate_mode mode) >>> { >>> struct address_space *mapping; >>> - int rc; >>> + int rc = -EAGAIN; >>> + bool is_lru = !__PageMovable(page); >>> >>> VM_BUG_ON_PAGE(!PageLocked(page), page); >>> VM_BUG_ON_PAGE(!PageLocked(newpage), newpage); >>> >>> mapping = page_mapping(page); >>> - if (!mapping) >>> - rc = migrate_page(mapping, newpage, page, mode); >>> - else if (mapping->a_ops->migratepage) >>> - /* >>> - * Most pages have a mapping and most filesystems provide a >>> - * migratepage callback. Anonymous pages are part of swap >>> - * space which also has its own migratepage callback. This >>> - * is the most common path for page migration. >>> - */ >>> - rc = mapping->a_ops->migratepage(mapping, newpage, page, mode); >>> - else >>> - rc = fallback_migrate_page(mapping, newpage, page, mode); >>> + /* >>> + * In case of non-lru page, it could be released after >>> + * isolation step. In that case, we shouldn't try >>> + * fallback migration which is designed for LRU pages. >>> + */ >> >> Hmm but is_lru was determined from !__PageMovable() above, also well >> after the isolation step. So if the driver already released it, we >> wouldn't detect it? And this function is all under same page lock, >> so if __PageMovable was true above, so will be PageMovable below? > > You are missing what I mentioned above. > We should keep the type bit to catch what you are saying(i.e., driver > already released). > > __PageMovable just checks PAGE_MAPPING_MOVABLE flag and PageMovable > checks page->mapping valid while __ClearPageMovable reset only > valid vaule of mapping, not PAGE_MAPPING_MOVABLE flag. > > I wrote it down in Documentation/vm/page_migration. > > "For testing of non-lru movable page, VM supports __PageMovable function. > However, it doesn't guarantee to identify non-lru movable page because > page->mapping field is unified with other variables in struct page. > As well, if driver releases the page after isolation by VM, page->mapping > doesn't have stable value although it has PAGE_MAPPING_MOVABLE > (Look at __ClearPageMovable). But __PageMovable is cheap to catch whether > page is LRU or non-lru movable once the page has been isolated. Because > LRU pages never can have PAGE_MAPPING_MOVABLE in page->mapping. It is also > good for just peeking to test non-lru movable pages before more expensive > checking with lock_page in pfn scanning to select victim. > > For guaranteeing non-lru movable page, VM provides PageMovable function. > Unlike __PageMovable, PageMovable functions validates page->mapping and > mapping->a_ops->isolate_page under lock_page. The lock_page prevents sudden > destroying of page->mapping. > > Driver using __SetPageMovable should clear the flag via __ClearMovablePage > under page_lock before the releasing the page." Right, I get it now. >>> + if (!((unsigned long)page->mapping & PAGE_MAPPING_FLAGS)) >>> page->mapping = NULL; >> >> The two lines above make little sense to me without a comment. > > I folded this. > > @@ -901,7 +901,12 @@ static int move_to_new_page(struct page *newpage, struct > page *page, > __ClearPageIsolated(page); > } > > - if (!((unsigned long)page->mapping & PAGE_MAPPING_FLAGS)) > + /* > + * Anonymous and movable page->mapping will be cleard by > + * free_pages_prepare so don't reset it here for keeping > + * the type to work PageAnon, for example. > + */ > + if (!PageMappingFlags(page)) > page->mapping = NULL; > } Thanks.