On Wed, Apr 21, 2021 at 03:00:55PM +0800, Muchun Song wrote: > In the previous patch, we know how to make the lruvec lock safe when the > LRU pages reparented. We should do something like following. > > memcg_reparent_objcgs(memcg) > 1) lock > // lruvec belongs to memcg and lruvec_parent belongs to parent memcg. > spin_lock(&lruvec->lru_lock); > spin_lock(&lruvec_parent->lru_lock); > > 2) do reparent > // Move all the pages from the lruvec list to the parent lruvec list. > > 3) unlock > spin_unlock(&lruvec_parent->lru_lock); > spin_unlock(&lruvec->lru_lock); > > Apart from the page lruvec lock, the deferred split queue lock (THP only) > also needs to do something similar. So we extracted the necessary 3 steps > in the memcg_reparent_objcgs(). > > memcg_reparent_objcgs(memcg) > 1) lock > memcg_reparent_ops->lock(memcg, parent); > > 2) reparent > memcg_reparent_ops->reparent(memcg, reparent); > > 3) unlock > memcg_reparent_ops->unlock(memcg, reparent); > > Now there are two different locks (e.g. lruvec lock and deferred split > queue lock) need to use this infrastructure. In the next patch, we will > use those APIs to make those locks safe when the LRU pages reparented. > > Signed-off-by: Muchun Song <songmuchun@xxxxxxxxxxxxx> > --- > include/linux/memcontrol.h | 11 +++++++++++ > mm/memcontrol.c | 49 ++++++++++++++++++++++++++++++++++++++++++++-- > 2 files changed, 58 insertions(+), 2 deletions(-) > > diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h > index 228263f2c82b..b12847b0be09 100644 > --- a/include/linux/memcontrol.h > +++ b/include/linux/memcontrol.h > @@ -355,6 +355,17 @@ struct mem_cgroup { > /* WARNING: nodeinfo must be the last member here */ > }; > > +struct memcg_reparent_ops { > + struct list_head list; > + > + /* Irq is disabled before calling those functions. */ > + void (*lock)(struct mem_cgroup *memcg, struct mem_cgroup *parent); > + void (*unlock)(struct mem_cgroup *memcg, struct mem_cgroup *parent); > + void (*reparent)(struct mem_cgroup *memcg, struct mem_cgroup *parent); > +}; > + > +void __init register_memcg_repatent(struct memcg_reparent_ops *ops); > + > /* > * size of first charge trial. "32" comes from vmscan.c's magic value. > * TODO: maybe necessary to use big numbers in big irons. > diff --git a/mm/memcontrol.c b/mm/memcontrol.c > index a48403e5999c..f88fe2f06f5b 100644 > --- a/mm/memcontrol.c > +++ b/mm/memcontrol.c > @@ -330,6 +330,41 @@ static struct obj_cgroup *obj_cgroup_alloc(void) > return objcg; > } > > +static LIST_HEAD(reparent_ops_head); Because this list is completely static, why not make a build-time initialized array instead? I guess it's a more canonical way of solving problems like this. The proposed API looks good to me.