1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2013 Red Hat, Inc. and Parallels Inc. All rights reserved.
4*4882a593Smuzhiyun * Authors: David Chinner and Glauber Costa
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Generic LRU infrastructure
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun #include <linux/kernel.h>
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/mm.h>
11*4882a593Smuzhiyun #include <linux/list_lru.h>
12*4882a593Smuzhiyun #include <linux/slab.h>
13*4882a593Smuzhiyun #include <linux/mutex.h>
14*4882a593Smuzhiyun #include <linux/memcontrol.h>
15*4882a593Smuzhiyun #include "slab.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #ifdef CONFIG_MEMCG_KMEM
18*4882a593Smuzhiyun static LIST_HEAD(list_lrus);
19*4882a593Smuzhiyun static DEFINE_MUTEX(list_lrus_mutex);
20*4882a593Smuzhiyun
list_lru_register(struct list_lru * lru)21*4882a593Smuzhiyun static void list_lru_register(struct list_lru *lru)
22*4882a593Smuzhiyun {
23*4882a593Smuzhiyun mutex_lock(&list_lrus_mutex);
24*4882a593Smuzhiyun list_add(&lru->list, &list_lrus);
25*4882a593Smuzhiyun mutex_unlock(&list_lrus_mutex);
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun
list_lru_unregister(struct list_lru * lru)28*4882a593Smuzhiyun static void list_lru_unregister(struct list_lru *lru)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun mutex_lock(&list_lrus_mutex);
31*4882a593Smuzhiyun list_del(&lru->list);
32*4882a593Smuzhiyun mutex_unlock(&list_lrus_mutex);
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun
lru_shrinker_id(struct list_lru * lru)35*4882a593Smuzhiyun static int lru_shrinker_id(struct list_lru *lru)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun return lru->shrinker_id;
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun
list_lru_memcg_aware(struct list_lru * lru)40*4882a593Smuzhiyun static inline bool list_lru_memcg_aware(struct list_lru *lru)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun return lru->memcg_aware;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun static inline struct list_lru_one *
list_lru_from_memcg_idx(struct list_lru_node * nlru,int idx)46*4882a593Smuzhiyun list_lru_from_memcg_idx(struct list_lru_node *nlru, int idx)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun struct list_lru_memcg *memcg_lrus;
49*4882a593Smuzhiyun /*
50*4882a593Smuzhiyun * Either lock or RCU protects the array of per cgroup lists
51*4882a593Smuzhiyun * from relocation (see memcg_update_list_lru_node).
52*4882a593Smuzhiyun */
53*4882a593Smuzhiyun memcg_lrus = rcu_dereference_check(nlru->memcg_lrus,
54*4882a593Smuzhiyun lockdep_is_held(&nlru->lock));
55*4882a593Smuzhiyun if (memcg_lrus && idx >= 0)
56*4882a593Smuzhiyun return memcg_lrus->lru[idx];
57*4882a593Smuzhiyun return &nlru->lru;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun static inline struct list_lru_one *
list_lru_from_kmem(struct list_lru_node * nlru,void * ptr,struct mem_cgroup ** memcg_ptr)61*4882a593Smuzhiyun list_lru_from_kmem(struct list_lru_node *nlru, void *ptr,
62*4882a593Smuzhiyun struct mem_cgroup **memcg_ptr)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun struct list_lru_one *l = &nlru->lru;
65*4882a593Smuzhiyun struct mem_cgroup *memcg = NULL;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun if (!nlru->memcg_lrus)
68*4882a593Smuzhiyun goto out;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun memcg = mem_cgroup_from_obj(ptr);
71*4882a593Smuzhiyun if (!memcg)
72*4882a593Smuzhiyun goto out;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun l = list_lru_from_memcg_idx(nlru, memcg_cache_id(memcg));
75*4882a593Smuzhiyun out:
76*4882a593Smuzhiyun if (memcg_ptr)
77*4882a593Smuzhiyun *memcg_ptr = memcg;
78*4882a593Smuzhiyun return l;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun #else
list_lru_register(struct list_lru * lru)81*4882a593Smuzhiyun static void list_lru_register(struct list_lru *lru)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
list_lru_unregister(struct list_lru * lru)85*4882a593Smuzhiyun static void list_lru_unregister(struct list_lru *lru)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
lru_shrinker_id(struct list_lru * lru)89*4882a593Smuzhiyun static int lru_shrinker_id(struct list_lru *lru)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun return -1;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
list_lru_memcg_aware(struct list_lru * lru)94*4882a593Smuzhiyun static inline bool list_lru_memcg_aware(struct list_lru *lru)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun return false;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun static inline struct list_lru_one *
list_lru_from_memcg_idx(struct list_lru_node * nlru,int idx)100*4882a593Smuzhiyun list_lru_from_memcg_idx(struct list_lru_node *nlru, int idx)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun return &nlru->lru;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun static inline struct list_lru_one *
list_lru_from_kmem(struct list_lru_node * nlru,void * ptr,struct mem_cgroup ** memcg_ptr)106*4882a593Smuzhiyun list_lru_from_kmem(struct list_lru_node *nlru, void *ptr,
107*4882a593Smuzhiyun struct mem_cgroup **memcg_ptr)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun if (memcg_ptr)
110*4882a593Smuzhiyun *memcg_ptr = NULL;
111*4882a593Smuzhiyun return &nlru->lru;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun #endif /* CONFIG_MEMCG_KMEM */
114*4882a593Smuzhiyun
list_lru_add(struct list_lru * lru,struct list_head * item)115*4882a593Smuzhiyun bool list_lru_add(struct list_lru *lru, struct list_head *item)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun int nid = page_to_nid(virt_to_page(item));
118*4882a593Smuzhiyun struct list_lru_node *nlru = &lru->node[nid];
119*4882a593Smuzhiyun struct mem_cgroup *memcg;
120*4882a593Smuzhiyun struct list_lru_one *l;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun spin_lock(&nlru->lock);
123*4882a593Smuzhiyun if (list_empty(item)) {
124*4882a593Smuzhiyun l = list_lru_from_kmem(nlru, item, &memcg);
125*4882a593Smuzhiyun list_add_tail(item, &l->list);
126*4882a593Smuzhiyun /* Set shrinker bit if the first element was added */
127*4882a593Smuzhiyun if (!l->nr_items++)
128*4882a593Smuzhiyun memcg_set_shrinker_bit(memcg, nid,
129*4882a593Smuzhiyun lru_shrinker_id(lru));
130*4882a593Smuzhiyun nlru->nr_items++;
131*4882a593Smuzhiyun spin_unlock(&nlru->lock);
132*4882a593Smuzhiyun return true;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun spin_unlock(&nlru->lock);
135*4882a593Smuzhiyun return false;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(list_lru_add);
138*4882a593Smuzhiyun
list_lru_del(struct list_lru * lru,struct list_head * item)139*4882a593Smuzhiyun bool list_lru_del(struct list_lru *lru, struct list_head *item)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun int nid = page_to_nid(virt_to_page(item));
142*4882a593Smuzhiyun struct list_lru_node *nlru = &lru->node[nid];
143*4882a593Smuzhiyun struct list_lru_one *l;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun spin_lock(&nlru->lock);
146*4882a593Smuzhiyun if (!list_empty(item)) {
147*4882a593Smuzhiyun l = list_lru_from_kmem(nlru, item, NULL);
148*4882a593Smuzhiyun list_del_init(item);
149*4882a593Smuzhiyun l->nr_items--;
150*4882a593Smuzhiyun nlru->nr_items--;
151*4882a593Smuzhiyun spin_unlock(&nlru->lock);
152*4882a593Smuzhiyun return true;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun spin_unlock(&nlru->lock);
155*4882a593Smuzhiyun return false;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(list_lru_del);
158*4882a593Smuzhiyun
list_lru_isolate(struct list_lru_one * list,struct list_head * item)159*4882a593Smuzhiyun void list_lru_isolate(struct list_lru_one *list, struct list_head *item)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun list_del_init(item);
162*4882a593Smuzhiyun list->nr_items--;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(list_lru_isolate);
165*4882a593Smuzhiyun
list_lru_isolate_move(struct list_lru_one * list,struct list_head * item,struct list_head * head)166*4882a593Smuzhiyun void list_lru_isolate_move(struct list_lru_one *list, struct list_head *item,
167*4882a593Smuzhiyun struct list_head *head)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun list_move(item, head);
170*4882a593Smuzhiyun list->nr_items--;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(list_lru_isolate_move);
173*4882a593Smuzhiyun
list_lru_count_one(struct list_lru * lru,int nid,struct mem_cgroup * memcg)174*4882a593Smuzhiyun unsigned long list_lru_count_one(struct list_lru *lru,
175*4882a593Smuzhiyun int nid, struct mem_cgroup *memcg)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun struct list_lru_node *nlru = &lru->node[nid];
178*4882a593Smuzhiyun struct list_lru_one *l;
179*4882a593Smuzhiyun unsigned long count;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun rcu_read_lock();
182*4882a593Smuzhiyun l = list_lru_from_memcg_idx(nlru, memcg_cache_id(memcg));
183*4882a593Smuzhiyun count = READ_ONCE(l->nr_items);
184*4882a593Smuzhiyun rcu_read_unlock();
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun return count;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(list_lru_count_one);
189*4882a593Smuzhiyun
list_lru_count_node(struct list_lru * lru,int nid)190*4882a593Smuzhiyun unsigned long list_lru_count_node(struct list_lru *lru, int nid)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun struct list_lru_node *nlru;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun nlru = &lru->node[nid];
195*4882a593Smuzhiyun return nlru->nr_items;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(list_lru_count_node);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun static unsigned long
__list_lru_walk_one(struct list_lru_node * nlru,int memcg_idx,list_lru_walk_cb isolate,void * cb_arg,unsigned long * nr_to_walk)200*4882a593Smuzhiyun __list_lru_walk_one(struct list_lru_node *nlru, int memcg_idx,
201*4882a593Smuzhiyun list_lru_walk_cb isolate, void *cb_arg,
202*4882a593Smuzhiyun unsigned long *nr_to_walk)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun struct list_lru_one *l;
206*4882a593Smuzhiyun struct list_head *item, *n;
207*4882a593Smuzhiyun unsigned long isolated = 0;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun l = list_lru_from_memcg_idx(nlru, memcg_idx);
210*4882a593Smuzhiyun restart:
211*4882a593Smuzhiyun list_for_each_safe(item, n, &l->list) {
212*4882a593Smuzhiyun enum lru_status ret;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun /*
215*4882a593Smuzhiyun * decrement nr_to_walk first so that we don't livelock if we
216*4882a593Smuzhiyun * get stuck on large numbers of LRU_RETRY items
217*4882a593Smuzhiyun */
218*4882a593Smuzhiyun if (!*nr_to_walk)
219*4882a593Smuzhiyun break;
220*4882a593Smuzhiyun --*nr_to_walk;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun ret = isolate(item, l, &nlru->lock, cb_arg);
223*4882a593Smuzhiyun switch (ret) {
224*4882a593Smuzhiyun case LRU_REMOVED_RETRY:
225*4882a593Smuzhiyun assert_spin_locked(&nlru->lock);
226*4882a593Smuzhiyun fallthrough;
227*4882a593Smuzhiyun case LRU_REMOVED:
228*4882a593Smuzhiyun isolated++;
229*4882a593Smuzhiyun nlru->nr_items--;
230*4882a593Smuzhiyun /*
231*4882a593Smuzhiyun * If the lru lock has been dropped, our list
232*4882a593Smuzhiyun * traversal is now invalid and so we have to
233*4882a593Smuzhiyun * restart from scratch.
234*4882a593Smuzhiyun */
235*4882a593Smuzhiyun if (ret == LRU_REMOVED_RETRY)
236*4882a593Smuzhiyun goto restart;
237*4882a593Smuzhiyun break;
238*4882a593Smuzhiyun case LRU_ROTATE:
239*4882a593Smuzhiyun list_move_tail(item, &l->list);
240*4882a593Smuzhiyun break;
241*4882a593Smuzhiyun case LRU_SKIP:
242*4882a593Smuzhiyun break;
243*4882a593Smuzhiyun case LRU_RETRY:
244*4882a593Smuzhiyun /*
245*4882a593Smuzhiyun * The lru lock has been dropped, our list traversal is
246*4882a593Smuzhiyun * now invalid and so we have to restart from scratch.
247*4882a593Smuzhiyun */
248*4882a593Smuzhiyun assert_spin_locked(&nlru->lock);
249*4882a593Smuzhiyun goto restart;
250*4882a593Smuzhiyun default:
251*4882a593Smuzhiyun BUG();
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun return isolated;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun unsigned long
list_lru_walk_one(struct list_lru * lru,int nid,struct mem_cgroup * memcg,list_lru_walk_cb isolate,void * cb_arg,unsigned long * nr_to_walk)258*4882a593Smuzhiyun list_lru_walk_one(struct list_lru *lru, int nid, struct mem_cgroup *memcg,
259*4882a593Smuzhiyun list_lru_walk_cb isolate, void *cb_arg,
260*4882a593Smuzhiyun unsigned long *nr_to_walk)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun struct list_lru_node *nlru = &lru->node[nid];
263*4882a593Smuzhiyun unsigned long ret;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun spin_lock(&nlru->lock);
266*4882a593Smuzhiyun ret = __list_lru_walk_one(nlru, memcg_cache_id(memcg), isolate, cb_arg,
267*4882a593Smuzhiyun nr_to_walk);
268*4882a593Smuzhiyun spin_unlock(&nlru->lock);
269*4882a593Smuzhiyun return ret;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(list_lru_walk_one);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun unsigned long
list_lru_walk_one_irq(struct list_lru * lru,int nid,struct mem_cgroup * memcg,list_lru_walk_cb isolate,void * cb_arg,unsigned long * nr_to_walk)274*4882a593Smuzhiyun list_lru_walk_one_irq(struct list_lru *lru, int nid, struct mem_cgroup *memcg,
275*4882a593Smuzhiyun list_lru_walk_cb isolate, void *cb_arg,
276*4882a593Smuzhiyun unsigned long *nr_to_walk)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun struct list_lru_node *nlru = &lru->node[nid];
279*4882a593Smuzhiyun unsigned long ret;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun spin_lock_irq(&nlru->lock);
282*4882a593Smuzhiyun ret = __list_lru_walk_one(nlru, memcg_cache_id(memcg), isolate, cb_arg,
283*4882a593Smuzhiyun nr_to_walk);
284*4882a593Smuzhiyun spin_unlock_irq(&nlru->lock);
285*4882a593Smuzhiyun return ret;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
list_lru_walk_node(struct list_lru * lru,int nid,list_lru_walk_cb isolate,void * cb_arg,unsigned long * nr_to_walk)288*4882a593Smuzhiyun unsigned long list_lru_walk_node(struct list_lru *lru, int nid,
289*4882a593Smuzhiyun list_lru_walk_cb isolate, void *cb_arg,
290*4882a593Smuzhiyun unsigned long *nr_to_walk)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun long isolated = 0;
293*4882a593Smuzhiyun int memcg_idx;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun isolated += list_lru_walk_one(lru, nid, NULL, isolate, cb_arg,
296*4882a593Smuzhiyun nr_to_walk);
297*4882a593Smuzhiyun if (*nr_to_walk > 0 && list_lru_memcg_aware(lru)) {
298*4882a593Smuzhiyun for_each_memcg_cache_index(memcg_idx) {
299*4882a593Smuzhiyun struct list_lru_node *nlru = &lru->node[nid];
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun spin_lock(&nlru->lock);
302*4882a593Smuzhiyun isolated += __list_lru_walk_one(nlru, memcg_idx,
303*4882a593Smuzhiyun isolate, cb_arg,
304*4882a593Smuzhiyun nr_to_walk);
305*4882a593Smuzhiyun spin_unlock(&nlru->lock);
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun if (*nr_to_walk <= 0)
308*4882a593Smuzhiyun break;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun return isolated;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(list_lru_walk_node);
314*4882a593Smuzhiyun
init_one_lru(struct list_lru_one * l)315*4882a593Smuzhiyun static void init_one_lru(struct list_lru_one *l)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun INIT_LIST_HEAD(&l->list);
318*4882a593Smuzhiyun l->nr_items = 0;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun #ifdef CONFIG_MEMCG_KMEM
__memcg_destroy_list_lru_node(struct list_lru_memcg * memcg_lrus,int begin,int end)322*4882a593Smuzhiyun static void __memcg_destroy_list_lru_node(struct list_lru_memcg *memcg_lrus,
323*4882a593Smuzhiyun int begin, int end)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun int i;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun for (i = begin; i < end; i++)
328*4882a593Smuzhiyun kfree(memcg_lrus->lru[i]);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
__memcg_init_list_lru_node(struct list_lru_memcg * memcg_lrus,int begin,int end)331*4882a593Smuzhiyun static int __memcg_init_list_lru_node(struct list_lru_memcg *memcg_lrus,
332*4882a593Smuzhiyun int begin, int end)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun int i;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun for (i = begin; i < end; i++) {
337*4882a593Smuzhiyun struct list_lru_one *l;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun l = kmalloc(sizeof(struct list_lru_one), GFP_KERNEL);
340*4882a593Smuzhiyun if (!l)
341*4882a593Smuzhiyun goto fail;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun init_one_lru(l);
344*4882a593Smuzhiyun memcg_lrus->lru[i] = l;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun return 0;
347*4882a593Smuzhiyun fail:
348*4882a593Smuzhiyun __memcg_destroy_list_lru_node(memcg_lrus, begin, i);
349*4882a593Smuzhiyun return -ENOMEM;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun
memcg_init_list_lru_node(struct list_lru_node * nlru)352*4882a593Smuzhiyun static int memcg_init_list_lru_node(struct list_lru_node *nlru)
353*4882a593Smuzhiyun {
354*4882a593Smuzhiyun struct list_lru_memcg *memcg_lrus;
355*4882a593Smuzhiyun int size = memcg_nr_cache_ids;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun memcg_lrus = kvmalloc(sizeof(*memcg_lrus) +
358*4882a593Smuzhiyun size * sizeof(void *), GFP_KERNEL);
359*4882a593Smuzhiyun if (!memcg_lrus)
360*4882a593Smuzhiyun return -ENOMEM;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun if (__memcg_init_list_lru_node(memcg_lrus, 0, size)) {
363*4882a593Smuzhiyun kvfree(memcg_lrus);
364*4882a593Smuzhiyun return -ENOMEM;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun RCU_INIT_POINTER(nlru->memcg_lrus, memcg_lrus);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun return 0;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
memcg_destroy_list_lru_node(struct list_lru_node * nlru)371*4882a593Smuzhiyun static void memcg_destroy_list_lru_node(struct list_lru_node *nlru)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun struct list_lru_memcg *memcg_lrus;
374*4882a593Smuzhiyun /*
375*4882a593Smuzhiyun * This is called when shrinker has already been unregistered,
376*4882a593Smuzhiyun * and nobody can use it. So, there is no need to use kvfree_rcu_local().
377*4882a593Smuzhiyun */
378*4882a593Smuzhiyun memcg_lrus = rcu_dereference_protected(nlru->memcg_lrus, true);
379*4882a593Smuzhiyun __memcg_destroy_list_lru_node(memcg_lrus, 0, memcg_nr_cache_ids);
380*4882a593Smuzhiyun kvfree(memcg_lrus);
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun
kvfree_rcu_local(struct rcu_head * head)383*4882a593Smuzhiyun static void kvfree_rcu_local(struct rcu_head *head)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun struct list_lru_memcg *mlru;
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun mlru = container_of(head, struct list_lru_memcg, rcu);
388*4882a593Smuzhiyun kvfree(mlru);
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
memcg_update_list_lru_node(struct list_lru_node * nlru,int old_size,int new_size)391*4882a593Smuzhiyun static int memcg_update_list_lru_node(struct list_lru_node *nlru,
392*4882a593Smuzhiyun int old_size, int new_size)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun struct list_lru_memcg *old, *new;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun BUG_ON(old_size > new_size);
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun old = rcu_dereference_protected(nlru->memcg_lrus,
399*4882a593Smuzhiyun lockdep_is_held(&list_lrus_mutex));
400*4882a593Smuzhiyun new = kvmalloc(sizeof(*new) + new_size * sizeof(void *), GFP_KERNEL);
401*4882a593Smuzhiyun if (!new)
402*4882a593Smuzhiyun return -ENOMEM;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun if (__memcg_init_list_lru_node(new, old_size, new_size)) {
405*4882a593Smuzhiyun kvfree(new);
406*4882a593Smuzhiyun return -ENOMEM;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun memcpy(&new->lru, &old->lru, old_size * sizeof(void *));
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun /*
412*4882a593Smuzhiyun * The locking below allows readers that hold nlru->lock avoid taking
413*4882a593Smuzhiyun * rcu_read_lock (see list_lru_from_memcg_idx).
414*4882a593Smuzhiyun *
415*4882a593Smuzhiyun * Since list_lru_{add,del} may be called under an IRQ-safe lock,
416*4882a593Smuzhiyun * we have to use IRQ-safe primitives here to avoid deadlock.
417*4882a593Smuzhiyun */
418*4882a593Smuzhiyun spin_lock_irq(&nlru->lock);
419*4882a593Smuzhiyun rcu_assign_pointer(nlru->memcg_lrus, new);
420*4882a593Smuzhiyun spin_unlock_irq(&nlru->lock);
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun call_rcu(&old->rcu, kvfree_rcu_local);
423*4882a593Smuzhiyun return 0;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
memcg_cancel_update_list_lru_node(struct list_lru_node * nlru,int old_size,int new_size)426*4882a593Smuzhiyun static void memcg_cancel_update_list_lru_node(struct list_lru_node *nlru,
427*4882a593Smuzhiyun int old_size, int new_size)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun struct list_lru_memcg *memcg_lrus;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun memcg_lrus = rcu_dereference_protected(nlru->memcg_lrus,
432*4882a593Smuzhiyun lockdep_is_held(&list_lrus_mutex));
433*4882a593Smuzhiyun /* do not bother shrinking the array back to the old size, because we
434*4882a593Smuzhiyun * cannot handle allocation failures here */
435*4882a593Smuzhiyun __memcg_destroy_list_lru_node(memcg_lrus, old_size, new_size);
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun
memcg_init_list_lru(struct list_lru * lru,bool memcg_aware)438*4882a593Smuzhiyun static int memcg_init_list_lru(struct list_lru *lru, bool memcg_aware)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun int i;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun lru->memcg_aware = memcg_aware;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun if (!memcg_aware)
445*4882a593Smuzhiyun return 0;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun for_each_node(i) {
448*4882a593Smuzhiyun if (memcg_init_list_lru_node(&lru->node[i]))
449*4882a593Smuzhiyun goto fail;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun return 0;
452*4882a593Smuzhiyun fail:
453*4882a593Smuzhiyun for (i = i - 1; i >= 0; i--) {
454*4882a593Smuzhiyun if (!lru->node[i].memcg_lrus)
455*4882a593Smuzhiyun continue;
456*4882a593Smuzhiyun memcg_destroy_list_lru_node(&lru->node[i]);
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun return -ENOMEM;
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun
memcg_destroy_list_lru(struct list_lru * lru)461*4882a593Smuzhiyun static void memcg_destroy_list_lru(struct list_lru *lru)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun int i;
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun if (!list_lru_memcg_aware(lru))
466*4882a593Smuzhiyun return;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun for_each_node(i)
469*4882a593Smuzhiyun memcg_destroy_list_lru_node(&lru->node[i]);
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
memcg_update_list_lru(struct list_lru * lru,int old_size,int new_size)472*4882a593Smuzhiyun static int memcg_update_list_lru(struct list_lru *lru,
473*4882a593Smuzhiyun int old_size, int new_size)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun int i;
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun if (!list_lru_memcg_aware(lru))
478*4882a593Smuzhiyun return 0;
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun for_each_node(i) {
481*4882a593Smuzhiyun if (memcg_update_list_lru_node(&lru->node[i],
482*4882a593Smuzhiyun old_size, new_size))
483*4882a593Smuzhiyun goto fail;
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun return 0;
486*4882a593Smuzhiyun fail:
487*4882a593Smuzhiyun for (i = i - 1; i >= 0; i--) {
488*4882a593Smuzhiyun if (!lru->node[i].memcg_lrus)
489*4882a593Smuzhiyun continue;
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun memcg_cancel_update_list_lru_node(&lru->node[i],
492*4882a593Smuzhiyun old_size, new_size);
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun return -ENOMEM;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
memcg_cancel_update_list_lru(struct list_lru * lru,int old_size,int new_size)497*4882a593Smuzhiyun static void memcg_cancel_update_list_lru(struct list_lru *lru,
498*4882a593Smuzhiyun int old_size, int new_size)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun int i;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun if (!list_lru_memcg_aware(lru))
503*4882a593Smuzhiyun return;
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun for_each_node(i)
506*4882a593Smuzhiyun memcg_cancel_update_list_lru_node(&lru->node[i],
507*4882a593Smuzhiyun old_size, new_size);
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
memcg_update_all_list_lrus(int new_size)510*4882a593Smuzhiyun int memcg_update_all_list_lrus(int new_size)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun int ret = 0;
513*4882a593Smuzhiyun struct list_lru *lru;
514*4882a593Smuzhiyun int old_size = memcg_nr_cache_ids;
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun mutex_lock(&list_lrus_mutex);
517*4882a593Smuzhiyun list_for_each_entry(lru, &list_lrus, list) {
518*4882a593Smuzhiyun ret = memcg_update_list_lru(lru, old_size, new_size);
519*4882a593Smuzhiyun if (ret)
520*4882a593Smuzhiyun goto fail;
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun out:
523*4882a593Smuzhiyun mutex_unlock(&list_lrus_mutex);
524*4882a593Smuzhiyun return ret;
525*4882a593Smuzhiyun fail:
526*4882a593Smuzhiyun list_for_each_entry_continue_reverse(lru, &list_lrus, list)
527*4882a593Smuzhiyun memcg_cancel_update_list_lru(lru, old_size, new_size);
528*4882a593Smuzhiyun goto out;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
memcg_drain_list_lru_node(struct list_lru * lru,int nid,int src_idx,struct mem_cgroup * dst_memcg)531*4882a593Smuzhiyun static void memcg_drain_list_lru_node(struct list_lru *lru, int nid,
532*4882a593Smuzhiyun int src_idx, struct mem_cgroup *dst_memcg)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun struct list_lru_node *nlru = &lru->node[nid];
535*4882a593Smuzhiyun int dst_idx = dst_memcg->kmemcg_id;
536*4882a593Smuzhiyun struct list_lru_one *src, *dst;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun /*
539*4882a593Smuzhiyun * Since list_lru_{add,del} may be called under an IRQ-safe lock,
540*4882a593Smuzhiyun * we have to use IRQ-safe primitives here to avoid deadlock.
541*4882a593Smuzhiyun */
542*4882a593Smuzhiyun spin_lock_irq(&nlru->lock);
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun src = list_lru_from_memcg_idx(nlru, src_idx);
545*4882a593Smuzhiyun dst = list_lru_from_memcg_idx(nlru, dst_idx);
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun list_splice_init(&src->list, &dst->list);
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun if (src->nr_items) {
550*4882a593Smuzhiyun dst->nr_items += src->nr_items;
551*4882a593Smuzhiyun memcg_set_shrinker_bit(dst_memcg, nid, lru_shrinker_id(lru));
552*4882a593Smuzhiyun src->nr_items = 0;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun spin_unlock_irq(&nlru->lock);
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun
memcg_drain_list_lru(struct list_lru * lru,int src_idx,struct mem_cgroup * dst_memcg)558*4882a593Smuzhiyun static void memcg_drain_list_lru(struct list_lru *lru,
559*4882a593Smuzhiyun int src_idx, struct mem_cgroup *dst_memcg)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun int i;
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun if (!list_lru_memcg_aware(lru))
564*4882a593Smuzhiyun return;
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun for_each_node(i)
567*4882a593Smuzhiyun memcg_drain_list_lru_node(lru, i, src_idx, dst_memcg);
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun
memcg_drain_all_list_lrus(int src_idx,struct mem_cgroup * dst_memcg)570*4882a593Smuzhiyun void memcg_drain_all_list_lrus(int src_idx, struct mem_cgroup *dst_memcg)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun struct list_lru *lru;
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun mutex_lock(&list_lrus_mutex);
575*4882a593Smuzhiyun list_for_each_entry(lru, &list_lrus, list)
576*4882a593Smuzhiyun memcg_drain_list_lru(lru, src_idx, dst_memcg);
577*4882a593Smuzhiyun mutex_unlock(&list_lrus_mutex);
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun #else
memcg_init_list_lru(struct list_lru * lru,bool memcg_aware)580*4882a593Smuzhiyun static int memcg_init_list_lru(struct list_lru *lru, bool memcg_aware)
581*4882a593Smuzhiyun {
582*4882a593Smuzhiyun return 0;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun
memcg_destroy_list_lru(struct list_lru * lru)585*4882a593Smuzhiyun static void memcg_destroy_list_lru(struct list_lru *lru)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun #endif /* CONFIG_MEMCG_KMEM */
589*4882a593Smuzhiyun
__list_lru_init(struct list_lru * lru,bool memcg_aware,struct lock_class_key * key,struct shrinker * shrinker)590*4882a593Smuzhiyun int __list_lru_init(struct list_lru *lru, bool memcg_aware,
591*4882a593Smuzhiyun struct lock_class_key *key, struct shrinker *shrinker)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun int i;
594*4882a593Smuzhiyun int err = -ENOMEM;
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun #ifdef CONFIG_MEMCG_KMEM
597*4882a593Smuzhiyun if (shrinker)
598*4882a593Smuzhiyun lru->shrinker_id = shrinker->id;
599*4882a593Smuzhiyun else
600*4882a593Smuzhiyun lru->shrinker_id = -1;
601*4882a593Smuzhiyun #endif
602*4882a593Smuzhiyun memcg_get_cache_ids();
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun lru->node = kcalloc(nr_node_ids, sizeof(*lru->node), GFP_KERNEL);
605*4882a593Smuzhiyun if (!lru->node)
606*4882a593Smuzhiyun goto out;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun for_each_node(i) {
609*4882a593Smuzhiyun spin_lock_init(&lru->node[i].lock);
610*4882a593Smuzhiyun if (key)
611*4882a593Smuzhiyun lockdep_set_class(&lru->node[i].lock, key);
612*4882a593Smuzhiyun init_one_lru(&lru->node[i].lru);
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun err = memcg_init_list_lru(lru, memcg_aware);
616*4882a593Smuzhiyun if (err) {
617*4882a593Smuzhiyun kfree(lru->node);
618*4882a593Smuzhiyun /* Do this so a list_lru_destroy() doesn't crash: */
619*4882a593Smuzhiyun lru->node = NULL;
620*4882a593Smuzhiyun goto out;
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun list_lru_register(lru);
624*4882a593Smuzhiyun out:
625*4882a593Smuzhiyun memcg_put_cache_ids();
626*4882a593Smuzhiyun return err;
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(__list_lru_init);
629*4882a593Smuzhiyun
list_lru_destroy(struct list_lru * lru)630*4882a593Smuzhiyun void list_lru_destroy(struct list_lru *lru)
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun /* Already destroyed or not yet initialized? */
633*4882a593Smuzhiyun if (!lru->node)
634*4882a593Smuzhiyun return;
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun memcg_get_cache_ids();
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun list_lru_unregister(lru);
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun memcg_destroy_list_lru(lru);
641*4882a593Smuzhiyun kfree(lru->node);
642*4882a593Smuzhiyun lru->node = NULL;
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun #ifdef CONFIG_MEMCG_KMEM
645*4882a593Smuzhiyun lru->shrinker_id = -1;
646*4882a593Smuzhiyun #endif
647*4882a593Smuzhiyun memcg_put_cache_ids();
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(list_lru_destroy);
650