]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - mm/frontswap.c
One can get this information from minix/inode.c, but adding the
[karo-tx-linux.git] / mm / frontswap.c
1 /*
2  * Frontswap frontend
3  *
4  * This code provides the generic "frontend" layer to call a matching
5  * "backend" driver implementation of frontswap.  See
6  * Documentation/vm/frontswap.txt for more information.
7  *
8  * Copyright (C) 2009-2010 Oracle Corp.  All rights reserved.
9  * Author: Dan Magenheimer
10  *
11  * This work is licensed under the terms of the GNU GPL, version 2.
12  */
13
14 #include <linux/mm.h>
15 #include <linux/mman.h>
16 #include <linux/sysctl.h>
17 #include <linux/swap.h>
18 #include <linux/swapops.h>
19 #include <linux/proc_fs.h>
20 #include <linux/security.h>
21 #include <linux/capability.h>
22 #include <linux/module.h>
23 #include <linux/uaccess.h>
24 #include <linux/frontswap.h>
25 #include <linux/swapfile.h>
26
27 /*
28  * frontswap_ops is set by frontswap_register_ops to contain the pointers
29  * to the frontswap "backend" implementation functions.
30  */
31 static struct frontswap_ops frontswap_ops;
32
33 /*
34  * This global enablement flag reduces overhead on systems where frontswap_ops
35  * has not been registered, so is preferred to the slower alternative: a
36  * function call that checks a non-global.
37  */
38 int frontswap_enabled;
39 EXPORT_SYMBOL(frontswap_enabled);
40
41 /*
42  * Useful stats available in /sys/kernel/mm/frontswap.  These are for
43  * information only so are not protected against increment/decrement races.
44  */
45 static unsigned long frontswap_gets;
46 static unsigned long frontswap_succ_puts;
47 static unsigned long frontswap_failed_puts;
48 static unsigned long frontswap_flushes;
49
50 /*
51  * Register operations for frontswap, returning previous thus allowing
52  * detection of multiple backends and possible nesting
53  */
54 struct frontswap_ops frontswap_register_ops(struct frontswap_ops *ops)
55 {
56         struct frontswap_ops old = frontswap_ops;
57
58         frontswap_ops = *ops;
59         frontswap_enabled = 1;
60         return old;
61 }
62 EXPORT_SYMBOL(frontswap_register_ops);
63
64 /* Called when a swap device is swapon'd */
65 void __frontswap_init(unsigned type)
66 {
67         struct swap_info_struct *sis = swap_info[type];
68
69         BUG_ON(sis == NULL);
70         if (sis->frontswap_map == NULL)
71                 return;
72         if (frontswap_enabled)
73                 (*frontswap_ops.init)(type);
74 }
75 EXPORT_SYMBOL(__frontswap_init);
76
77 /*
78  * "Put" data from a page to frontswap and associate it with the page's
79  * swaptype and offset.  Page must be locked and in the swap cache.
80  * If frontswap already contains a page with matching swaptype and
81  * offset, the frontswap implmentation may either overwrite the data
82  * and return success or flush the page from frontswap and return failure
83  */
84 int __frontswap_put_page(struct page *page)
85 {
86         int ret = -1, dup = 0;
87         swp_entry_t entry = { .val = page_private(page), };
88         int type = swp_type(entry);
89         struct swap_info_struct *sis = swap_info[type];
90         pgoff_t offset = swp_offset(entry);
91
92         BUG_ON(!PageLocked(page));
93         BUG_ON(sis == NULL);
94         if (frontswap_test(sis, offset))
95                 dup = 1;
96         ret = (*frontswap_ops.put_page)(type, offset, page);
97         if (ret == 0) {
98                 frontswap_set(sis, offset);
99                 frontswap_succ_puts++;
100                 if (!dup)
101                         atomic_inc(&sis->frontswap_pages);
102         } else if (dup) {
103                 /*
104                   failed dup always results in automatic flush of
105                   the (older) page from frontswap
106                  */
107                 frontswap_clear(sis, offset);
108                 atomic_dec(&sis->frontswap_pages);
109                 frontswap_failed_puts++;
110         } else
111                 frontswap_failed_puts++;
112         return ret;
113 }
114 EXPORT_SYMBOL(__frontswap_put_page);
115
116 /*
117  * "Get" data from frontswap associated with swaptype and offset that were
118  * specified when the data was put to frontswap and use it to fill the
119  * specified page with data. Page must be locked and in the swap cache
120  */
121 int __frontswap_get_page(struct page *page)
122 {
123         int ret = -1;
124         swp_entry_t entry = { .val = page_private(page), };
125         int type = swp_type(entry);
126         struct swap_info_struct *sis = swap_info[type];
127         pgoff_t offset = swp_offset(entry);
128
129         BUG_ON(!PageLocked(page));
130         BUG_ON(sis == NULL);
131         if (frontswap_test(sis, offset))
132                 ret = (*frontswap_ops.get_page)(type, offset, page);
133         if (ret == 0)
134                 frontswap_gets++;
135         return ret;
136 }
137 EXPORT_SYMBOL(__frontswap_get_page);
138
139 /*
140  * Flush any data from frontswap associated with the specified swaptype
141  * and offset so that a subsequent "get" will fail.
142  */
143 void __frontswap_flush_page(unsigned type, pgoff_t offset)
144 {
145         struct swap_info_struct *sis = swap_info[type];
146
147         BUG_ON(sis == NULL);
148         if (frontswap_test(sis, offset)) {
149                 (*frontswap_ops.flush_page)(type, offset);
150                 atomic_dec(&sis->frontswap_pages);
151                 frontswap_clear(sis, offset);
152                 frontswap_flushes++;
153         }
154 }
155 EXPORT_SYMBOL(__frontswap_flush_page);
156
157 /*
158  * Flush all data from frontswap associated with all offsets for the
159  * specified swaptype.
160  */
161 void __frontswap_flush_area(unsigned type)
162 {
163         struct swap_info_struct *sis = swap_info[type];
164
165         BUG_ON(sis == NULL);
166         if (sis->frontswap_map == NULL)
167                 return;
168         (*frontswap_ops.flush_area)(type);
169         atomic_set(&sis->frontswap_pages, 0);
170         memset(sis->frontswap_map, 0, sis->max / sizeof(long));
171 }
172 EXPORT_SYMBOL(__frontswap_flush_area);
173
174 /*
175  * Frontswap, like a true swap device, may unnecessarily retain pages
176  * under certain circumstances; "shrink" frontswap is essentially a
177  * "partial swapoff" and works by calling try_to_unuse to attempt to
178  * unuse enough frontswap pages to attempt to -- subject to memory
179  * constraints -- reduce the number of pages in frontswap
180  */
181 void frontswap_shrink(unsigned long target_pages)
182 {
183         int wrapped = 0;
184         bool locked = false;
185
186         /* try a few times to maximize chance of try_to_unuse success */
187         for (wrapped = 0; wrapped < 3; wrapped++) {
188
189                 struct swap_info_struct *si = NULL;
190                 int si_frontswap_pages;
191                 unsigned long total_pages = 0, total_pages_to_unuse;
192                 unsigned long pages = 0, pages_to_unuse = 0;
193                 int type;
194
195                 /*
196                  * we don't want to hold swap_lock while doing a very
197                  * lengthy try_to_unuse, but swap_list may change
198                  * so restart scan from swap_list.head each time
199                  */
200                 spin_lock(&swap_lock);
201                 locked = true;
202                 total_pages = 0;
203                 for (type = swap_list.head; type >= 0; type = si->next) {
204                         si = swap_info[type];
205                         total_pages += atomic_read(&si->frontswap_pages);
206                 }
207                 if (total_pages <= target_pages)
208                         goto out;
209                 total_pages_to_unuse = total_pages - target_pages;
210                 for (type = swap_list.head; type >= 0; type = si->next) {
211                         si = swap_info[type];
212                         si_frontswap_pages = atomic_read(&si->frontswap_pages);
213                         if (total_pages_to_unuse < si_frontswap_pages)
214                                 pages = pages_to_unuse = total_pages_to_unuse;
215                         else {
216                                 pages = si_frontswap_pages;
217                                 pages_to_unuse = 0; /* unuse all */
218                         }
219                         if (security_vm_enough_memory_kern(pages))
220                                 continue;
221                         vm_unacct_memory(pages);
222                         break;
223                 }
224                 if (type < 0)
225                         goto out;
226                 locked = false;
227                 spin_unlock(&swap_lock);
228                 try_to_unuse(type, true, pages_to_unuse);
229         }
230
231 out:
232         if (locked)
233                 spin_unlock(&swap_lock);
234         return;
235 }
236 EXPORT_SYMBOL(frontswap_shrink);
237
238 /*
239  * Count and return the number of pages frontswap pages across all
240  * swap devices.  This is exported so that a kernel module can
241  * determine current usage without reading sysfs.
242  */
243 unsigned long frontswap_curr_pages(void)
244 {
245         int type;
246         unsigned long totalpages = 0;
247         struct swap_info_struct *si = NULL;
248
249         spin_lock(&swap_lock);
250         for (type = swap_list.head; type >= 0; type = si->next) {
251                 si = swap_info[type];
252                 if (si != NULL)
253                         totalpages += atomic_read(&si->frontswap_pages);
254         }
255         spin_unlock(&swap_lock);
256         return totalpages;
257 }
258 EXPORT_SYMBOL(frontswap_curr_pages);
259
260 #ifdef CONFIG_SYSFS
261
262 /* see Documentation/ABI/xxx/sysfs-kernel-mm-frontswap */
263
264 #define FRONTSWAP_ATTR_RO(_name) \
265         static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
266 #define FRONTSWAP_ATTR(_name) \
267         static struct kobj_attribute _name##_attr = \
268                 __ATTR(_name, 0644, _name##_show, _name##_store)
269
270 static ssize_t curr_pages_show(struct kobject *kobj,
271                                struct kobj_attribute *attr, char *buf)
272 {
273         return sprintf(buf, "%lu\n", frontswap_curr_pages());
274 }
275
276 static ssize_t curr_pages_store(struct kobject *kobj,
277                                struct kobj_attribute *attr,
278                                const char *buf, size_t count)
279 {
280         unsigned long target_pages;
281
282         if (strict_strtoul(buf, 10, &target_pages))
283                 return -EINVAL;
284
285         frontswap_shrink(target_pages);
286
287         return count;
288 }
289 FRONTSWAP_ATTR(curr_pages);
290
291 static ssize_t succ_puts_show(struct kobject *kobj,
292                                struct kobj_attribute *attr, char *buf)
293 {
294         return sprintf(buf, "%lu\n", frontswap_succ_puts);
295 }
296 FRONTSWAP_ATTR_RO(succ_puts);
297
298 static ssize_t failed_puts_show(struct kobject *kobj,
299                                struct kobj_attribute *attr, char *buf)
300 {
301         return sprintf(buf, "%lu\n", frontswap_failed_puts);
302 }
303 FRONTSWAP_ATTR_RO(failed_puts);
304
305 static ssize_t gets_show(struct kobject *kobj,
306                                struct kobj_attribute *attr, char *buf)
307 {
308         return sprintf(buf, "%lu\n", frontswap_gets);
309 }
310 FRONTSWAP_ATTR_RO(gets);
311
312 static ssize_t flushes_show(struct kobject *kobj,
313                                struct kobj_attribute *attr, char *buf)
314 {
315         return sprintf(buf, "%lu\n", frontswap_flushes);
316 }
317 FRONTSWAP_ATTR_RO(flushes);
318
319 static struct attribute *frontswap_attrs[] = {
320         &curr_pages_attr.attr,
321         &succ_puts_attr.attr,
322         &failed_puts_attr.attr,
323         &gets_attr.attr,
324         &flushes_attr.attr,
325         NULL,
326 };
327
328 static struct attribute_group frontswap_attr_group = {
329         .attrs = frontswap_attrs,
330         .name = "frontswap",
331 };
332
333 #endif /* CONFIG_SYSFS */
334
335 static int __init init_frontswap(void)
336 {
337         int err = 0;
338
339 #ifdef CONFIG_SYSFS
340         err = sysfs_create_group(mm_kobj, &frontswap_attr_group);
341 #endif /* CONFIG_SYSFS */
342         return err;
343 }
344
345 static void __exit exit_frontswap(void)
346 {
347         frontswap_shrink(0UL);
348 }
349
350 module_init(init_frontswap);
351 module_exit(exit_frontswap);