Add linux-next specific files for 20110801
[linux-2.6/next.git] / mm / frontswap.c
blob22f866e9e05aefe005a26c5e2e440164be4abc31
1 /*
2 * Frontswap frontend
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.
8 * Copyright (C) 2009-2010 Oracle Corp. All rights reserved.
9 * Author: Dan Magenheimer
11 * This work is licensed under the terms of the GNU GPL, version 2.
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>
28 * frontswap_ops is set by frontswap_register_ops to contain the pointers
29 * to the frontswap "backend" implementation functions.
31 static struct frontswap_ops frontswap_ops;
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.
38 int frontswap_enabled;
39 EXPORT_SYMBOL(frontswap_enabled);
41 /* useful stats available in /sys/kernel/mm/frontswap */
42 static unsigned long frontswap_gets;
43 static unsigned long frontswap_succ_puts;
44 static unsigned long frontswap_failed_puts;
45 static unsigned long frontswap_flushes;
48 * register operations for frontswap, returning previous thus allowing
49 * detection of multiple backends and possible nesting
51 struct frontswap_ops frontswap_register_ops(struct frontswap_ops *ops)
53 struct frontswap_ops old = frontswap_ops;
55 frontswap_ops = *ops;
56 frontswap_enabled = 1;
57 return old;
59 EXPORT_SYMBOL(frontswap_register_ops);
61 /* Called when a swap device is swapon'd */
62 void __frontswap_init(unsigned type)
64 if (frontswap_enabled)
65 (*frontswap_ops.init)(type);
67 EXPORT_SYMBOL(__frontswap_init);
70 * "Put" data from a page to frontswap and associate it with the page's
71 * swaptype and offset. Page must be locked and in the swap cache.
72 * If frontswap already contains a page with matching swaptype and
73 * offset, the frontswap implmentation may either overwrite the data
74 * and return success or flush the page from frontswap and return failure
76 int __frontswap_put_page(struct page *page)
78 int ret = -1, dup = 0;
79 swp_entry_t entry = { .val = page_private(page), };
80 int type = swp_type(entry);
81 struct swap_info_struct *sis = swap_info[type];
82 pgoff_t offset = swp_offset(entry);
84 BUG_ON(!PageLocked(page));
85 if (frontswap_test(sis, offset))
86 dup = 1;
87 ret = (*frontswap_ops.put_page)(type, offset, page);
88 if (ret == 0) {
89 frontswap_set(sis, offset);
90 frontswap_succ_puts++;
91 if (!dup)
92 sis->frontswap_pages++;
93 } else if (dup) {
95 failed dup always results in automatic flush of
96 the (older) page from frontswap
98 frontswap_clear(sis, offset);
99 sis->frontswap_pages--;
100 frontswap_failed_puts++;
101 } else
102 frontswap_failed_puts++;
103 return ret;
105 EXPORT_SYMBOL(__frontswap_put_page);
108 * "Get" data from frontswap associated with swaptype and offset that were
109 * specified when the data was put to frontswap and use it to fill the
110 * specified page with data. Page must be locked and in the swap cache
112 int __frontswap_get_page(struct page *page)
114 int ret = -1;
115 swp_entry_t entry = { .val = page_private(page), };
116 int type = swp_type(entry);
117 struct swap_info_struct *sis = swap_info[type];
118 pgoff_t offset = swp_offset(entry);
120 BUG_ON(!PageLocked(page));
121 if (frontswap_test(sis, offset))
122 ret = (*frontswap_ops.get_page)(type, offset, page);
123 if (ret == 0)
124 frontswap_gets++;
125 return ret;
127 EXPORT_SYMBOL(__frontswap_get_page);
130 * Flush any data from frontswap associated with the specified swaptype
131 * and offset so that a subsequent "get" will fail.
133 void __frontswap_flush_page(unsigned type, pgoff_t offset)
135 struct swap_info_struct *sis = swap_info[type];
137 if (frontswap_test(sis, offset)) {
138 (*frontswap_ops.flush_page)(type, offset);
139 sis->frontswap_pages--;
140 frontswap_clear(sis, offset);
141 frontswap_flushes++;
144 EXPORT_SYMBOL(__frontswap_flush_page);
147 * Flush all data from frontswap associated with all offsets for the
148 * specified swaptype.
150 void __frontswap_flush_area(unsigned type)
152 struct swap_info_struct *sis = swap_info[type];
154 (*frontswap_ops.flush_area)(type);
155 sis->frontswap_pages = 0;
156 memset(sis->frontswap_map, 0, sis->max / sizeof(long));
158 EXPORT_SYMBOL(__frontswap_flush_area);
161 * Frontswap, like a true swap device, may unnecessarily retain pages
162 * under certain circumstances; "shrink" frontswap is essentially a
163 * "partial swapoff" and works by calling try_to_unuse to attempt to
164 * unuse enough frontswap pages to attempt to -- subject to memory
165 * constraints -- reduce the number of pages in frontswap
167 void frontswap_shrink(unsigned long target_pages)
169 int wrapped = 0;
170 bool locked = false;
172 for (wrapped = 0; wrapped <= 3; wrapped++) {
174 struct swap_info_struct *si = NULL;
175 unsigned long total_pages = 0, total_pages_to_unuse;
176 unsigned long pages = 0, unuse_pages = 0;
177 int type;
180 * we don't want to hold swap_lock while doing a very
181 * lengthy try_to_unuse, but swap_list may change
182 * so restart scan from swap_list.head each time
184 spin_lock(&swap_lock);
185 locked = true;
186 total_pages = 0;
187 for (type = swap_list.head; type >= 0; type = si->next) {
188 si = swap_info[type];
189 total_pages += si->frontswap_pages;
191 if (total_pages <= target_pages)
192 goto out;
193 total_pages_to_unuse = total_pages - target_pages;
194 for (type = swap_list.head; type >= 0; type = si->next) {
195 si = swap_info[type];
196 if (total_pages_to_unuse < si->frontswap_pages)
197 pages = unuse_pages = total_pages_to_unuse;
198 else {
199 pages = si->frontswap_pages;
200 unuse_pages = 0; /* unuse all */
202 if (security_vm_enough_memory_kern(pages))
203 continue;
204 vm_unacct_memory(pages);
205 break;
207 if (type < 0)
208 goto out;
209 locked = false;
210 spin_unlock(&swap_lock);
211 try_to_unuse(type, true, unuse_pages);
214 out:
215 if (locked)
216 spin_unlock(&swap_lock);
217 return;
219 EXPORT_SYMBOL(frontswap_shrink);
222 * count and return the number of pages frontswap pages across all
223 * swap devices. This is exported so that a kernel module can
224 * determine current usage without reading sysfs.
226 unsigned long frontswap_curr_pages(void)
228 int type;
229 unsigned long totalpages = 0;
230 struct swap_info_struct *si = NULL;
232 spin_lock(&swap_lock);
233 for (type = swap_list.head; type >= 0; type = si->next) {
234 si = swap_info[type];
235 totalpages += si->frontswap_pages;
237 spin_unlock(&swap_lock);
238 return totalpages;
240 EXPORT_SYMBOL(frontswap_curr_pages);
242 #ifdef CONFIG_SYSFS
244 /* see Documentation/ABI/xxx/sysfs-kernel-mm-frontswap */
246 #define FRONTSWAP_ATTR_RO(_name) \
247 static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
248 #define FRONTSWAP_ATTR(_name) \
249 static struct kobj_attribute _name##_attr = \
250 __ATTR(_name, 0644, _name##_show, _name##_store)
252 static ssize_t curr_pages_show(struct kobject *kobj,
253 struct kobj_attribute *attr, char *buf)
255 return sprintf(buf, "%lu\n", frontswap_curr_pages());
258 static ssize_t curr_pages_store(struct kobject *kobj,
259 struct kobj_attribute *attr,
260 const char *buf, size_t count)
262 unsigned long target_pages;
263 int err;
265 err = strict_strtoul(buf, 10, &target_pages);
266 if (err)
267 return -EINVAL;
269 frontswap_shrink(target_pages);
271 return count;
273 FRONTSWAP_ATTR(curr_pages);
275 static ssize_t succ_puts_show(struct kobject *kobj,
276 struct kobj_attribute *attr, char *buf)
278 return sprintf(buf, "%lu\n", frontswap_succ_puts);
280 FRONTSWAP_ATTR_RO(succ_puts);
282 static ssize_t failed_puts_show(struct kobject *kobj,
283 struct kobj_attribute *attr, char *buf)
285 return sprintf(buf, "%lu\n", frontswap_failed_puts);
287 FRONTSWAP_ATTR_RO(failed_puts);
289 static ssize_t gets_show(struct kobject *kobj,
290 struct kobj_attribute *attr, char *buf)
292 return sprintf(buf, "%lu\n", frontswap_gets);
294 FRONTSWAP_ATTR_RO(gets);
296 static ssize_t flushes_show(struct kobject *kobj,
297 struct kobj_attribute *attr, char *buf)
299 return sprintf(buf, "%lu\n", frontswap_flushes);
301 FRONTSWAP_ATTR_RO(flushes);
303 static struct attribute *frontswap_attrs[] = {
304 &curr_pages_attr.attr,
305 &succ_puts_attr.attr,
306 &failed_puts_attr.attr,
307 &gets_attr.attr,
308 &flushes_attr.attr,
309 NULL,
312 static struct attribute_group frontswap_attr_group = {
313 .attrs = frontswap_attrs,
314 .name = "frontswap",
317 #endif /* CONFIG_SYSFS */
319 static int __init init_frontswap(void)
321 #ifdef CONFIG_SYSFS
322 int err;
324 err = sysfs_create_group(mm_kobj, &frontswap_attr_group);
325 #endif /* CONFIG_SYSFS */
326 return 0;
329 static void __exit exit_frontswap(void)
331 frontswap_shrink(0UL);
334 module_init(init_frontswap);
335 module_exit(exit_frontswap);