Re: [patch 13/13] mm: memcontrol: rewrite uncharge API

From: Johannes Weiner
Date: Fri Jul 18 2014 - 10:46:14 EST


Hi Michal,

[cc'ing Miklos for fuse's use of replace_page_cache()]

On Fri, Jul 18, 2014 at 09:12:46AM +0200, Michal Hocko wrote:
> On Tue 15-07-14 14:19:35, Michal Hocko wrote:
> > [...]
> > > +/**
> > > + * mem_cgroup_migrate - migrate a charge to another page
> > > + * @oldpage: currently charged page
> > > + * @newpage: page to transfer the charge to
> > > + * @lrucare: page might be on LRU already
> >
> > which one? I guess the newpage?
> >
> > > + *
> > > + * Migrate the charge from @oldpage to @newpage.
> > > + *
> > > + * Both pages must be locked, @newpage->mapping must be set up.
> > > + */
> > > +void mem_cgroup_migrate(struct page *oldpage, struct page *newpage,
> > > + bool lrucare)
> > > +{
> > > + unsigned int nr_pages = 1;
> > > + struct page_cgroup *pc;
> > > +
> > > + VM_BUG_ON_PAGE(!PageLocked(oldpage), oldpage);
> > > + VM_BUG_ON_PAGE(!PageLocked(newpage), newpage);
> > > + VM_BUG_ON_PAGE(PageLRU(oldpage), oldpage);
> > > + VM_BUG_ON_PAGE(PageLRU(newpage), newpage);
> >
> > VM_BUG_ON_PAGE(PageLRU(newpage) && !lruvec, newpage);
>
> I guess everything except these two notes got addressed.

Sorry, they fell through the cracks.

Yes, @newpage can already be on the LRU, and it's what @lrucare is
for. However, you got me thinking about the source page, and so I
went back to replace_page_cache(); and fuse code, which is the only
user of it.

I assumed the source page would always be new, according to this part
in fuse_try_move_page():

/*
* This is a new and locked page, it shouldn't be mapped or
* have any special flags on it
*/
if (WARN_ON(page_mapped(oldpage)))
goto out_fallback_unlock;
if (WARN_ON(page_has_private(oldpage)))
goto out_fallback_unlock;
if (WARN_ON(PageDirty(oldpage) || PageWriteback(oldpage)))
goto out_fallback_unlock;
if (WARN_ON(PageMlocked(oldpage)))
goto out_fallback_unlock;

However, it's in the page cache and I can't really convince myself
that it's not also on the LRU. Miklos, I have trouble pinpointing
where oldpage is instantiated exactly and what state it might be in -
can it already be on the LRU?

If it can, we need to make sure we don't change pc->mem_cgroup while
mem_cgroup_migrate() is looking at it:

---