[PATCH v2 22/28] memcg, list_lru: duplicate LRUs upon kmemcg creation
Glauber Costa
glommer at parallels.com
Mon Apr 1 08:22:38 UTC 2013
Hi Kame,
>>
>> +/*
>> + * This is supposed to be M x N matrix, where M is kmem-limited memcg,
>> + * and N is the number of nodes.
>> + */
>
> Could you add a comment that M can be changed and the array can be resized.
Yes, I can.
>
>> +struct list_lru_array {
>> + struct list_lru_node node[1];
>> +};
>> +
>> struct list_lru {
>> struct list_lru_node node[MAX_NUMNODES];
>> nodemask_t active_nodes;
>> +#ifdef CONFIG_MEMCG_KMEM
>> + struct list_head lrus;
>> + struct list_lru_array **memcg_lrus;
>> +#endif
>
> please add comments, for what ....
>
ok.
>> +struct list_lru_array *lru_alloc_array(void)
>> +{
>> + struct list_lru_array *lru_array;
>> int i;
>>
>> - nodes_clear(lru->active_nodes);
>> - for (i = 0; i < MAX_NUMNODES; i++) {
>> - spin_lock_init(&lru->node[i].lock);
>> - INIT_LIST_HEAD(&lru->node[i].list);
>> - lru->node[i].nr_items = 0;
>> + lru_array = kzalloc(nr_node_ids * sizeof(struct list_lru_node),
>> + GFP_KERNEL);
>
> A nitpick...you can use kmalloc() here. All field will be overwritten.
It is, however, not future-proof if anyone wants to add more fields, and
forget to zero out the structure. If you really feel strongly for
kmalloc I can change. But I don't see this as a big issue, specially
this not being a fast path.
>> +#ifdef CONFIG_MEMCG_KMEM
>> +int __memcg_init_lru(struct list_lru *lru)
>> +{
>> + int ret;
>> +
>> + INIT_LIST_HEAD(&lru->lrus);
>> + mutex_lock(&all_memcg_lrus_mutex);
>> + list_add(&lru->lrus, &all_memcg_lrus);
>> + ret = memcg_new_lru(lru);
>> + mutex_unlock(&all_memcg_lrus_mutex);
>> + return ret;
>> +}
>
> returns 0 at success ? what kind of error can be shown here ?
>
memcg_new_lru will allocate memory, and therefore can fail with ENOMEM.
It will already return 0 itself on success, so just forwarding its
return value is around.
>> -EXPORT_SYMBOL_GPL(list_lru_init);
>> +EXPORT_SYMBOL_GPL(__list_lru_init);
>> diff --git a/mm/memcontrol.c b/mm/memcontrol.c
>> index ecdae39..c6c90d8 100644
>> --- a/mm/memcontrol.c
>> +++ b/mm/memcontrol.c
>> @@ -2988,16 +2988,30 @@ int memcg_update_cache_sizes(struct mem_cgroup *memcg)
>> memcg_kmem_set_activated(memcg);
>>
>> ret = memcg_update_all_caches(num+1);
>> - if (ret) {
>> - ida_simple_remove(&kmem_limited_groups, num);
>> - memcg_kmem_clear_activated(memcg);
>> - return ret;
>> - }
>> + if (ret)
>> + goto out;
>> +
>> + /*
>> + * We should make sure that the array size is not updated until we are
>> + * done; otherwise we have no easy way to know whether or not we should
>> + * grow the array.
>> + */
>> + ret = memcg_update_all_lrus(num + 1);
>> + if (ret)
>> + goto out;
>>
>> memcg->kmemcg_id = num;
>> +
>> + memcg_update_array_size(num + 1);
>> +
>> INIT_LIST_HEAD(&memcg->memcg_slab_caches);
>> mutex_init(&memcg->slab_caches_mutex);
>> +
>> return 0;
>> +out:
>> + ida_simple_remove(&kmem_limited_groups, num);
>> + memcg_kmem_clear_activated(memcg);
>> + return ret;
>
> When this failure can happens ? This happens only when the user
> tries to set kmem_limit and doesn't affect kernel internal logic ?
>
There are 2 points of failure for this:
1) setting kmem limit from a previously unset scenario,
2) creating a new child memcg, as a child of a kmem limited memcg
Those are the same as the slab, and indeed they are attempted right
after it.
LRU initialization failures can still exist in a 3rd way, when a new LRU
is created and we have no memory available to hold its structures. But
this will not be called from here.
More information about the Containers
mailing list