aboutsummaryrefslogtreecommitdiffstats
path: root/mm/frontswap.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/frontswap.c')
-rw-r--r--mm/frontswap.c150
1 files changed, 90 insertions, 60 deletions
diff --git a/mm/frontswap.c b/mm/frontswap.c
index e25025574a0..6b3e71a2cd4 100644
--- a/mm/frontswap.c
+++ b/mm/frontswap.c
@@ -11,15 +11,11 @@
11 * This work is licensed under the terms of the GNU GPL, version 2. 11 * This work is licensed under the terms of the GNU GPL, version 2.
12 */ 12 */
13 13
14#include <linux/mm.h>
15#include <linux/mman.h> 14#include <linux/mman.h>
16#include <linux/swap.h> 15#include <linux/swap.h>
17#include <linux/swapops.h> 16#include <linux/swapops.h>
18#include <linux/proc_fs.h>
19#include <linux/security.h> 17#include <linux/security.h>
20#include <linux/capability.h>
21#include <linux/module.h> 18#include <linux/module.h>
22#include <linux/uaccess.h>
23#include <linux/debugfs.h> 19#include <linux/debugfs.h>
24#include <linux/frontswap.h> 20#include <linux/frontswap.h>
25#include <linux/swapfile.h> 21#include <linux/swapfile.h>
@@ -110,16 +106,21 @@ void __frontswap_init(unsigned type)
110 BUG_ON(sis == NULL); 106 BUG_ON(sis == NULL);
111 if (sis->frontswap_map == NULL) 107 if (sis->frontswap_map == NULL)
112 return; 108 return;
113 if (frontswap_enabled) 109 frontswap_ops.init(type);
114 (*frontswap_ops.init)(type);
115} 110}
116EXPORT_SYMBOL(__frontswap_init); 111EXPORT_SYMBOL(__frontswap_init);
117 112
113static inline void __frontswap_clear(struct swap_info_struct *sis, pgoff_t offset)
114{
115 frontswap_clear(sis, offset);
116 atomic_dec(&sis->frontswap_pages);
117}
118
118/* 119/*
119 * "Store" data from a page to frontswap and associate it with the page's 120 * "Store" data from a page to frontswap and associate it with the page's
120 * swaptype and offset. Page must be locked and in the swap cache. 121 * swaptype and offset. Page must be locked and in the swap cache.
121 * If frontswap already contains a page with matching swaptype and 122 * If frontswap already contains a page with matching swaptype and
122 * offset, the frontswap implmentation may either overwrite the data and 123 * offset, the frontswap implementation may either overwrite the data and
123 * return success or invalidate the page from frontswap and return failure. 124 * return success or invalidate the page from frontswap and return failure.
124 */ 125 */
125int __frontswap_store(struct page *page) 126int __frontswap_store(struct page *page)
@@ -134,22 +135,21 @@ int __frontswap_store(struct page *page)
134 BUG_ON(sis == NULL); 135 BUG_ON(sis == NULL);
135 if (frontswap_test(sis, offset)) 136 if (frontswap_test(sis, offset))
136 dup = 1; 137 dup = 1;
137 ret = (*frontswap_ops.store)(type, offset, page); 138 ret = frontswap_ops.store(type, offset, page);
138 if (ret == 0) { 139 if (ret == 0) {
139 frontswap_set(sis, offset); 140 frontswap_set(sis, offset);
140 inc_frontswap_succ_stores(); 141 inc_frontswap_succ_stores();
141 if (!dup) 142 if (!dup)
142 atomic_inc(&sis->frontswap_pages); 143 atomic_inc(&sis->frontswap_pages);
143 } else if (dup) { 144 } else {
144 /* 145 /*
145 failed dup always results in automatic invalidate of 146 failed dup always results in automatic invalidate of
146 the (older) page from frontswap 147 the (older) page from frontswap
147 */ 148 */
148 frontswap_clear(sis, offset);
149 atomic_dec(&sis->frontswap_pages);
150 inc_frontswap_failed_stores();
151 } else
152 inc_frontswap_failed_stores(); 149 inc_frontswap_failed_stores();
150 if (dup)
151 __frontswap_clear(sis, offset);
152 }
153 if (frontswap_writethrough_enabled) 153 if (frontswap_writethrough_enabled)
154 /* report failure so swap also writes to swap device */ 154 /* report failure so swap also writes to swap device */
155 ret = -1; 155 ret = -1;
@@ -173,7 +173,7 @@ int __frontswap_load(struct page *page)
173 BUG_ON(!PageLocked(page)); 173 BUG_ON(!PageLocked(page));
174 BUG_ON(sis == NULL); 174 BUG_ON(sis == NULL);
175 if (frontswap_test(sis, offset)) 175 if (frontswap_test(sis, offset))
176 ret = (*frontswap_ops.load)(type, offset, page); 176 ret = frontswap_ops.load(type, offset, page);
177 if (ret == 0) 177 if (ret == 0)
178 inc_frontswap_loads(); 178 inc_frontswap_loads();
179 return ret; 179 return ret;
@@ -190,9 +190,8 @@ void __frontswap_invalidate_page(unsigned type, pgoff_t offset)
190 190
191 BUG_ON(sis == NULL); 191 BUG_ON(sis == NULL);
192 if (frontswap_test(sis, offset)) { 192 if (frontswap_test(sis, offset)) {
193 (*frontswap_ops.invalidate_page)(type, offset); 193 frontswap_ops.invalidate_page(type, offset);
194 atomic_dec(&sis->frontswap_pages); 194 __frontswap_clear(sis, offset);
195 frontswap_clear(sis, offset);
196 inc_frontswap_invalidates(); 195 inc_frontswap_invalidates();
197 } 196 }
198} 197}
@@ -209,67 +208,102 @@ void __frontswap_invalidate_area(unsigned type)
209 BUG_ON(sis == NULL); 208 BUG_ON(sis == NULL);
210 if (sis->frontswap_map == NULL) 209 if (sis->frontswap_map == NULL)
211 return; 210 return;
212 (*frontswap_ops.invalidate_area)(type); 211 frontswap_ops.invalidate_area(type);
213 atomic_set(&sis->frontswap_pages, 0); 212 atomic_set(&sis->frontswap_pages, 0);
214 memset(sis->frontswap_map, 0, sis->max / sizeof(long)); 213 memset(sis->frontswap_map, 0, sis->max / sizeof(long));
215} 214}
216EXPORT_SYMBOL(__frontswap_invalidate_area); 215EXPORT_SYMBOL(__frontswap_invalidate_area);
217 216
218/* 217static unsigned long __frontswap_curr_pages(void)
219 * Frontswap, like a true swap device, may unnecessarily retain pages
220 * under certain circumstances; "shrink" frontswap is essentially a
221 * "partial swapoff" and works by calling try_to_unuse to attempt to
222 * unuse enough frontswap pages to attempt to -- subject to memory
223 * constraints -- reduce the number of pages in frontswap to the
224 * number given in the parameter target_pages.
225 */
226void frontswap_shrink(unsigned long target_pages)
227{ 218{
228 struct swap_info_struct *si = NULL;
229 int si_frontswap_pages;
230 unsigned long total_pages = 0, total_pages_to_unuse;
231 unsigned long pages = 0, pages_to_unuse = 0;
232 int type; 219 int type;
233 bool locked = false; 220 unsigned long totalpages = 0;
221 struct swap_info_struct *si = NULL;
234 222
235 /* 223 assert_spin_locked(&swap_lock);
236 * we don't want to hold swap_lock while doing a very
237 * lengthy try_to_unuse, but swap_list may change
238 * so restart scan from swap_list.head each time
239 */
240 spin_lock(&swap_lock);
241 locked = true;
242 total_pages = 0;
243 for (type = swap_list.head; type >= 0; type = si->next) { 224 for (type = swap_list.head; type >= 0; type = si->next) {
244 si = swap_info[type]; 225 si = swap_info[type];
245 total_pages += atomic_read(&si->frontswap_pages); 226 totalpages += atomic_read(&si->frontswap_pages);
246 } 227 }
247 if (total_pages <= target_pages) 228 return totalpages;
248 goto out; 229}
249 total_pages_to_unuse = total_pages - target_pages; 230
231static int __frontswap_unuse_pages(unsigned long total, unsigned long *unused,
232 int *swapid)
233{
234 int ret = -EINVAL;
235 struct swap_info_struct *si = NULL;
236 int si_frontswap_pages;
237 unsigned long total_pages_to_unuse = total;
238 unsigned long pages = 0, pages_to_unuse = 0;
239 int type;
240
241 assert_spin_locked(&swap_lock);
250 for (type = swap_list.head; type >= 0; type = si->next) { 242 for (type = swap_list.head; type >= 0; type = si->next) {
251 si = swap_info[type]; 243 si = swap_info[type];
252 si_frontswap_pages = atomic_read(&si->frontswap_pages); 244 si_frontswap_pages = atomic_read(&si->frontswap_pages);
253 if (total_pages_to_unuse < si_frontswap_pages) 245 if (total_pages_to_unuse < si_frontswap_pages) {
254 pages = pages_to_unuse = total_pages_to_unuse; 246 pages = pages_to_unuse = total_pages_to_unuse;
255 else { 247 } else {
256 pages = si_frontswap_pages; 248 pages = si_frontswap_pages;
257 pages_to_unuse = 0; /* unuse all */ 249 pages_to_unuse = 0; /* unuse all */
258 } 250 }
259 /* ensure there is enough RAM to fetch pages from frontswap */ 251 /* ensure there is enough RAM to fetch pages from frontswap */
260 if (security_vm_enough_memory_mm(current->mm, pages)) 252 if (security_vm_enough_memory_mm(current->mm, pages)) {
253 ret = -ENOMEM;
261 continue; 254 continue;
255 }
262 vm_unacct_memory(pages); 256 vm_unacct_memory(pages);
257 *unused = pages_to_unuse;
258 *swapid = type;
259 ret = 0;
263 break; 260 break;
264 } 261 }
265 if (type < 0) 262
266 goto out; 263 return ret;
267 locked = false; 264}
265
266static int __frontswap_shrink(unsigned long target_pages,
267 unsigned long *pages_to_unuse,
268 int *type)
269{
270 unsigned long total_pages = 0, total_pages_to_unuse;
271
272 assert_spin_locked(&swap_lock);
273
274 total_pages = __frontswap_curr_pages();
275 if (total_pages <= target_pages) {
276 /* Nothing to do */
277 *pages_to_unuse = 0;
278 return 0;
279 }
280 total_pages_to_unuse = total_pages - target_pages;
281 return __frontswap_unuse_pages(total_pages_to_unuse, pages_to_unuse, type);
282}
283
284/*
285 * Frontswap, like a true swap device, may unnecessarily retain pages
286 * under certain circumstances; "shrink" frontswap is essentially a
287 * "partial swapoff" and works by calling try_to_unuse to attempt to
288 * unuse enough frontswap pages to attempt to -- subject to memory
289 * constraints -- reduce the number of pages in frontswap to the
290 * number given in the parameter target_pages.
291 */
292void frontswap_shrink(unsigned long target_pages)
293{
294 unsigned long pages_to_unuse = 0;
295 int type, ret;
296
297 /*
298 * we don't want to hold swap_lock while doing a very
299 * lengthy try_to_unuse, but swap_list may change
300 * so restart scan from swap_list.head each time
301 */
302 spin_lock(&swap_lock);
303 ret = __frontswap_shrink(target_pages, &pages_to_unuse, &type);
268 spin_unlock(&swap_lock); 304 spin_unlock(&swap_lock);
269 try_to_unuse(type, true, pages_to_unuse); 305 if (ret == 0 && pages_to_unuse)
270out: 306 try_to_unuse(type, true, pages_to_unuse);
271 if (locked)
272 spin_unlock(&swap_lock);
273 return; 307 return;
274} 308}
275EXPORT_SYMBOL(frontswap_shrink); 309EXPORT_SYMBOL(frontswap_shrink);
@@ -281,16 +315,12 @@ EXPORT_SYMBOL(frontswap_shrink);
281 */ 315 */
282unsigned long frontswap_curr_pages(void) 316unsigned long frontswap_curr_pages(void)
283{ 317{
284 int type;
285 unsigned long totalpages = 0; 318 unsigned long totalpages = 0;
286 struct swap_info_struct *si = NULL;
287 319
288 spin_lock(&swap_lock); 320 spin_lock(&swap_lock);
289 for (type = swap_list.head; type >= 0; type = si->next) { 321 totalpages = __frontswap_curr_pages();
290 si = swap_info[type];
291 totalpages += atomic_read(&si->frontswap_pages);
292 }
293 spin_unlock(&swap_lock); 322 spin_unlock(&swap_lock);
323
294 return totalpages; 324 return totalpages;
295} 325}
296EXPORT_SYMBOL(frontswap_curr_pages); 326EXPORT_SYMBOL(frontswap_curr_pages);