diff options
-rw-r--r-- | include/linux/frontswap.h | 2 | ||||
-rw-r--r-- | mm/frontswap.c | 34 |
2 files changed, 32 insertions, 4 deletions
diff --git a/include/linux/frontswap.h b/include/linux/frontswap.h index 0e4e2eec5c1d..30442547b9e6 100644 --- a/include/linux/frontswap.h +++ b/include/linux/frontswap.h | |||
@@ -19,6 +19,8 @@ extern struct frontswap_ops | |||
19 | extern void frontswap_shrink(unsigned long); | 19 | extern void frontswap_shrink(unsigned long); |
20 | extern unsigned long frontswap_curr_pages(void); | 20 | extern unsigned long frontswap_curr_pages(void); |
21 | extern void frontswap_writethrough(bool); | 21 | extern void frontswap_writethrough(bool); |
22 | #define FRONTSWAP_HAS_EXCLUSIVE_GETS | ||
23 | extern void frontswap_tmem_exclusive_gets(bool); | ||
22 | 24 | ||
23 | extern void __frontswap_init(unsigned type); | 25 | extern void __frontswap_init(unsigned type); |
24 | extern int __frontswap_store(struct page *page); | 26 | extern int __frontswap_store(struct page *page); |
diff --git a/mm/frontswap.c b/mm/frontswap.c index 6b3e71a2cd48..2890e67d6026 100644 --- a/mm/frontswap.c +++ b/mm/frontswap.c | |||
@@ -44,6 +44,13 @@ EXPORT_SYMBOL(frontswap_enabled); | |||
44 | */ | 44 | */ |
45 | static bool frontswap_writethrough_enabled __read_mostly; | 45 | static bool frontswap_writethrough_enabled __read_mostly; |
46 | 46 | ||
47 | /* | ||
48 | * If enabled, the underlying tmem implementation is capable of doing | ||
49 | * exclusive gets, so frontswap_load, on a successful tmem_get must | ||
50 | * mark the page as no longer in frontswap AND mark it dirty. | ||
51 | */ | ||
52 | static bool frontswap_tmem_exclusive_gets_enabled __read_mostly; | ||
53 | |||
47 | #ifdef CONFIG_DEBUG_FS | 54 | #ifdef CONFIG_DEBUG_FS |
48 | /* | 55 | /* |
49 | * Counters available via /sys/kernel/debug/frontswap (if debugfs is | 56 | * Counters available via /sys/kernel/debug/frontswap (if debugfs is |
@@ -97,6 +104,15 @@ void frontswap_writethrough(bool enable) | |||
97 | EXPORT_SYMBOL(frontswap_writethrough); | 104 | EXPORT_SYMBOL(frontswap_writethrough); |
98 | 105 | ||
99 | /* | 106 | /* |
107 | * Enable/disable frontswap exclusive gets (see above). | ||
108 | */ | ||
109 | void frontswap_tmem_exclusive_gets(bool enable) | ||
110 | { | ||
111 | frontswap_tmem_exclusive_gets_enabled = enable; | ||
112 | } | ||
113 | EXPORT_SYMBOL(frontswap_tmem_exclusive_gets); | ||
114 | |||
115 | /* | ||
100 | * Called when a swap device is swapon'd. | 116 | * Called when a swap device is swapon'd. |
101 | */ | 117 | */ |
102 | void __frontswap_init(unsigned type) | 118 | void __frontswap_init(unsigned type) |
@@ -174,8 +190,13 @@ int __frontswap_load(struct page *page) | |||
174 | BUG_ON(sis == NULL); | 190 | BUG_ON(sis == NULL); |
175 | if (frontswap_test(sis, offset)) | 191 | if (frontswap_test(sis, offset)) |
176 | ret = frontswap_ops.load(type, offset, page); | 192 | ret = frontswap_ops.load(type, offset, page); |
177 | if (ret == 0) | 193 | if (ret == 0) { |
178 | inc_frontswap_loads(); | 194 | inc_frontswap_loads(); |
195 | if (frontswap_tmem_exclusive_gets_enabled) { | ||
196 | SetPageDirty(page); | ||
197 | frontswap_clear(sis, offset); | ||
198 | } | ||
199 | } | ||
179 | return ret; | 200 | return ret; |
180 | } | 201 | } |
181 | EXPORT_SYMBOL(__frontswap_load); | 202 | EXPORT_SYMBOL(__frontswap_load); |
@@ -263,6 +284,11 @@ static int __frontswap_unuse_pages(unsigned long total, unsigned long *unused, | |||
263 | return ret; | 284 | return ret; |
264 | } | 285 | } |
265 | 286 | ||
287 | /* | ||
288 | * Used to check if it's necessory and feasible to unuse pages. | ||
289 | * Return 1 when nothing to do, 0 when need to shink pages, | ||
290 | * error code when there is an error. | ||
291 | */ | ||
266 | static int __frontswap_shrink(unsigned long target_pages, | 292 | static int __frontswap_shrink(unsigned long target_pages, |
267 | unsigned long *pages_to_unuse, | 293 | unsigned long *pages_to_unuse, |
268 | int *type) | 294 | int *type) |
@@ -275,7 +301,7 @@ static int __frontswap_shrink(unsigned long target_pages, | |||
275 | if (total_pages <= target_pages) { | 301 | if (total_pages <= target_pages) { |
276 | /* Nothing to do */ | 302 | /* Nothing to do */ |
277 | *pages_to_unuse = 0; | 303 | *pages_to_unuse = 0; |
278 | return 0; | 304 | return 1; |
279 | } | 305 | } |
280 | total_pages_to_unuse = total_pages - target_pages; | 306 | total_pages_to_unuse = total_pages - target_pages; |
281 | return __frontswap_unuse_pages(total_pages_to_unuse, pages_to_unuse, type); | 307 | return __frontswap_unuse_pages(total_pages_to_unuse, pages_to_unuse, type); |
@@ -292,7 +318,7 @@ static int __frontswap_shrink(unsigned long target_pages, | |||
292 | void frontswap_shrink(unsigned long target_pages) | 318 | void frontswap_shrink(unsigned long target_pages) |
293 | { | 319 | { |
294 | unsigned long pages_to_unuse = 0; | 320 | unsigned long pages_to_unuse = 0; |
295 | int type, ret; | 321 | int uninitialized_var(type), ret; |
296 | 322 | ||
297 | /* | 323 | /* |
298 | * we don't want to hold swap_lock while doing a very | 324 | * we don't want to hold swap_lock while doing a very |
@@ -302,7 +328,7 @@ void frontswap_shrink(unsigned long target_pages) | |||
302 | spin_lock(&swap_lock); | 328 | spin_lock(&swap_lock); |
303 | ret = __frontswap_shrink(target_pages, &pages_to_unuse, &type); | 329 | ret = __frontswap_shrink(target_pages, &pages_to_unuse, &type); |
304 | spin_unlock(&swap_lock); | 330 | spin_unlock(&swap_lock); |
305 | if (ret == 0 && pages_to_unuse) | 331 | if (ret == 0) |
306 | try_to_unuse(type, true, pages_to_unuse); | 332 | try_to_unuse(type, true, pages_to_unuse); |
307 | return; | 333 | return; |
308 | } | 334 | } |