aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/tmem.c
diff options
context:
space:
mode:
authorDan Magenheimer <dan.magenheimer@oracle.com>2011-06-17 17:06:20 -0400
committerDan Magenheimer <dan.magenheimer@oracle.com>2011-06-17 17:06:20 -0400
commitafec6e04922d0c8c7e244be2e544bac5e7e36294 (patch)
tree45bb22e18e87b6a618a12c39426cb4914f446d15 /drivers/xen/tmem.c
parent55922c9d1b84b89cb946c777fddccb3247e7df2c (diff)
xen: prepare tmem shim to handle frontswap
Provide the shim code for frontswap for Xen tmem even if the frontswap patchset is not present yet. (The egg is before the chicken.) Signed-off-by: Dan Magenheimer <dan.magenheimer@oracle.com> Reviewed-by: Konrad Wilk <konrad.wilk@oracle.com>
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 "