xref: /OK3568_Linux_fs/kernel/mm/page_pinner.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <linux/debugfs.h>
3*4882a593Smuzhiyun #include <linux/mm.h>
4*4882a593Smuzhiyun #include <linux/slab.h>
5*4882a593Smuzhiyun #include <linux/uaccess.h>
6*4882a593Smuzhiyun #include <linux/memblock.h>
7*4882a593Smuzhiyun #include <linux/stacktrace.h>
8*4882a593Smuzhiyun #include <linux/page_pinner.h>
9*4882a593Smuzhiyun #include <linux/jump_label.h>
10*4882a593Smuzhiyun #include <linux/migrate.h>
11*4882a593Smuzhiyun #include <linux/stackdepot.h>
12*4882a593Smuzhiyun #include <linux/seq_file.h>
13*4882a593Smuzhiyun #include <linux/sched/clock.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "internal.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define PAGE_PINNER_STACK_DEPTH 16
18*4882a593Smuzhiyun #define LONGTERM_PIN_BUCKETS	4096
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun struct page_pinner {
21*4882a593Smuzhiyun 	depot_stack_handle_t handle;
22*4882a593Smuzhiyun 	s64 ts_usec;
23*4882a593Smuzhiyun 	atomic_t count;
24*4882a593Smuzhiyun };
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun struct captured_pinner {
27*4882a593Smuzhiyun 	depot_stack_handle_t handle;
28*4882a593Smuzhiyun 	union {
29*4882a593Smuzhiyun 		s64 ts_usec;
30*4882a593Smuzhiyun 		s64 elapsed;
31*4882a593Smuzhiyun 	};
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	/* struct page fields */
34*4882a593Smuzhiyun 	unsigned long pfn;
35*4882a593Smuzhiyun 	int count;
36*4882a593Smuzhiyun 	int mapcount;
37*4882a593Smuzhiyun 	struct address_space *mapping;
38*4882a593Smuzhiyun 	unsigned long flags;
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun struct longterm_pinner {
42*4882a593Smuzhiyun 	spinlock_t lock;
43*4882a593Smuzhiyun 	unsigned int index;
44*4882a593Smuzhiyun 	struct captured_pinner pinner[LONGTERM_PIN_BUCKETS];
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun static struct longterm_pinner lt_pinner = {
48*4882a593Smuzhiyun 	.lock = __SPIN_LOCK_UNLOCKED(lt_pinner.lock),
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun static s64 threshold_usec = 300000;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun /* alloc_contig failed pinner */
54*4882a593Smuzhiyun static struct longterm_pinner acf_pinner = {
55*4882a593Smuzhiyun 	.lock = __SPIN_LOCK_UNLOCKED(acf_pinner.lock),
56*4882a593Smuzhiyun };
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun static bool page_pinner_enabled;
59*4882a593Smuzhiyun DEFINE_STATIC_KEY_FALSE(page_pinner_inited);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun DEFINE_STATIC_KEY_TRUE(failure_tracking);
62*4882a593Smuzhiyun EXPORT_SYMBOL(failure_tracking);
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun static depot_stack_handle_t failure_handle;
65*4882a593Smuzhiyun 
early_page_pinner_param(char * buf)66*4882a593Smuzhiyun static int __init early_page_pinner_param(char *buf)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	page_pinner_enabled = true;
69*4882a593Smuzhiyun 	return 0;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun early_param("page_pinner", early_page_pinner_param);
72*4882a593Smuzhiyun 
need_page_pinner(void)73*4882a593Smuzhiyun static bool need_page_pinner(void)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	return page_pinner_enabled;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun 
register_failure_stack(void)78*4882a593Smuzhiyun static noinline void register_failure_stack(void)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	unsigned long entries[4];
81*4882a593Smuzhiyun 	unsigned int nr_entries;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 0);
84*4882a593Smuzhiyun 	failure_handle = stack_depot_save(entries, nr_entries, GFP_KERNEL);
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
init_page_pinner(void)87*4882a593Smuzhiyun static void init_page_pinner(void)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	if (!page_pinner_enabled)
90*4882a593Smuzhiyun 		return;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	register_failure_stack();
93*4882a593Smuzhiyun 	static_branch_enable(&page_pinner_inited);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun struct page_ext_operations page_pinner_ops = {
97*4882a593Smuzhiyun 	.size = sizeof(struct page_pinner),
98*4882a593Smuzhiyun 	.need = need_page_pinner,
99*4882a593Smuzhiyun 	.init = init_page_pinner,
100*4882a593Smuzhiyun };
101*4882a593Smuzhiyun 
get_page_pinner(struct page_ext * page_ext)102*4882a593Smuzhiyun static inline struct page_pinner *get_page_pinner(struct page_ext *page_ext)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	return (void *)page_ext + page_pinner_ops.offset;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun 
save_stack(gfp_t flags)107*4882a593Smuzhiyun static noinline depot_stack_handle_t save_stack(gfp_t flags)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	unsigned long entries[PAGE_PINNER_STACK_DEPTH];
110*4882a593Smuzhiyun 	depot_stack_handle_t handle;
111*4882a593Smuzhiyun 	unsigned int nr_entries;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 2);
114*4882a593Smuzhiyun 	handle = stack_depot_save(entries, nr_entries, flags);
115*4882a593Smuzhiyun 	if (!handle)
116*4882a593Smuzhiyun 		handle = failure_handle;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	return handle;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun 
capture_page_state(struct page * page,struct captured_pinner * record)121*4882a593Smuzhiyun static void capture_page_state(struct page *page,
122*4882a593Smuzhiyun 			       struct captured_pinner *record)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	record->flags = page->flags;
125*4882a593Smuzhiyun 	record->mapping = page_mapping(page);
126*4882a593Smuzhiyun 	record->pfn = page_to_pfn(page);
127*4882a593Smuzhiyun 	record->count = page_count(page);
128*4882a593Smuzhiyun 	record->mapcount = page_mapcount(page);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
check_longterm_pin(struct page_pinner * page_pinner,struct page * page)131*4882a593Smuzhiyun static void check_longterm_pin(struct page_pinner *page_pinner,
132*4882a593Smuzhiyun 			      struct page *page)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	s64 now, delta = 0;
135*4882a593Smuzhiyun 	unsigned long flags;
136*4882a593Smuzhiyun 	unsigned int idx;
137*4882a593Smuzhiyun 	struct captured_pinner record;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	now = ktime_to_us(ktime_get_boottime());
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	/* get/put_page can be raced. Ignore that case */
142*4882a593Smuzhiyun 	if (page_pinner->ts_usec < now)
143*4882a593Smuzhiyun 		delta = now - page_pinner->ts_usec;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	if (delta <= threshold_usec)
146*4882a593Smuzhiyun 		return;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	record.handle = page_pinner->handle;
149*4882a593Smuzhiyun 	record.elapsed = delta;
150*4882a593Smuzhiyun 	capture_page_state(page, &record);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	spin_lock_irqsave(&lt_pinner.lock, flags);
153*4882a593Smuzhiyun 	idx = lt_pinner.index++;
154*4882a593Smuzhiyun 	lt_pinner.index %= LONGTERM_PIN_BUCKETS;
155*4882a593Smuzhiyun 	lt_pinner.pinner[idx] = record;
156*4882a593Smuzhiyun 	spin_unlock_irqrestore(&lt_pinner.lock, flags);
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
__reset_page_pinner(struct page * page,unsigned int order,bool free)159*4882a593Smuzhiyun void __reset_page_pinner(struct page *page, unsigned int order, bool free)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun 	struct page_pinner *page_pinner;
162*4882a593Smuzhiyun 	struct page_ext *page_ext;
163*4882a593Smuzhiyun 	int i;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	page_ext = page_ext_get(page);
166*4882a593Smuzhiyun 	if (unlikely(!page_ext))
167*4882a593Smuzhiyun 		return;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	for (i = 0; i < (1 << order); i++) {
170*4882a593Smuzhiyun 		if (!test_bit(PAGE_EXT_GET, &page_ext->flags) &&
171*4882a593Smuzhiyun 			!test_bit(PAGE_EXT_PINNER_MIGRATION_FAILED,
172*4882a593Smuzhiyun 				  &page_ext->flags))
173*4882a593Smuzhiyun 			continue;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 		page_pinner = get_page_pinner(page_ext);
176*4882a593Smuzhiyun 		if (free) {
177*4882a593Smuzhiyun 			/* record page free call path */
178*4882a593Smuzhiyun 			__page_pinner_migration_failed(page);
179*4882a593Smuzhiyun 			atomic_set(&page_pinner->count, 0);
180*4882a593Smuzhiyun 			__clear_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags);
181*4882a593Smuzhiyun 		} else {
182*4882a593Smuzhiyun 			check_longterm_pin(page_pinner, page);
183*4882a593Smuzhiyun 		}
184*4882a593Smuzhiyun 		clear_bit(PAGE_EXT_GET, &page_ext->flags);
185*4882a593Smuzhiyun 		page_ext = page_ext_next(page_ext);
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 	page_ext_put(page_ext);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
__set_page_pinner_handle(struct page * page,struct page_ext * page_ext,depot_stack_handle_t handle,unsigned int order)190*4882a593Smuzhiyun static inline void __set_page_pinner_handle(struct page *page,
191*4882a593Smuzhiyun 	struct page_ext *page_ext, depot_stack_handle_t handle,
192*4882a593Smuzhiyun 	unsigned int order)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	struct page_pinner *page_pinner;
195*4882a593Smuzhiyun 	int i;
196*4882a593Smuzhiyun 	s64 usec = ktime_to_us(ktime_get_boottime());
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	for (i = 0; i < (1 << order); i++) {
199*4882a593Smuzhiyun 		page_pinner = get_page_pinner(page_ext);
200*4882a593Smuzhiyun 		page_pinner->handle = handle;
201*4882a593Smuzhiyun 		page_pinner->ts_usec = usec;
202*4882a593Smuzhiyun 		set_bit(PAGE_EXT_GET, &page_ext->flags);
203*4882a593Smuzhiyun 		atomic_inc(&page_pinner->count);
204*4882a593Smuzhiyun 		page_ext = page_ext_next(page_ext);
205*4882a593Smuzhiyun 	}
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
__set_page_pinner(struct page * page,unsigned int order)208*4882a593Smuzhiyun noinline void __set_page_pinner(struct page *page, unsigned int order)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	struct page_ext *page_ext;
211*4882a593Smuzhiyun 	depot_stack_handle_t handle;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	handle = save_stack(GFP_NOWAIT|__GFP_NOWARN);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	page_ext = page_ext_get(page);
216*4882a593Smuzhiyun 	if (unlikely(!page_ext))
217*4882a593Smuzhiyun 		return;
218*4882a593Smuzhiyun 	__set_page_pinner_handle(page, page_ext, handle, order);
219*4882a593Smuzhiyun 	page_ext_put(page_ext);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun static ssize_t
print_page_pinner(bool longterm,char __user * buf,size_t count,struct captured_pinner * record)223*4882a593Smuzhiyun print_page_pinner(bool longterm, char __user *buf, size_t count, struct captured_pinner *record)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun 	int ret;
226*4882a593Smuzhiyun 	unsigned long *entries;
227*4882a593Smuzhiyun 	unsigned int nr_entries;
228*4882a593Smuzhiyun 	char *kbuf;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	count = min_t(size_t, count, PAGE_SIZE);
231*4882a593Smuzhiyun 	kbuf = kmalloc(count, GFP_KERNEL);
232*4882a593Smuzhiyun 	if (!kbuf)
233*4882a593Smuzhiyun 		return -ENOMEM;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	if (longterm) {
236*4882a593Smuzhiyun 		ret = snprintf(kbuf, count, "Page pinned for %lld us\n",
237*4882a593Smuzhiyun 			       record->elapsed);
238*4882a593Smuzhiyun 	} else {
239*4882a593Smuzhiyun 		u64 ts_usec = record->ts_usec;
240*4882a593Smuzhiyun 		unsigned long rem_usec = do_div(ts_usec, 1000000);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 		ret = snprintf(kbuf, count,
243*4882a593Smuzhiyun 			       "Page pinned ts [%5lu.%06lu]\n",
244*4882a593Smuzhiyun 			       (unsigned long)ts_usec, rem_usec);
245*4882a593Smuzhiyun 	}
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	if (ret >= count)
248*4882a593Smuzhiyun 		goto err;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	/* Print information relevant to grouping pages by mobility */
251*4882a593Smuzhiyun 	ret += snprintf(kbuf + ret, count - ret,
252*4882a593Smuzhiyun 			"PFN 0x%lx Block %lu count %d mapcount %d mapping %pS Flags %#lx(%pGp)\n",
253*4882a593Smuzhiyun 			record->pfn,
254*4882a593Smuzhiyun 			record->pfn >> pageblock_order,
255*4882a593Smuzhiyun 			record->count, record->mapcount,
256*4882a593Smuzhiyun 			record->mapping,
257*4882a593Smuzhiyun 			record->flags, &record->flags);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	if (ret >= count)
260*4882a593Smuzhiyun 		goto err;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	nr_entries = stack_depot_fetch(record->handle, &entries);
263*4882a593Smuzhiyun 	ret += stack_trace_snprint(kbuf + ret, count - ret, entries,
264*4882a593Smuzhiyun 				   nr_entries, 0);
265*4882a593Smuzhiyun 	if (ret >= count)
266*4882a593Smuzhiyun 		goto err;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	ret += snprintf(kbuf + ret, count - ret, "\n");
269*4882a593Smuzhiyun 	if (ret >= count)
270*4882a593Smuzhiyun 		goto err;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	if (copy_to_user(buf, kbuf, ret))
273*4882a593Smuzhiyun 		ret = -EFAULT;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	kfree(kbuf);
276*4882a593Smuzhiyun 	return ret;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun err:
279*4882a593Smuzhiyun 	kfree(kbuf);
280*4882a593Smuzhiyun 	return -ENOMEM;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun 
__dump_page_pinner(struct page * page)283*4882a593Smuzhiyun void __dump_page_pinner(struct page *page)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun 	struct page_ext *page_ext = page_ext_get(page);
286*4882a593Smuzhiyun 	struct page_pinner *page_pinner;
287*4882a593Smuzhiyun 	depot_stack_handle_t handle;
288*4882a593Smuzhiyun 	unsigned long *entries;
289*4882a593Smuzhiyun 	unsigned int nr_entries;
290*4882a593Smuzhiyun 	int pageblock_mt;
291*4882a593Smuzhiyun 	unsigned long pfn;
292*4882a593Smuzhiyun 	int count;
293*4882a593Smuzhiyun 	unsigned long rem_usec;
294*4882a593Smuzhiyun 	u64 ts_usec;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	if (unlikely(!page_ext)) {
297*4882a593Smuzhiyun 		pr_alert("There is not page extension available.\n");
298*4882a593Smuzhiyun 		return;
299*4882a593Smuzhiyun 	}
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	page_pinner = get_page_pinner(page_ext);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	count = atomic_read(&page_pinner->count);
304*4882a593Smuzhiyun 	if (!count) {
305*4882a593Smuzhiyun 		pr_alert("page_pinner info is not present (never set?)\n");
306*4882a593Smuzhiyun 		page_ext_put(page_ext);
307*4882a593Smuzhiyun 		return;
308*4882a593Smuzhiyun 	}
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	pfn = page_to_pfn(page);
311*4882a593Smuzhiyun 	ts_usec = page_pinner->ts_usec;
312*4882a593Smuzhiyun 	rem_usec = do_div(ts_usec, 1000000);
313*4882a593Smuzhiyun 	pr_alert("page last pinned %5lu.%06lu] count %d\n",
314*4882a593Smuzhiyun 		 (unsigned long)ts_usec, rem_usec, count);
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	pageblock_mt = get_pageblock_migratetype(page);
317*4882a593Smuzhiyun 	pr_alert("PFN %lu Block %lu type %s Flags %#lx(%pGp)\n",
318*4882a593Smuzhiyun 			pfn,
319*4882a593Smuzhiyun 			pfn >> pageblock_order,
320*4882a593Smuzhiyun 			migratetype_names[pageblock_mt],
321*4882a593Smuzhiyun 			page->flags, &page->flags);
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	handle = READ_ONCE(page_pinner->handle);
324*4882a593Smuzhiyun 	if (!handle) {
325*4882a593Smuzhiyun 		pr_alert("page_pinner allocation stack trace missing\n");
326*4882a593Smuzhiyun 	} else {
327*4882a593Smuzhiyun 		nr_entries = stack_depot_fetch(handle, &entries);
328*4882a593Smuzhiyun 		stack_trace_print(entries, nr_entries, 0);
329*4882a593Smuzhiyun 	}
330*4882a593Smuzhiyun 	page_ext_put(page_ext);
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun 
__page_pinner_migration_failed(struct page * page)333*4882a593Smuzhiyun void __page_pinner_migration_failed(struct page *page)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun 	struct page_ext *page_ext = page_ext_get(page);
336*4882a593Smuzhiyun 	struct captured_pinner record;
337*4882a593Smuzhiyun 	unsigned long flags;
338*4882a593Smuzhiyun 	unsigned int idx;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	if (unlikely(!page_ext))
341*4882a593Smuzhiyun 		return;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	if (!test_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags)) {
344*4882a593Smuzhiyun 		page_ext_put(page_ext);
345*4882a593Smuzhiyun 		return;
346*4882a593Smuzhiyun 	}
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	page_ext_put(page_ext);
349*4882a593Smuzhiyun 	record.handle = save_stack(GFP_NOWAIT|__GFP_NOWARN);
350*4882a593Smuzhiyun 	record.ts_usec = ktime_to_us(ktime_get_boottime());
351*4882a593Smuzhiyun 	capture_page_state(page, &record);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	spin_lock_irqsave(&acf_pinner.lock, flags);
354*4882a593Smuzhiyun 	idx = acf_pinner.index++;
355*4882a593Smuzhiyun 	acf_pinner.index %= LONGTERM_PIN_BUCKETS;
356*4882a593Smuzhiyun 	acf_pinner.pinner[idx] = record;
357*4882a593Smuzhiyun 	spin_unlock_irqrestore(&acf_pinner.lock, flags);
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun EXPORT_SYMBOL(__page_pinner_migration_failed);
360*4882a593Smuzhiyun 
__page_pinner_mark_migration_failed_pages(struct list_head * page_list)361*4882a593Smuzhiyun void __page_pinner_mark_migration_failed_pages(struct list_head *page_list)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun 	struct page *page;
364*4882a593Smuzhiyun 	struct page_ext *page_ext;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	list_for_each_entry(page, page_list, lru) {
367*4882a593Smuzhiyun 		/* The page will be freed by putback_movable_pages soon */
368*4882a593Smuzhiyun 		if (page_count(page) == 1)
369*4882a593Smuzhiyun 			continue;
370*4882a593Smuzhiyun 		page_ext = page_ext_get(page);
371*4882a593Smuzhiyun 		if (unlikely(!page_ext))
372*4882a593Smuzhiyun 			continue;
373*4882a593Smuzhiyun 		__set_bit(PAGE_EXT_PINNER_MIGRATION_FAILED, &page_ext->flags);
374*4882a593Smuzhiyun 		page_ext_put(page_ext);
375*4882a593Smuzhiyun 		__page_pinner_migration_failed(page);
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun static ssize_t
read_longterm_page_pinner(struct file * file,char __user * buf,size_t count,loff_t * ppos)380*4882a593Smuzhiyun read_longterm_page_pinner(struct file *file, char __user *buf, size_t count,
381*4882a593Smuzhiyun 			  loff_t *ppos)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun 	loff_t i, idx;
384*4882a593Smuzhiyun 	struct captured_pinner record;
385*4882a593Smuzhiyun 	unsigned long flags;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	if (!static_branch_unlikely(&page_pinner_inited))
388*4882a593Smuzhiyun 		return -EINVAL;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	if (*ppos >= LONGTERM_PIN_BUCKETS)
391*4882a593Smuzhiyun 		return 0;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	i = *ppos;
394*4882a593Smuzhiyun 	*ppos = i + 1;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	/*
397*4882a593Smuzhiyun 	 * reading the records in the reverse order with newest one
398*4882a593Smuzhiyun 	 * being read first followed by older ones
399*4882a593Smuzhiyun 	 */
400*4882a593Smuzhiyun 	idx = (lt_pinner.index - 1 - i + LONGTERM_PIN_BUCKETS) %
401*4882a593Smuzhiyun 	       LONGTERM_PIN_BUCKETS;
402*4882a593Smuzhiyun 	spin_lock_irqsave(&lt_pinner.lock, flags);
403*4882a593Smuzhiyun 	record = lt_pinner.pinner[idx];
404*4882a593Smuzhiyun 	spin_unlock_irqrestore(&lt_pinner.lock, flags);
405*4882a593Smuzhiyun 	if (!record.handle)
406*4882a593Smuzhiyun 		return 0;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	return print_page_pinner(true, buf, count, &record);
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun static const struct file_operations proc_longterm_pinner_operations = {
412*4882a593Smuzhiyun 	.read		= read_longterm_page_pinner,
413*4882a593Smuzhiyun };
414*4882a593Smuzhiyun 
read_alloc_contig_failed(struct file * file,char __user * buf,size_t count,loff_t * ppos)415*4882a593Smuzhiyun static ssize_t read_alloc_contig_failed(struct file *file, char __user *buf,
416*4882a593Smuzhiyun 					size_t count, loff_t *ppos)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun 	loff_t i, idx;
419*4882a593Smuzhiyun 	struct captured_pinner record;
420*4882a593Smuzhiyun 	unsigned long flags;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	if (!static_branch_unlikely(&failure_tracking))
423*4882a593Smuzhiyun 		return -EINVAL;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	if (*ppos >= LONGTERM_PIN_BUCKETS)
426*4882a593Smuzhiyun 		return 0;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	i = *ppos;
429*4882a593Smuzhiyun 	*ppos = i + 1;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	/*
432*4882a593Smuzhiyun 	 * reading the records in the reverse order with newest one
433*4882a593Smuzhiyun 	 * being read first followed by older ones
434*4882a593Smuzhiyun 	 */
435*4882a593Smuzhiyun 	idx = (acf_pinner.index - 1 - i + LONGTERM_PIN_BUCKETS) %
436*4882a593Smuzhiyun 	       LONGTERM_PIN_BUCKETS;
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	spin_lock_irqsave(&acf_pinner.lock, flags);
439*4882a593Smuzhiyun 	record = acf_pinner.pinner[idx];
440*4882a593Smuzhiyun 	spin_unlock_irqrestore(&acf_pinner.lock, flags);
441*4882a593Smuzhiyun 	if (!record.handle)
442*4882a593Smuzhiyun 		return 0;
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	return print_page_pinner(false, buf, count, &record);
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun static const struct file_operations proc_alloc_contig_failed_operations = {
448*4882a593Smuzhiyun 	.read		= read_alloc_contig_failed,
449*4882a593Smuzhiyun };
450*4882a593Smuzhiyun 
pp_threshold_set(void * data,unsigned long long val)451*4882a593Smuzhiyun static int pp_threshold_set(void *data, unsigned long long val)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun 	unsigned long flags;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	threshold_usec = (s64)val;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	spin_lock_irqsave(&lt_pinner.lock, flags);
458*4882a593Smuzhiyun 	memset(lt_pinner.pinner, 0,
459*4882a593Smuzhiyun 	       sizeof(struct captured_pinner) * LONGTERM_PIN_BUCKETS);
460*4882a593Smuzhiyun 	lt_pinner.index = 0;
461*4882a593Smuzhiyun 	spin_unlock_irqrestore(&lt_pinner.lock, flags);
462*4882a593Smuzhiyun 	return 0;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun 
pp_threshold_get(void * data,unsigned long long * val)465*4882a593Smuzhiyun static int pp_threshold_get(void *data, unsigned long long *val)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun 	*val = (unsigned long long)threshold_usec;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	return 0;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun DEFINE_DEBUGFS_ATTRIBUTE(pp_threshold_fops, pp_threshold_get,
472*4882a593Smuzhiyun 			 pp_threshold_set, "%lld\n");
473*4882a593Smuzhiyun 
failure_tracking_set(void * data,u64 val)474*4882a593Smuzhiyun static int failure_tracking_set(void *data, u64 val)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun 	bool on;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	on = (bool)val;
479*4882a593Smuzhiyun 	if (on)
480*4882a593Smuzhiyun 		static_branch_enable(&failure_tracking);
481*4882a593Smuzhiyun 	else
482*4882a593Smuzhiyun 		static_branch_disable(&failure_tracking);
483*4882a593Smuzhiyun 	return 0;
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun 
failure_tracking_get(void * data,u64 * val)486*4882a593Smuzhiyun static int failure_tracking_get(void *data, u64 *val)
487*4882a593Smuzhiyun {
488*4882a593Smuzhiyun 	*val = static_branch_unlikely(&failure_tracking);
489*4882a593Smuzhiyun 	return 0;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun DEFINE_DEBUGFS_ATTRIBUTE(failure_tracking_fops,
492*4882a593Smuzhiyun 			 failure_tracking_get,
493*4882a593Smuzhiyun 			 failure_tracking_set, "%llu\n");
494*4882a593Smuzhiyun 
page_pinner_init(void)495*4882a593Smuzhiyun static int __init page_pinner_init(void)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun 	struct dentry *pp_debugfs_root;
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	if (!static_branch_unlikely(&page_pinner_inited))
500*4882a593Smuzhiyun 		return 0;
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	pr_info("page_pinner enabled\n");
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	pp_debugfs_root = debugfs_create_dir("page_pinner", NULL);
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	debugfs_create_file("longterm_pinner", 0444, pp_debugfs_root, NULL,
507*4882a593Smuzhiyun 			    &proc_longterm_pinner_operations);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	debugfs_create_file("threshold", 0644, pp_debugfs_root, NULL,
510*4882a593Smuzhiyun 			    &pp_threshold_fops);
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	debugfs_create_file("alloc_contig_failed", 0444,
513*4882a593Smuzhiyun 			    pp_debugfs_root, NULL,
514*4882a593Smuzhiyun 			    &proc_alloc_contig_failed_operations);
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	debugfs_create_file("failure_tracking", 0644,
517*4882a593Smuzhiyun 			    pp_debugfs_root, NULL,
518*4882a593Smuzhiyun 			    &failure_tracking_fops);
519*4882a593Smuzhiyun 	return 0;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun late_initcall(page_pinner_init)
522