diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-24 16:15:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-24 16:15:25 -0400 |
commit | 2b849570264d9f802485e327b7a4b0c52991d26a (patch) | |
tree | 4f2f93a77f614877d4fc4a98a8b100fbe3dcebf0 /mm | |
parent | 62c4d9afa4bcf5315e2745a17a0228bf65b9ba40 (diff) | |
parent | 1d00015e268f9142de0b504b3e4a4905155276f2 (diff) |
Merge tag 'stable/for-linus-3.6-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/mm
Pull frontswap updates from Konrad Rzeszutek Wilk:
"Cleanups in code and documentation. Little bit of refactoring for
cleaner look."
* tag 'stable/for-linus-3.6-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/mm:
mm/frontswap: cleanup doc and comment error
mm: frontswap: remove unneeded headers
mm: frontswap: split out function to clear a page out
mm: frontswap: remove unnecessary check during initialization
mm: frontswap: make all branches of if statement in put page consistent
mm: frontswap: split frontswap_shrink further to simplify locking
mm: frontswap: split out __frontswap_unuse_pages
mm: frontswap: split out __frontswap_curr_pages
mm: frontswap: trivial coding convention issues
mm: frontswap: remove casting from function calls through ops structure
Diffstat (limited to 'mm')
-rw-r--r-- | mm/frontswap.c | 150 |
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 | } |
116 | EXPORT_SYMBOL(__frontswap_init); | 111 | EXPORT_SYMBOL(__frontswap_init); |
117 | 112 | ||
113 | static 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 | */ |
125 | int __frontswap_store(struct page *page) | 126 | int __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 | } |
216 | EXPORT_SYMBOL(__frontswap_invalidate_area); | 215 | EXPORT_SYMBOL(__frontswap_invalidate_area); |
217 | 216 | ||
218 | /* | 217 | static 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 | */ | ||
226 | void 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 | |
231 | static 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 | |||
266 | static 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 | */ | ||
292 | void 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) |
270 | out: | 306 | try_to_unuse(type, true, pages_to_unuse); |
271 | if (locked) | ||
272 | spin_unlock(&swap_lock); | ||
273 | return; | 307 | return; |
274 | } | 308 | } |
275 | EXPORT_SYMBOL(frontswap_shrink); | 309 | EXPORT_SYMBOL(frontswap_shrink); |
@@ -281,16 +315,12 @@ EXPORT_SYMBOL(frontswap_shrink); | |||
281 | */ | 315 | */ |
282 | unsigned long frontswap_curr_pages(void) | 316 | unsigned 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 | } |
296 | EXPORT_SYMBOL(frontswap_curr_pages); | 326 | EXPORT_SYMBOL(frontswap_curr_pages); |