mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	mm/zpool: update zswap to use zpool
Change zswap to use the zpool api instead of directly using zbud. Add a boot-time param to allow selecting which zpool implementation to use, with zbud as the default. Signed-off-by: Dan Streetman <ddstreet@ieee.org> Tested-by: Seth Jennings <sjennings@variantweb.net> Cc: Weijie Yang <weijie.yang@samsung.com> Cc: Minchan Kim <minchan@kernel.org> Cc: Nitin Gupta <ngupta@vflare.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									c795779df2
								
							
						
					
					
						commit
						12d79d64bf
					
				
					 2 changed files with 46 additions and 31 deletions
				
			
		| 
						 | 
					@ -535,7 +535,7 @@ config ZSWAP
 | 
				
			||||||
	bool "Compressed cache for swap pages (EXPERIMENTAL)"
 | 
						bool "Compressed cache for swap pages (EXPERIMENTAL)"
 | 
				
			||||||
	depends on FRONTSWAP && CRYPTO=y
 | 
						depends on FRONTSWAP && CRYPTO=y
 | 
				
			||||||
	select CRYPTO_LZO
 | 
						select CRYPTO_LZO
 | 
				
			||||||
	select ZBUD
 | 
						select ZPOOL
 | 
				
			||||||
	default n
 | 
						default n
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  A lightweight compressed cache for swap pages.  It takes
 | 
						  A lightweight compressed cache for swap pages.  It takes
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										75
									
								
								mm/zswap.c
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								mm/zswap.c
									
									
									
									
									
								
							| 
						 | 
					@ -34,7 +34,7 @@
 | 
				
			||||||
#include <linux/swap.h>
 | 
					#include <linux/swap.h>
 | 
				
			||||||
#include <linux/crypto.h>
 | 
					#include <linux/crypto.h>
 | 
				
			||||||
#include <linux/mempool.h>
 | 
					#include <linux/mempool.h>
 | 
				
			||||||
#include <linux/zbud.h>
 | 
					#include <linux/zpool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/mm_types.h>
 | 
					#include <linux/mm_types.h>
 | 
				
			||||||
#include <linux/page-flags.h>
 | 
					#include <linux/page-flags.h>
 | 
				
			||||||
| 
						 | 
					@ -45,8 +45,8 @@
 | 
				
			||||||
/*********************************
 | 
					/*********************************
 | 
				
			||||||
* statistics
 | 
					* statistics
 | 
				
			||||||
**********************************/
 | 
					**********************************/
 | 
				
			||||||
/* Number of memory pages used by the compressed pool */
 | 
					/* Total bytes used by the compressed storage */
 | 
				
			||||||
static u64 zswap_pool_pages;
 | 
					static u64 zswap_pool_total_size;
 | 
				
			||||||
/* The number of compressed pages currently stored in zswap */
 | 
					/* The number of compressed pages currently stored in zswap */
 | 
				
			||||||
