xref: /OK3568_Linux_fs/kernel/include/linux/list_lru.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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