On Wed, May 26, 2021 at 1:46 AM Roman Gushchin <guro@xxxxxx> wrote: > > 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 didn't think of using an array before. The first idea that popped out was a list. But you remind me of the array. I'd love to replace it with the array. Thanks, Roman. > I guess it's a more canonical way of solving problems like this. > The proposed API looks good to me.