aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/tmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/xen/tmem.c')
-rw-r--r--drivers/xen/tmem.c170
1 files changed, 158 insertions, 12 deletions
diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c
index 816a44959ef0..d369965e8f8a 100644
--- a/drivers/xen/tmem.c
+++ b/drivers/xen/tmem.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Xen implementation for transcendent memory (tmem) 2 * Xen implementation for transcendent memory (tmem)
3 * 3 *
4 * Copyright (C) 2009-2010 Oracle Corp. All rights reserved. 4 * Copyright (C) 2009-2011 Oracle Corp. All rights reserved.
5 * Author: Dan Magenheimer 5 * Author: Dan Magenheimer
6 */ 6 */
7 7
@@ -9,8 +9,14 @@
9#include <linux/types.h> 9#include <linux/types.h>
10#include <linux/init.h> 10#include <linux/init.h>
11#include <linux/pagemap.h> 11#include <linux/pagemap.h>
12#include <linux/module.h>
12#include <linux/cleancache.h> 13#include <linux/cleancache.h>
13 14
15/* temporary ifdef until include/linux/frontswap.h is upstream */
16#ifdef CONFIG_FRONTSWAP
17#include <linux/frontswap.h>
18#endif
19
14#include <xen/xen.h> 20#include <xen/xen.h>
15#include <xen/interface/xen.h> 21#include <xen/interface/xen.h>
16#include <asm/xen/hypercall.h> 22#include <asm/xen/hypercall.h>
@@ -122,14 +128,8 @@ static int xen_tmem_flush_object(u32 pool_id, struct tmem_oid oid)
122 return xen_tmem_op(TMEM_FLUSH_OBJECT, pool_id, oid, 0, 0, 0, 0, 0); 128 return xen_tmem_op(TMEM_FLUSH_OBJECT, pool_id, oid, 0, 0, 0, 0, 0);
123} 129}
124 130
125static int xen_tmem_destroy_pool(u32 pool_id) 131int tmem_enabled __read_mostly;
126{ 132EXPORT_SYMBOL(tmem_enabled);
127 struct tmem_oid oid = { { 0 } };
128
129 return xen_tmem_op(TMEM_DESTROY_POOL, pool_id, oid, 0, 0, 0, 0, 0);
130}
131
132int tmem_enabled;
133 133
134static int __init enable_tmem(char *s) 134static int __init enable_tmem(char *s)
135{ 135{
@@ -139,6 +139,14 @@ static int __init enable_tmem(char *s)
139 139
140__setup("tmem", enable_tmem); 140__setup("tmem", enable_tmem);
141 141
142#ifdef CONFIG_CLEANCACHE
143static int xen_tmem_destroy_pool(u32 pool_id)
144{
145 struct tmem_oid oid = { { 0 } };
146
147 return xen_tmem_op(TMEM_DESTROY_POOL, pool_id, oid, 0, 0, 0, 0, 0);
148}
149
142/* cleancache ops */ 150/* cleancache ops */
143 151
144static void tmem_cleancache_put_page(int pool, struct cleancache_filekey key, 152static void tmem_cleancache_put_page(int pool, struct cleancache_filekey key,
@@ -240,18 +248,156 @@ static struct cleancache_ops tmem_cleancache_ops = {
240 .init_shared_fs = tmem_cleancache_init_shared_fs, 248 .init_shared_fs = tmem_cleancache_init_shared_fs,
241 .init_fs = tmem_cleancache_init_fs 249 .init_fs = tmem_cleancache_init_fs
242}; 250};
251#endif
243 252
244static int __init xen_tmem_init(void) 253#ifdef CONFIG_FRONTSWAP
254/* frontswap tmem operations */
255
256/* a single tmem poolid is used for all frontswap "types" (swapfiles) */
257static int tmem_frontswap_poolid;
258
259/*
260 * Swizzling increases objects per swaptype, increasing tmem concurrency
261 * for heavy swaploads. Later, larger nr_cpus -> larger SWIZ_BITS
262 */
263#define SWIZ_BITS 4
264#define SWIZ_MASK ((1 << SWIZ_BITS) - 1)
265#define _oswiz(_type, _ind) ((_type << SWIZ_BITS) | (_ind & SWIZ_MASK))
266#define iswiz(_ind) (_ind >> SWIZ_BITS)
267
268static inline struct tmem_oid oswiz(unsigned type, u32 ind)
245{ 269{
246 struct cleancache_ops old_ops; 270 struct tmem_oid oid = { .oid = { 0 } };
271 oid.oid[0] = _oswiz(type, ind);
272 return oid;
273}
247 274
275/* returns 0 if the page was successfully put into frontswap, -1 if not */
276static int tmem_frontswap_put_page(unsigned type, pgoff_t offset,
277 struct page *page)
278{
279 u64 ind64 = (u64)offset;
280 u32 ind = (u32)offset;
281 unsigned long pfn = page_to_pfn(page);
282 int pool = tmem_frontswap_poolid;
283 int ret;
284
285 if (pool < 0)
286 return -1;
287 if (ind64 != ind)
288 return -1;
289 mb(); /* ensure page is quiescent; tmem may address it with an alias */
290 ret = xen_tmem_put_page(pool, oswiz(type, ind), iswiz(ind), pfn);
291 /* translate Xen tmem return values to linux semantics */
292 if (ret == 1)
293 return 0;
294 else
295 return -1;
296}
297
298/*
299 * returns 0 if the page was successfully gotten from frontswap, -1 if
300 * was not present (should never happen!)
301 */
302static int tmem_frontswap_get_page(unsigned type, pgoff_t offset,
303 struct page *page)
304{
305 u64 ind64 = (u64)offset;
306 u32 ind = (u32)offset;
307 unsigned long pfn = page_to_pfn(page);
308 int pool = tmem_frontswap_poolid;
309 int ret;
310
311 if (pool < 0)
312 return -1;
313 if (ind64 != ind)
314 return -1;
315 ret = xen_tmem_get_page(pool, oswiz(type, ind), iswiz(ind), pfn);
316 /* translate Xen tmem return values to linux semantics */
317 if (ret == 1)
318 return 0;
319 else
320 return -1;
321}
322
323/* flush a single page from frontswap */
324static void tmem_frontswap_flush_page(unsigned type, pgoff_t offset)
325{
326 u64 ind64 = (u64)offset;
327 u32 ind = (u32)offset;
328 int pool = tmem_frontswap_poolid;
329
330 if (pool < 0)
331 return;
332 if (ind64 != ind)
333 return;
334 (void) xen_tmem_flush_page(pool, oswiz(type, ind), iswiz(ind));
335}
336
337/* flush all pages from the passed swaptype */
338static void tmem_frontswap_flush_area(unsigned type)
339{
340 int pool = tmem_frontswap_poolid;
341 int ind;
342
343 if (pool < 0)
344 return;
345 for (ind = SWIZ_MASK; ind >= 0; ind--)
346 (void)xen_tmem_flush_object(pool, oswiz(type, ind));
347}
348
349static void tmem_frontswap_init(unsigned ignored)
350{
351 struct tmem_pool_uuid private = TMEM_POOL_PRIVATE_UUID;
352
353 /* a single tmem poolid is used for all frontswap "types" (swapfiles) */
354 if (tmem_frontswap_poolid < 0)
355 tmem_frontswap_poolid =
356 xen_tmem_new_pool(private, TMEM_POOL_PERSIST, PAGE_SIZE);
357}
358
359static int __initdata use_frontswap = 1;
360
361static int __init no_frontswap(char *s)
362{
363 use_frontswap = 0;
364 return 1;
365}
366
367__setup("nofrontswap", no_frontswap);
368
369static struct frontswap_ops tmem_frontswap_ops = {
370 .put_page = tmem_frontswap_put_page,
371 .get_page = tmem_frontswap_get_page,
372 .flush_page = tmem_frontswap_flush_page,
373 .flush_area = tmem_frontswap_flush_area,
374 .init = tmem_frontswap_init
375};
376#endif
377
378static int __init xen_tmem_init(void)
379{
248 if (!xen_domain()) 380 if (!xen_domain())
249 return 0; 381 return 0;
382#ifdef CONFIG_FRONTSWAP
383 if (tmem_enabled && use_frontswap) {
384 char *s = "";
385 struct frontswap_ops old_ops =
386 frontswap_register_ops(&tmem_frontswap_ops);
387
388 tmem_frontswap_poolid = -1;
389 if (old_ops.init != NULL)
390 s = " (WARNING: frontswap_ops overridden)";
391 printk(KERN_INFO "frontswap enabled, RAM provided by "
392 "Xen Transcendent Memory\n");
393 }
394#endif
250#ifdef CONFIG_CLEANCACHE 395#ifdef CONFIG_CLEANCACHE
251 BUG_ON(sizeof(struct cleancache_filekey) != sizeof(struct tmem_oid)); 396 BUG_ON(sizeof(struct cleancache_filekey) != sizeof(struct tmem_oid));
252 if (tmem_enabled && use_cleancache) { 397 if (tmem_enabled && use_cleancache) {
253 char *s = ""; 398 char *s = "";
254 old_ops = cleancache_register_ops(&tmem_cleancache_ops); 399 struct cleancache_ops old_ops =
400 cleancache_register_ops(&tmem_cleancache_ops);
255 if (old_ops.init_fs != NULL) 401 if (old_ops.init_fs != NULL)
256 s = " (WARNING: cleancache_ops overridden)"; 402 s = " (WARNING: cleancache_ops overridden)";
257 printk(KERN_INFO "cleancache enabled, RAM provided by " 403 printk(KERN_INFO "cleancache enabled, RAM provided by "