]> git.ipfire.org Git - thirdparty/kernel/linux.git/blame - drivers/staging/android/ion/ion_page_pool.c
mm: rename and change semantics of nr_indirectly_reclaimable_bytes
[thirdparty/kernel/linux.git] / drivers / staging / android / ion / ion_page_pool.c
CommitLineData
bdcb7be6 1// SPDX-License-Identifier: GPL-2.0
0214c7f2
RSZ
2/*
3 * drivers/staging/android/ion/ion_mem_pool.c
4 *
5 * Copyright (C) 2011 Google, Inc.
0214c7f2
RSZ
6 */
7
0214c7f2
RSZ
8#include <linux/list.h>
9#include <linux/slab.h>
0cd2dc4d 10#include <linux/swap.h>
eb9751db
LA
11
12#include "ion.h"
0214c7f2 13
acb42f8e 14static inline struct page *ion_page_pool_alloc_pages(struct ion_page_pool *pool)
0214c7f2 15{
acb42f8e 16 return alloc_pages(pool->gfp_mask, pool->order);
0214c7f2
RSZ
17}
18
19static void ion_page_pool_free_pages(struct ion_page_pool *pool,
20 struct page *page)
21{
22 __free_pages(page, pool->order);
23}
24
70ea629b 25static void ion_page_pool_add(struct ion_page_pool *pool, struct page *page)
0214c7f2 26{
efee5a0c 27 mutex_lock(&pool->mutex);
0fb9b815 28 if (PageHighMem(page)) {
38c003b1 29 list_add_tail(&page->lru, &pool->high_items);
0fb9b815
RSZ
30 pool->high_count++;
31 } else {
38c003b1 32 list_add_tail(&page->lru, &pool->low_items);
0fb9b815
RSZ
33 pool->low_count++;
34 }
548cbba1 35
b29940c1
VB
36 mod_node_page_state(page_pgdat(page), NR_KERNEL_MISC_RECLAIMABLE,
37 1 << pool->order);
efee5a0c 38 mutex_unlock(&pool->mutex);
0214c7f2
RSZ
39}
40
0fb9b815 41static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high)
0214c7f2 42{
0214c7f2
RSZ
43 struct page *page;
44
0fb9b815
RSZ
45 if (high) {
46 BUG_ON(!pool->high_count);
38c003b1 47 page = list_first_entry(&pool->high_items, struct page, lru);
0fb9b815
RSZ
48 pool->high_count--;
49 } else {
50 BUG_ON(!pool->low_count);
38c003b1 51 page = list_first_entry(&pool->low_items, struct page, lru);
0fb9b815
RSZ
52 pool->low_count--;
53 }
0214c7f2 54
38c003b1 55 list_del(&page->lru);
b29940c1
VB
56 mod_node_page_state(page_pgdat(page), NR_KERNEL_MISC_RECLAIMABLE,
57 -(1 << pool->order));
0214c7f2
RSZ
58 return page;
59}
60
79240748 61struct page *ion_page_pool_alloc(struct ion_page_pool *pool)
0214c7f2
RSZ
62{
63 struct page *page = NULL;
64
65 BUG_ON(!pool);
66
67 mutex_lock(&pool->mutex);
0fb9b815
RSZ
68 if (pool->high_count)
69 page = ion_page_pool_remove(pool, true);
70 else if (pool->low_count)
71 page = ion_page_pool_remove(pool, false);
0214c7f2
RSZ
72 mutex_unlock(&pool->mutex);
73
0fb9b815
RSZ
74 if (!page)
75 page = ion_page_pool_alloc_pages(pool);
76
0214c7f2
RSZ
77 return page;
78}
79
e1d855b0 80void ion_page_pool_free(struct ion_page_pool *pool, struct page *page)
0214c7f2 81{
bdeb9f1c
HS
82 BUG_ON(pool->order != compound_order(page));
83
a3f75c43 84 ion_page_pool_add(pool, page);
0214c7f2
RSZ
85}
86
ea313b5f 87static int ion_page_pool_total(struct ion_page_pool *pool, bool high)
797a95c4 88{
80cb77dc 89 int count = pool->low_count;
797a95c4 90
80cb77dc
HS
91 if (high)
92 count += pool->high_count;
93
94 return count << pool->order;
797a95c4
RSZ
95}
96
ea313b5f 97int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask,
679011bd 98 int nr_to_scan)
0214c7f2 99{
b44d9ce3 100 int freed = 0;
0fb9b815
RSZ
101 bool high;
102
0cd2dc4d 103 if (current_is_kswapd())
17fbab1e 104 high = true;
0cd2dc4d
HS
105 else
106 high = !!(gfp_mask & __GFP_HIGHMEM);
0214c7f2 107
797a95c4 108 if (nr_to_scan == 0)
ea313b5f
RSZ
109 return ion_page_pool_total(pool, high);
110
b44d9ce3 111 while (freed < nr_to_scan) {
ea313b5f
RSZ
112 struct page *page;
113
114 mutex_lock(&pool->mutex);
ce3d1093 115 if (pool->low_count) {
ea313b5f 116 page = ion_page_pool_remove(pool, false);
ce3d1093
CC
117 } else if (high && pool->high_count) {
118 page = ion_page_pool_remove(pool, true);
ea313b5f 119 } else {
0fb9b815 120 mutex_unlock(&pool->mutex);
ea313b5f 121 break;
0214c7f2 122 }
ea313b5f
RSZ
123 mutex_unlock(&pool->mutex);
124 ion_page_pool_free_pages(pool, page);
b44d9ce3 125 freed += (1 << pool->order);
0214c7f2 126 }
0214c7f2 127
b9daf0b6 128 return freed;
0214c7f2
RSZ
129}
130
d92a1fab 131struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
0214c7f2 132{
8fb78ad6
BM
133 struct ion_page_pool *pool = kmalloc(sizeof(*pool), GFP_KERNEL);
134
0214c7f2
RSZ
135 if (!pool)
136 return NULL;
0fb9b815
RSZ
137 pool->high_count = 0;
138 pool->low_count = 0;
139 INIT_LIST_HEAD(&pool->low_items);
140 INIT_LIST_HEAD(&pool->high_items);
bdeb9f1c 141 pool->gfp_mask = gfp_mask | __GFP_COMP;
0214c7f2
RSZ
142 pool->order = order;
143 mutex_init(&pool->mutex);
797a95c4 144 plist_node_init(&pool->list, order);
0214c7f2
RSZ
145
146 return pool;
147}
148
149void ion_page_pool_destroy(struct ion_page_pool *pool)
150{
0214c7f2
RSZ
151 kfree(pool);
152}