1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
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 #ifndef _LRU_LIST_H
9*4882a593Smuzhiyun #define _LRU_LIST_H
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/list.h>
12*4882a593Smuzhiyun #include <linux/nodemask.h>
13*4882a593Smuzhiyun #include <linux/shrinker.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun struct mem_cgroup;
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun /* list_lru_walk_cb has to always return one of those */
18*4882a593Smuzhiyun enum lru_status {
19*4882a593Smuzhiyun LRU_REMOVED, /* item removed from list */
20*4882a593Smuzhiyun LRU_REMOVED_RETRY, /* item removed, but lock has been
21*4882a593Smuzhiyun dropped and reacquired */
22*4882a593Smuzhiyun LRU_ROTATE, /* item referenced, give another pass */
23*4882a593Smuzhiyun LRU_SKIP, /* item cannot be locked, skip */
24*4882a593Smuzhiyun LRU_RETRY, /* item not freeable. May drop the lock
25*4882a593Smuzhiyun internally, but has to return locked. */
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun struct list_lru_one {
29*4882a593Smuzhiyun struct list_head list;
30*4882a593Smuzhiyun /* may become negative during memcg reparenting */
31*4882a593Smuzhiyun long nr_items;
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun struct list_lru_memcg {
35*4882a593Smuzhiyun struct rcu_head rcu;
36*4882a593Smuzhiyun /* array of per cgroup lists, indexed by memcg_cache_id */
37*4882a593Smuzhiyun struct list_lru_one *lru[];
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun struct list_lru_node {
41*4882a593Smuzhiyun /* protects all lists on the node, including per cgroup */
42*4882a593Smuzhiyun spinlock_t lock;
43*4882a593Smuzhiyun /* global list, used for the root cgroup in cgroup aware lrus */
44*4882a593Smuzhiyun struct list_lru_one lru;
45*4882a593Smuzhiyun #ifdef CONFIG_MEMCG_KMEM
46*4882a593Smuzhiyun /* for cgroup aware lrus points to per cgroup lists, otherwise NULL */
47*4882a593Smuzhiyun struct list_lru_memcg __rcu *memcg_lrus;
48*4882a593Smuzhiyun #endif
49*4882a593Smuzhiyun long nr_items;
50*4882a593Smuzhiyun } ____cacheline_aligned_in_smp;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun struct list_lru {
53*4882a593Smuzhiyun struct list_lru_node *node;
54*4882a593Smuzhiyun #ifdef CONFIG_MEMCG_KMEM
55*4882a593Smuzhiyun struct list_head list;
56*4882a593Smuzhiyun int shrinker_id;
57*4882a593Smuzhiyun bool memcg_aware;
58*4882a593Smuzhiyun #endif
59*4882a593Smuzhiyun };
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun void list_lru_destroy(struct list_lru *lru);
62*4882a593Smuzhiyun int __list_lru_init(struct list_lru *lru, bool memcg_aware,
63*4882a593Smuzhiyun struct lock_class_key *key, struct shrinker *shrinker);
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun #define list_lru_init(lru) \
66*4882a593Smuzhiyun __list_lru_init((lru), false, NULL, NULL)
67*4882a593Smuzhiyun #define list_lru_init_key(lru, key) \
68*4882a593Smuzhiyun __list_lru_init((lru), false, (key), NULL)
69*4882a593Smuzhiyun #define list_lru_init_memcg(lru, shrinker) \
70*4882a593Smuzhiyun __list_lru_init((lru), true, NULL, shrinker)
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun int memcg_update_all_list_lrus(int num_memcgs);
73*4882a593Smuzhiyun void memcg_drain_all_list_lrus(int src_idx, struct mem_cgroup *dst_memcg);
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /**
76*4882a593Smuzhiyun * list_lru_add: add an element to the lru list's tail
77*4882a593Smuzhiyun * @list_lru: the lru pointer
78*4882a593Smuzhiyun * @item: the item to be added.
79*4882a593Smuzhiyun *
80*4882a593Smuzhiyun * If the element is already part of a list, this function returns doing
81*4882a593Smuzhiyun * nothing. Therefore the caller does not need to keep state about whether or
82*4882a593Smuzhiyun * not the element already belongs in the list and is allowed to lazy update
83*4882a593Smuzhiyun * it. Note however that this is valid for *a* list, not *this* list. If
84*4882a593Smuzhiyun * the caller organize itself in a way that elements can be in more than
85*4882a593Smuzhiyun * one type of list, it is up to the caller to fully remove the item from
86*4882a593Smuzhiyun * the previous list (with list_lru_del() for instance) before moving it
87*4882a593Smuzhiyun * to @list_lru
88*4882a593Smuzhiyun *
89*4882a593Smuzhiyun * Return value: true if the list was updated, false otherwise
90*4882a593Smuzhiyun */
91*4882a593Smuzhiyun bool list_lru_add(struct list_lru *lru, struct list_head *item);
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun /**
94*4882a593Smuzhiyun * list_lru_del: delete an element to the lru list
95*4882a593Smuzhiyun * @list_lru: the lru pointer
96*4882a593Smuzhiyun * @item: the item to be deleted.
97*4882a593Smuzhiyun *
98*4882a593Smuzhiyun * This function works analogously as list_lru_add in terms of list
99*4882a593Smuzhiyun * manipulation. The comments about an element already pertaining to
100*4882a593Smuzhiyun * a list are also valid for list_lru_del.
101*4882a593Smuzhiyun *
102*4882a593Smuzhiyun * Return value: true if the list was updated, false otherwise
103*4882a593Smuzhiyun */
104*4882a593Smuzhiyun bool list_lru_del(struct list_lru *lru, struct list_head *item);
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /**
107*4882a593Smuzhiyun * list_lru_count_one: return the number of objects currently held by @lru
108*4882a593Smuzhiyun * @lru: the lru pointer.
109*4882a593Smuzhiyun * @nid: the node id to count from.
110*4882a593Smuzhiyun * @memcg: the cgroup to count from.
111*4882a593Smuzhiyun *
112*4882a593Smuzhiyun * Always return a non-negative number, 0 for empty lists. There is no
113*4882a593Smuzhiyun * guarantee that the list is not updated while the count is being computed.
114*4882a593Smuzhiyun * Callers that want such a guarantee need to provide an outer lock.
115*4882a593Smuzhiyun */
116*4882a593Smuzhiyun unsigned long list_lru_count_one(struct list_lru *lru,
117*4882a593Smuzhiyun int nid, struct mem_cgroup *memcg);
118*4882a593Smuzhiyun unsigned long list_lru_count_node(struct list_lru *lru, int nid);
119*4882a593Smuzhiyun
list_lru_shrink_count(struct list_lru * lru,struct shrink_control * sc)120*4882a593Smuzhiyun static inline unsigned long list_lru_shrink_count(struct list_lru *lru,
121*4882a593Smuzhiyun struct shrink_control *sc)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun return list_lru_count_one(lru, sc->nid, sc->memcg);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
list_lru_count(struct list_lru * lru)126*4882a593Smuzhiyun static inline unsigned long list_lru_count(struct list_lru *lru)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun long count = 0;
129*4882a593Smuzhiyun int nid;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun for_each_node_state(nid, N_NORMAL_MEMORY)
132*4882a593Smuzhiyun count += list_lru_count_node(lru, nid);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun return count;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun void list_lru_isolate(struct list_lru_one *list, struct list_head *item);
138*4882a593Smuzhiyun void list_lru_isolate_move(struct list_lru_one *list, struct list_head *item,
139*4882a593Smuzhiyun struct list_head *head);
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun typedef enum lru_status (*list_lru_walk_cb)(struct list_head *item,
142*4882a593Smuzhiyun struct list_lru_one *list, spinlock_t *lock, void *cb_arg);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /**
145*4882a593Smuzhiyun * list_lru_walk_one: walk a list_lru, isolating and disposing freeable items.
146*4882a593Smuzhiyun * @lru: the lru pointer.
147*4882a593Smuzhiyun * @nid: the node id to scan from.
148*4882a593Smuzhiyun * @memcg: the cgroup to scan from.
149*4882a593Smuzhiyun * @isolate: callback function that is resposible for deciding what to do with
150*4882a593Smuzhiyun * the item currently being scanned
151*4882a593Smuzhiyun * @cb_arg: opaque type that will be passed to @isolate
152*4882a593Smuzhiyun * @nr_to_walk: how many items to scan.
153*4882a593Smuzhiyun *
154*4882a593Smuzhiyun * This function will scan all elements in a particular list_lru, calling the
155*4882a593Smuzhiyun * @isolate callback for each of those items, along with the current list
156*4882a593Smuzhiyun * spinlock and a caller-provided opaque. The @isolate callback can choose to
157*4882a593Smuzhiyun * drop the lock internally, but *must* return with the lock held. The callback
158*4882a593Smuzhiyun * will return an enum lru_status telling the list_lru infrastructure what to
159*4882a593Smuzhiyun * do with the object being scanned.
160*4882a593Smuzhiyun *
161*4882a593Smuzhiyun * Please note that nr_to_walk does not mean how many objects will be freed,
162*4882a593Smuzhiyun * just how many objects will be scanned.
163*4882a593Smuzhiyun *
164*4882a593Smuzhiyun * Return value: the number of objects effectively removed from the LRU.
165*4882a593Smuzhiyun */
166*4882a593Smuzhiyun unsigned long list_lru_walk_one(struct list_lru *lru,
167*4882a593Smuzhiyun int nid, struct mem_cgroup *memcg,
168*4882a593Smuzhiyun list_lru_walk_cb isolate, void *cb_arg,
169*4882a593Smuzhiyun unsigned long *nr_to_walk);
170*4882a593Smuzhiyun /**
171*4882a593Smuzhiyun * list_lru_walk_one_irq: walk a list_lru, isolating and disposing freeable items.
172*4882a593Smuzhiyun * @lru: the lru pointer.
173*4882a593Smuzhiyun * @nid: the node id to scan from.
174*4882a593Smuzhiyun * @memcg: the cgroup to scan from.
175*4882a593Smuzhiyun * @isolate: callback function that is resposible for deciding what to do with
176*4882a593Smuzhiyun * the item currently being scanned
177*4882a593Smuzhiyun * @cb_arg: opaque type that will be passed to @isolate
178*4882a593Smuzhiyun * @nr_to_walk: how many items to scan.
179*4882a593Smuzhiyun *
180*4882a593Smuzhiyun * Same as @list_lru_walk_one except that the spinlock is acquired with
181*4882a593Smuzhiyun * spin_lock_irq().
182*4882a593Smuzhiyun */
183*4882a593Smuzhiyun unsigned long list_lru_walk_one_irq(struct list_lru *lru,
184*4882a593Smuzhiyun int nid, struct mem_cgroup *memcg,
185*4882a593Smuzhiyun list_lru_walk_cb isolate, void *cb_arg,
186*4882a593Smuzhiyun unsigned long *nr_to_walk);
187*4882a593Smuzhiyun unsigned long list_lru_walk_node(struct list_lru *lru, int nid,
188*4882a593Smuzhiyun list_lru_walk_cb isolate, void *cb_arg,
189*4882a593Smuzhiyun unsigned long *nr_to_walk);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun static inline unsigned long
list_lru_shrink_walk(struct list_lru * lru,struct shrink_control * sc,list_lru_walk_cb isolate,void * cb_arg)192*4882a593Smuzhiyun list_lru_shrink_walk(struct list_lru *lru, struct shrink_control *sc,
193*4882a593Smuzhiyun list_lru_walk_cb isolate, void *cb_arg)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun return list_lru_walk_one(lru, sc->nid, sc->memcg, isolate, cb_arg,
196*4882a593Smuzhiyun &sc->nr_to_scan);
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun static inline unsigned long
list_lru_shrink_walk_irq(struct list_lru * lru,struct shrink_control * sc,list_lru_walk_cb isolate,void * cb_arg)200*4882a593Smuzhiyun list_lru_shrink_walk_irq(struct list_lru *lru, struct shrink_control *sc,
201*4882a593Smuzhiyun list_lru_walk_cb isolate, void *cb_arg)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun return list_lru_walk_one_irq(lru, sc->nid, sc->memcg, isolate, cb_arg,
204*4882a593Smuzhiyun &sc->nr_to_scan);
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun static inline unsigned long
list_lru_walk(struct list_lru * lru,list_lru_walk_cb isolate,void * cb_arg,unsigned long nr_to_walk)208*4882a593Smuzhiyun list_lru_walk(struct list_lru *lru, list_lru_walk_cb isolate,
209*4882a593Smuzhiyun void *cb_arg, unsigned long nr_to_walk)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun long isolated = 0;
212*4882a593Smuzhiyun int nid;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun for_each_node_state(nid, N_NORMAL_MEMORY) {
215*4882a593Smuzhiyun isolated += list_lru_walk_node(lru, nid, isolate,
216*4882a593Smuzhiyun cb_arg, &nr_to_walk);
217*4882a593Smuzhiyun if (nr_to_walk <= 0)
218*4882a593Smuzhiyun break;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun return isolated;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun #endif /* _LRU_LIST_H */
223