static atomic_t zswap_stored_pages = ATOMIC_INIT(0);
 | 
					static atomic_t zswap_stored_pages = ATOMIC_INIT(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,8 +89,13 @@ static unsigned int zswap_max_pool_percent = 20;
 | 
				
			||||||
module_param_named(max_pool_percent,
 | 
					module_param_named(max_pool_percent,
 | 
				
			||||||
			zswap_max_pool_percent, uint, 0644);
 | 
								zswap_max_pool_percent, uint, 0644);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* zbud_pool is shared by all of zswap backend  */
 | 
					/* Compressed storage to use */
 | 
				
			||||||
static struct zbud_pool *zswap_pool;
 | 
					#define ZSWAP_ZPOOL_DEFAULT "zbud"
 | 
				
			||||||
 | 
					static char *zswap_zpool_type = ZSWAP_ZPOOL_DEFAULT;
 | 
				
			||||||
 | 
					module_param_named(zpool, zswap_zpool_type, charp, 0444);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* zpool is shared by all of zswap backend  */
 | 
				
			||||||
 | 
					static struct zpool *zswap_pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*********************************
 | 
					/*********************************
 | 
				
			||||||
* compression functions
 | 
					* compression functions
 | 
				
			||||||
| 
						 | 
					@ -168,7 +173,7 @@ static void zswap_comp_exit(void)
 | 
				
			||||||
 *            be held while changing the refcount.  Since the lock must
 | 
					 *            be held while changing the refcount.  Since the lock must
 | 
				
			||||||
 *            be held, there is no reason to also make refcount atomic.
 | 
					 *            be held, there is no reason to also make refcount atomic.
 | 
				
			||||||
 * offset - the swap offset for the entry.  Index into the red-black tree.
 | 
					 * offset - the swap offset for the entry.  Index into the red-black tree.
 | 
				
			||||||
 * handle - zbud allocation handle that stores the compressed page data
 | 
					 * handle - zpool allocation handle that stores the compressed page data
 | 
				
			||||||
 * length - the length in bytes of the compressed page data.  Needed during
 | 
					 * length - the length in bytes of the compressed page data.  Needed during
 | 
				
			||||||
 *          decompression
 | 
					 *          decompression
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -284,15 +289,15 @@ static void zswap_rb_erase(struct rb_root *root, struct zswap_entry *entry)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Carries out the common pattern of freeing and entry's zbud allocation,
 | 
					 * Carries out the common pattern of freeing and entry's zpool allocation,
 | 
				
			||||||
 * freeing the entry itself, and decrementing the number of stored pages.
 | 
					 * freeing the entry itself, and decrementing the number of stored pages.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void zswap_free_entry(struct zswap_entry *entry)
 | 
					static void zswap_free_entry(struct zswap_entry *entry)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	zbud_free(zswap_pool, entry->handle);
 | 
						zpool_free(zswap_pool, entry->handle);
 | 
				
			||||||
	zswap_entry_cache_free(entry);
 | 
						zswap_entry_cache_free(entry);
 | 
				
			||||||
	atomic_dec(&zswap_stored_pages);
 | 
						atomic_dec(&zswap_stored_pages);
 | 
				
			||||||
	zswap_pool_pages = zbud_get_pool_size(zswap_pool);
 | 
						zswap_pool_total_size = zpool_get_total_size(zswap_pool);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* caller must hold the tree lock */
 | 
					/* caller must hold the tree lock */
 | 
				
			||||||
| 
						 | 
					@ -409,7 +414,7 @@ static int zswap_cpu_init(void)
 | 
				
			||||||
static bool zswap_is_full(void)
 | 
					static bool zswap_is_full(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return totalram_pages * zswap_max_pool_percent / 100 <
 | 
						return totalram_pages * zswap_max_pool_percent / 100 <
 | 
				
			||||||
		zswap_pool_pages;
 | 
							DIV_ROUND_UP(zswap_pool_total_size, PAGE_SIZE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*********************************
 | 
					/*********************************
 | 
				
			||||||
| 
						 | 
					@ -525,7 +530,7 @@ static int zswap_get_swap_cache_page(swp_entry_t entry,
 | 
				
			||||||
 * the swap cache, the compressed version stored by zswap can be
 | 
					 * the swap cache, the compressed version stored by zswap can be
 | 
				
			||||||
 * freed.
 | 
					 * freed.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int zswap_writeback_entry(struct zbud_pool *pool, unsigned long handle)
 | 
					static int zswap_writeback_entry(struct zpool *pool, unsigned long handle)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct zswap_header *zhdr;
 | 
						struct zswap_header *zhdr;
 | 
				
			||||||
	swp_entry_t swpentry;
 | 
						swp_entry_t swpentry;
 | 
				
			||||||
| 
						 | 
					@ -541,9 +546,9 @@ static int zswap_writeback_entry(struct zbud_pool *pool, unsigned long handle)
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* extract swpentry from data */
 | 
						/* extract swpentry from data */
 | 
				
			||||||
	zhdr = zbud_map(pool, handle);
 | 
						zhdr = zpool_map_handle(pool, handle, ZPOOL_MM_RO);
 | 
				
			||||||
	swpentry = zhdr->swpentry; /* here */
 | 
						swpentry = zhdr->swpentry; /* here */
 | 
				
			||||||
	zbud_unmap(pool, handle);
 | 
						zpool_unmap_handle(pool, handle);
 | 
				
			||||||
	tree = zswap_trees[swp_type(swpentry)];
 | 
						tree = zswap_trees[swp_type(swpentry)];
 | 
				
			||||||
	offset = swp_offset(swpentry);
 | 
						offset = swp_offset(swpentry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -573,13 +578,13 @@ static int zswap_writeback_entry(struct zbud_pool *pool, unsigned long handle)
 | 
				
			||||||
	case ZSWAP_SWAPCACHE_NEW: /* page is locked */
 | 
						case ZSWAP_SWAPCACHE_NEW: /* page is locked */
 | 
				
			||||||
		/* decompress */
 | 
							/* decompress */
 | 
				
			||||||
		dlen = PAGE_SIZE;
 | 
							dlen = PAGE_SIZE;
 | 
				
			||||||
		src = (u8 *)zbud_map(zswap_pool, entry->handle) +
 | 
							src = (u8 *)zpool_map_handle(zswap_pool, entry->handle,
 | 
				
			||||||
			sizeof(struct zswap_header);
 | 
									ZPOOL_MM_RO) + sizeof(struct zswap_header);
 | 
				
			||||||
		dst = kmap_atomic(page);
 | 
							dst = kmap_atomic(page);
 | 
				
			||||||
		ret = zswap_comp_op(ZSWAP_COMPOP_DECOMPRESS, src,
 | 
							ret = zswap_comp_op(ZSWAP_COMPOP_DECOMPRESS, src,
 | 
				
			||||||
				entry->length, dst, &dlen);
 | 
									entry->length, dst, &dlen);
 | 
				
			||||||
		kunmap_atomic(dst);
 | 
							kunmap_atomic(dst);
 | 
				
			||||||
		zbud_unmap(zswap_pool, entry->handle);
 | 
							zpool_unmap_handle(zswap_pool, entry->handle);
 | 
				
			||||||
		BUG_ON(ret);
 | 
							BUG_ON(ret);
 | 
				
			||||||
		BUG_ON(dlen != PAGE_SIZE);
 | 
							BUG_ON(dlen != PAGE_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -652,7 +657,7 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset,
 | 
				
			||||||
	/* reclaim space if needed */
 | 
						/* reclaim space if needed */
 | 
				
			||||||
	if (zswap_is_full()) {
 | 
						if (zswap_is_full()) {
 | 
				
			||||||
		zswap_pool_limit_hit++;
 | 
							zswap_pool_limit_hit++;
 | 
				
			||||||
		if (zbud_reclaim_page(zswap_pool, 8)) {
 | 
							if (zpool_shrink(zswap_pool, 1, NULL)) {
 | 
				
			||||||
			zswap_reject_reclaim_fail++;
 | 
								zswap_reject_reclaim_fail++;
 | 
				
			||||||
			ret = -ENOMEM;
 | 
								ret = -ENOMEM;
 | 
				
			||||||
			goto reject;
 | 
								goto reject;
 | 
				
			||||||
| 
						 | 
					@ -679,7 +684,7 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* store */
 | 
						/* store */
 | 
				
			||||||
	len = dlen + sizeof(struct zswap_header);
 | 
						len = dlen + sizeof(struct zswap_header);
 | 
				
			||||||
	ret = zbud_alloc(zswap_pool, len, __GFP_NORETRY | __GFP_NOWARN,
 | 
						ret = zpool_malloc(zswap_pool, len, __GFP_NORETRY | __GFP_NOWARN,
 | 
				
			||||||
		&handle);
 | 
							&handle);
 | 
				
			||||||
	if (ret == -ENOSPC) {
 | 
						if (ret == -ENOSPC) {
 | 
				
			||||||
		zswap_reject_compress_poor++;
 | 
							zswap_reject_compress_poor++;
 | 
				
			||||||
| 
						 | 
					@ -689,11 +694,11 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset,
 | 
				
			||||||
		zswap_reject_alloc_fail++;
 | 
							zswap_reject_alloc_fail++;
 | 
				
			||||||
		goto freepage;
 | 
							goto freepage;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	zhdr = zbud_map(zswap_pool, handle);
 | 
						zhdr = zpool_map_handle(zswap_pool, handle, ZPOOL_MM_RW);
 | 
				
			||||||
	zhdr->swpentry = swp_entry(type, offset);
 | 
						zhdr->swpentry = swp_entry(type, offset);
 | 
				
			||||||
	buf = (u8 *)(zhdr + 1);
 | 
						buf = (u8 *)(zhdr + 1);
 | 
				
			||||||
	memcpy(buf, dst, dlen);
 | 
						memcpy(buf, dst, dlen);
 | 
				
			||||||
	zbud_unmap(zswap_pool, handle);
 | 
						zpool_unmap_handle(zswap_pool, handle);
 | 
				
			||||||
	put_cpu_var(zswap_dstmem);
 | 
						put_cpu_var(zswap_dstmem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* populate entry */
 | 
						/* populate entry */
 | 
				
			||||||
| 
						 | 
					@ -716,7 +721,7 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* update stats */
 | 
						/* update stats */
 | 
				
			||||||
	atomic_inc(&zswap_stored_pages);
 | 
						atomic_inc(&zswap_stored_pages);
 | 
				
			||||||
	zswap_pool_pages = zbud_get_pool_size(zswap_pool);
 | 
						zswap_pool_total_size = zpool_get_total_size(zswap_pool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -752,13 +757,13 @@ static int zswap_frontswap_load(unsigned type, pgoff_t offset,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* decompress */
 | 
						/* decompress */
 | 
				
			||||||
	dlen = PAGE_SIZE;
 | 
						dlen = PAGE_SIZE;
 | 
				
			||||||
	src = (u8 *)zbud_map(zswap_pool, entry->handle) +
 | 
						src = (u8 *)zpool_map_handle(zswap_pool, entry->handle,
 | 
				
			||||||
			sizeof(struct zswap_header);
 | 
								ZPOOL_MM_RO) + sizeof(struct zswap_header);
 | 
				
			||||||
	dst = kmap_atomic(page);
 | 
						dst = kmap_atomic(page);
 | 
				
			||||||
	ret = zswap_comp_op(ZSWAP_COMPOP_DECOMPRESS, src, entry->length,
 | 
						ret = zswap_comp_op(ZSWAP_COMPOP_DECOMPRESS, src, entry->length,
 | 
				
			||||||
		dst, &dlen);
 | 
							dst, &dlen);
 | 
				
			||||||
	kunmap_atomic(dst);
 | 
						kunmap_atomic(dst);
 | 
				
			||||||
	zbud_unmap(zswap_pool, entry->handle);
 | 
						zpool_unmap_handle(zswap_pool, entry->handle);
 | 
				
			||||||
	BUG_ON(ret);
 | 
						BUG_ON(ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&tree->lock);
 | 
						spin_lock(&tree->lock);
 | 
				
			||||||
| 
						 | 
					@ -811,7 +816,7 @@ static void zswap_frontswap_invalidate_area(unsigned type)
 | 
				
			||||||
	zswap_trees[type] = NULL;
 | 
						zswap_trees[type] = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct zbud_ops zswap_zbud_ops = {
 | 
					static struct zpool_ops zswap_zpool_ops = {
 | 
				
			||||||
	.evict = zswap_writeback_entry
 | 
						.evict = zswap_writeback_entry
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -869,8 +874,8 @@ static int __init zswap_debugfs_init(void)
 | 
				
			||||||
			zswap_debugfs_root, &zswap_written_back_pages);
 | 
								zswap_debugfs_root, &zswap_written_back_pages);
 | 
				
			||||||
	debugfs_create_u64("duplicate_entry", S_IRUGO,
 | 
						debugfs_create_u64("duplicate_entry", S_IRUGO,
 | 
				
			||||||
			zswap_debugfs_root, &zswap_duplicate_entry);
 | 
								zswap_debugfs_root, &zswap_duplicate_entry);
 | 
				
			||||||
	debugfs_create_u64("pool_pages", S_IRUGO,
 | 
						debugfs_create_u64("pool_total_size", S_IRUGO,
 | 
				
			||||||
			zswap_debugfs_root, &zswap_pool_pages);
 | 
								zswap_debugfs_root, &zswap_pool_total_size);
 | 
				
			||||||
	debugfs_create_atomic_t("stored_pages", S_IRUGO,
 | 
						debugfs_create_atomic_t("stored_pages", S_IRUGO,
 | 
				
			||||||
			zswap_debugfs_root, &zswap_stored_pages);
 | 
								zswap_debugfs_root, &zswap_stored_pages);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -895,16 +900,26 @@ static void __exit zswap_debugfs_exit(void) { }
 | 
				
			||||||
**********************************/
 | 
					**********************************/
 | 
				
			||||||
static int __init init_zswap(void)
 | 
					static int __init init_zswap(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						gfp_t gfp = __GFP_NORETRY | __GFP_NOWARN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!zswap_enabled)
 | 
						if (!zswap_enabled)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pr_info("loading zswap\n");
 | 
						pr_info("loading zswap\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	zswap_pool = zbud_create_pool(GFP_KERNEL, &zswap_zbud_ops);
 | 
						zswap_pool = zpool_create_pool(zswap_zpool_type, gfp, &zswap_zpool_ops);
 | 
				
			||||||
 | 
						if (!zswap_pool && strcmp(zswap_zpool_type, ZSWAP_ZPOOL_DEFAULT)) {
 | 
				
			||||||
 | 
							pr_info("%s zpool not available\n", zswap_zpool_type);
 | 
				
			||||||
 | 
							zswap_zpool_type = ZSWAP_ZPOOL_DEFAULT;
 | 
				
			||||||
 | 
							zswap_pool = zpool_create_pool(zswap_zpool_type, gfp,
 | 
				
			||||||
 | 
										&zswap_zpool_ops);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (!zswap_pool) {
 | 
						if (!zswap_pool) {
 | 
				
			||||||
		pr_err("zbud pool creation failed\n");
 | 
							pr_err("%s zpool not available\n", zswap_zpool_type);
 | 
				
			||||||
 | 
							pr_err("zpool creation failed\n");
 | 
				
			||||||
		goto error;
 | 
							goto error;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						pr_info("using %s pool\n", zswap_zpool_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (zswap_entry_cache_create()) {
 | 
						if (zswap_entry_cache_create()) {
 | 
				
			||||||
		pr_err("entry cache creation failed\n");
 | 
							pr_err("entry cache creation failed\n");
 | 
				
			||||||
| 
						 | 
					@ -928,7 +943,7 @@ static int __init init_zswap(void)
 | 
				
			||||||
compfail:
 | 
					compfail:
 | 
				
			||||||
	zswap_entry_cache_destory();
 | 
						zswap_entry_cache_destory();
 | 
				
			||||||
cachefail:
 | 
					cachefail:
 | 
				
			||||||
	zbud_destroy_pool(zswap_pool);
 | 
						zpool_destroy_pool(zswap_pool);
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
	return -ENOMEM;
 | 
						return -ENOMEM;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue