diff options
Diffstat (limited to 'drivers/xen/tmem.c')
-rw-r--r-- | drivers/xen/tmem.c | 170 |
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 | ||
125 | static int xen_tmem_destroy_pool(u32 pool_id) | 131 | int tmem_enabled __read_mostly; |
126 | { | 132 | EXPORT_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 | |||
132 | int tmem_enabled; | ||
133 | 133 | ||
134 | static int __init enable_tmem(char *s) | 134 | static 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 | ||
143 | static 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 | ||
144 | static void tmem_cleancache_put_page(int pool, struct cleancache_filekey key, | 152 | static 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 | ||
244 | static 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) */ | ||
257 | static 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 | |||
268 | static 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 */ | ||
276 | static 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 | */ | ||
302 | static 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 */ | ||
324 | static 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 */ | ||
338 | static 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 | |||
349 | static 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 | |||
359 | static int __initdata use_frontswap = 1; | ||
360 | |||
361 | static int __init no_frontswap(char *s) | ||
362 | { | ||
363 | use_frontswap = 0; | ||
364 | return 1; | ||
365 | } | ||
366 | |||
367 | __setup("nofrontswap", no_frontswap); | ||
368 | |||
369 | static 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 | |||
378 | static 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 " |