> > But that leaves me with one more worry: compaction. We locked out > charge moving now, so between that and knowing that the page is alive, > we have page->mem_cgroup stable. But compaction doesn't know whether > the page is alive - it comes from a pfn and finds out using PageLRU. > > In the current code, pgdat->lru_lock remains the same before and after > the page is charged to a cgroup, so once compaction has that locked > and it observes PageLRU, it can go ahead and isolate the page. > > But lruvec->lru_lock changes during charging, and then compaction may > hold the wrong lock during isolation: > > compaction: generic_file_buffered_read: > > page_cache_alloc() > > !PageBuddy() > > lock_page_lruvec(page) > lruvec = mem_cgroup_page_lruvec() > spin_lock(&lruvec->lru_lock) > if lruvec != mem_cgroup_page_lruvec() > goto again > > add_to_page_cache_lru() > mem_cgroup_commit_charge() > page->mem_cgroup = foo > lru_cache_add() > __pagevec_lru_add() > SetPageLRU() > > if PageLRU(page): > __isolate_lru_page() > > I don't see what prevents the lruvec from changing under compaction, > neither in your patches nor in Hugh's. Maybe I'm missing something? > Hi Johannes, It looks my patch do the lruvec recheck/relock after PageLRU in compaction.c. It should be fine for your question. So I will try more testing after all changes. Thanks Alex @@ -949,10 +959,26 @@ static bool too_many_isolated(pg_data_t *pgdat) if (!(cc->gfp_mask & __GFP_FS) && page_mapping(page)) goto isolate_fail; + rcu_read_lock(); +reget_lruvec: + lruvec = mem_cgroup_page_lruvec(page, pgdat); + /* If we already hold the lock, we can skip some rechecking */ - if (!locked) { - locked = compact_lock_irqsave(&pgdat->lru_lock, - &flags, cc); + if (lruvec != locked_lruvec) { + if (locked_lruvec) { + spin_unlock_irqrestore(&locked_lruvec->lru_lock, + flags); + locked_lruvec = NULL; + } + if (compact_lock_irqsave(&lruvec->lru_lock, + &flags, cc)) + locked_lruvec = lruvec; + + + if (lruvec != mem_cgroup_page_lruvec(page, pgdat)) + goto reget_lruvec; + + rcu_read_unlock(); /* Try get exclusive access under lock */ if (!skip_updated) { @@ -974,9 +1000,9 @@ static bool too_many_isolated(pg_data_t *pgdat) low_pfn += compound_nr(page) - 1; goto isolate_fail; } - } + } else + rcu_read_unlock(); - lruvec = mem_cgroup_page_lruvec(page, pgdat); /* Try isolate the page */ if (__isolate_lru_page(page, isolate_mode) != 0) @@ -1017,9 +1043,10 @@ static bool too_many_isolated(pg_data_t *pgdat) * page anyway. */ if (nr_isolated) { - if (locked) { - spin_unlock_irqrestore(&pgdat->lru_lock, flags); - locked = false; + if (locked_lruvec) { + spin_unlock_irqrestore(&locked_lruvec->lru_lock, + flags); + locked_lruvec = NULL; } putback_movable_pages(&cc->migratepages);