Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

zswap: change zpool/compressor at runtime

Update the zpool and compressor parameters to be changeable at runtime.
When changed, a new pool is created with the requested zpool/compressor,
and added as the current pool at the front of the pool list. Previous
pools remain in the list only to remove existing compressed pages from.
The old pool(s) are removed once they become empty.

Signed-off-by: Dan Streetman <ddstreet@ieee.org>
Acked-by: Seth Jennings <sjennings@variantweb.net>
Cc: Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Dan Streetman and committed by
Linus Torvalds
90b0fc26 f1c54846

+129 -13
+129 -13
mm/zswap.c
··· 80 80 static bool zswap_enabled; 81 81 module_param_named(enabled, zswap_enabled, bool, 0644); 82 82 83 - /* Compressor to be used by zswap (fixed at boot for now) */ 83 + /* Crypto compressor to use */ 84 84 #define ZSWAP_COMPRESSOR_DEFAULT "lzo" 85 - static char *zswap_compressor = ZSWAP_COMPRESSOR_DEFAULT; 86 - module_param_named(compressor, zswap_compressor, charp, 0444); 85 + static char zswap_compressor[CRYPTO_MAX_ALG_NAME] = ZSWAP_COMPRESSOR_DEFAULT; 86 + static struct kparam_string zswap_compressor_kparam = { 87 + .string = zswap_compressor, 88 + .maxlen = sizeof(zswap_compressor), 89 + }; 90 + static int zswap_compressor_param_set(const char *, 91 + const struct kernel_param *); 92 + static struct kernel_param_ops zswap_compressor_param_ops = { 93 + .set = zswap_compressor_param_set, 94 + .get = param_get_string, 95 + }; 96 + module_param_cb(compressor, &zswap_compressor_param_ops, 97 + &zswap_compressor_kparam, 0644); 98 + 99 + /* Compressed storage zpool to use */ 100 + #define ZSWAP_ZPOOL_DEFAULT "zbud" 101 + static char zswap_zpool_type[32 /* arbitrary */] = ZSWAP_ZPOOL_DEFAULT; 102 + static struct kparam_string zswap_zpool_kparam = { 103 + .string = zswap_zpool_type, 104 + .maxlen = sizeof(zswap_zpool_type), 105 + }; 106 + static int zswap_zpool_param_set(const char *, const struct kernel_param *); 107 + static struct kernel_param_ops zswap_zpool_param_ops = { 108 + .set = zswap_zpool_param_set, 109 + .get = param_get_string, 110 + }; 111 + module_param_cb(zpool, &zswap_zpool_param_ops, &zswap_zpool_kparam, 0644); 87 112 88 113 /* The maximum percentage of memory that the compressed pool can occupy */ 89 114 static unsigned int zswap_max_pool_percent = 20; 90 - module_param_named(max_pool_percent, 91 - zswap_max_pool_percent, uint, 0644); 92 - 93 - /* Compressed storage to use */ 94 - #define ZSWAP_ZPOOL_DEFAULT "zbud" 95 - static char *zswap_zpool_type = ZSWAP_ZPOOL_DEFAULT; 96 - module_param_named(zpool, zswap_zpool_type, charp, 0444); 97 - 98 - /* zpool is shared by all of zswap backend */ 99 - static struct zpool *zswap_pool; 115 + module_param_named(max_pool_percent, zswap_max_pool_percent, uint, 0644); 100 116 101 117 /********************************* 102 118 * data structures ··· 176 160 static LIST_HEAD(zswap_pools); 177 161 /* protects zswap_pools list modification */ 178 162 static DEFINE_SPINLOCK(zswap_pools_lock); 163 + 164 + /* used by param callback function */ 165 + static bool zswap_init_started; 179 166 180 167 /********************************* 181 168 * helpers and fwd declarations ··· 681 662 } 682 663 683 664 /********************************* 665 + * param callbacks 666 + **********************************/ 667 + 668 + static int __zswap_param_set(const char *val, const struct kernel_param *kp, 669 + char *type, char *compressor) 670 + { 671 + struct zswap_pool *pool, *put_pool = NULL; 672 + char str[kp->str->maxlen], *s; 673 + int ret; 674 + 675 + /* 676 + * kp is either zswap_zpool_kparam or zswap_compressor_kparam, defined 677 + * at the top of this file, so maxlen is CRYPTO_MAX_ALG_NAME (64) or 678 + * 32 (arbitrary). 679 + */ 680 + strlcpy(str, val, kp->str->maxlen); 681 + s = strim(str); 682 + 683 + /* if this is load-time (pre-init) param setting, 684 + * don't create a pool; that's done during init. 685 + */ 686 + if (!zswap_init_started) 687 + return param_set_copystring(s, kp); 688 + 689 + /* no change required */ 690 + if (!strncmp(kp->str->string, s, kp->str->maxlen)) 691 + return 0; 692 + 693 + if (!type) { 694 + type = s; 695 + if (!zpool_has_pool(type)) { 696 + pr_err("zpool %s not available\n", type); 697 + return -ENOENT; 698 + } 699 + } else if (!compressor) { 700 + compressor = s; 701 + if (!crypto_has_comp(compressor, 0, 0)) { 702 + pr_err("compressor %s not available\n", compressor); 703 + return -ENOENT; 704 + } 705 + } 706 + 707 + spin_lock(&zswap_pools_lock); 708 + 709 + pool = zswap_pool_find_get(type, compressor); 710 + if (pool) { 711 + zswap_pool_debug("using existing", pool); 712 + list_del_rcu(&pool->list); 713 + } else { 714 + spin_unlock(&zswap_pools_lock); 715 + pool = zswap_pool_create(type, compressor); 716 + spin_lock(&zswap_pools_lock); 717 + } 718 + 719 + if (pool) 720 + ret = param_set_copystring(s, kp); 721 + else 722 + ret = -EINVAL; 723 + 724 + if (!ret) { 725 + put_pool = zswap_pool_current(); 726 + list_add_rcu(&pool->list, &zswap_pools); 727 + } else if (pool) { 728 + /* add the possibly pre-existing pool to the end of the pools 729 + * list; if it's new (and empty) then it'll be removed and 730 + * destroyed by the put after we drop the lock 731 + */ 732 + list_add_tail_rcu(&pool->list, &zswap_pools); 733 + put_pool = pool; 734 + } 735 + 736 + spin_unlock(&zswap_pools_lock); 737 + 738 + /* drop the ref from either the old current pool, 739 + * or the new pool we failed to add 740 + */ 741 + if (put_pool) 742 + zswap_pool_put(put_pool); 743 + 744 + return ret; 745 + } 746 + 747 + static int zswap_compressor_param_set(const char *val, 748 + const struct kernel_param *kp) 749 + { 750 + return __zswap_param_set(val, kp, zswap_zpool_type, NULL); 751 + } 752 + 753 + static int zswap_zpool_param_set(const char *val, 754 + const struct kernel_param *kp) 755 + { 756 + return __zswap_param_set(val, kp, NULL, zswap_compressor); 757 + } 758 + 759 + /********************************* 684 760 * writeback code 685 761 **********************************/ 686 762 /* return enum for zswap_get_swap_cache_page */ ··· 1227 1113 static int __init init_zswap(void) 1228 1114 { 1229 1115 struct zswap_pool *pool; 1116 + 1117 + zswap_init_started = true; 1230 1118 1231 1119 if (zswap_entry_cache_create()) { 1232 1120 pr_err("entry cache creation failed\n");