diff options
Diffstat (limited to 'mm/zswap.c')
| -rw-r--r-- | mm/zswap.c | 172 | 
1 files changed, 51 insertions, 121 deletions
| diff --git a/mm/zswap.c b/mm/zswap.c index 275b22cc8df4..067a0d62f318 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -118,7 +118,7 @@ struct zswap_pool {  	struct kref kref;  	struct list_head list;  	struct work_struct work; -	struct notifier_block notifier; +	struct hlist_node node;  	char tfm_name[CRYPTO_MAX_ALG_NAME];  }; @@ -352,143 +352,58 @@ static struct zswap_entry *zswap_entry_find_get(struct rb_root *root,  **********************************/  static DEFINE_PER_CPU(u8 *, zswap_dstmem); -static int __zswap_cpu_dstmem_notifier(unsigned long action, unsigned long cpu) +static int zswap_dstmem_prepare(unsigned int cpu)  {  	u8 *dst; -	switch (action) { -	case CPU_UP_PREPARE: -		dst = kmalloc_node(PAGE_SIZE * 2, GFP_KERNEL, cpu_to_node(cpu)); -		if (!dst) { -			pr_err("can't allocate compressor buffer\n"); -			return NOTIFY_BAD; -		} -		per_cpu(zswap_dstmem, cpu) = dst; -		break; -	case CPU_DEAD: -	case CPU_UP_CANCELED: -		dst = per_cpu(zswap_dstmem, cpu); -		kfree(dst); -		per_cpu(zswap_dstmem, cpu) = NULL; -		break; -	default: -		break; +	dst = kmalloc_node(PAGE_SIZE * 2, GFP_KERNEL, cpu_to_node(cpu)); +	if (!dst) { +		pr_err("can't allocate compressor buffer\n"); +		return -ENOMEM;  	} -	return NOTIFY_OK; +	per_cpu(zswap_dstmem, cpu) = dst; +	return 0;  } -static int zswap_cpu_dstmem_notifier(struct notifier_block *nb, -				     unsigned long action, void *pcpu) +static int zswap_dstmem_dead(unsigned int cpu)  { -	return __zswap_cpu_dstmem_notifier(action, (unsigned long)pcpu); -} +	u8 *dst; -static struct notifier_block zswap_dstmem_notifier = { -	.notifier_call =	zswap_cpu_dstmem_notifier, -}; +	dst = per_cpu(zswap_dstmem, cpu); +	kfree(dst); +	per_cpu(zswap_dstmem, cpu) = NULL; -static int __init zswap_cpu_dstmem_init(void) -{ -	unsigned long cpu; - -	cpu_notifier_register_begin(); -	for_each_online_cpu(cpu) -		if (__zswap_cpu_dstmem_notifier(CPU_UP_PREPARE, cpu) == -		    NOTIFY_BAD) -			goto cleanup; -	__register_cpu_notifier(&zswap_dstmem_notifier); -	cpu_notifier_register_done();  	return 0; - -cleanup: -	for_each_online_cpu(cpu) -		__zswap_cpu_dstmem_notifier(CPU_UP_CANCELED, cpu); -	cpu_notifier_register_done(); -	return -ENOMEM; -} - -static void zswap_cpu_dstmem_destroy(void) -{ -	unsigned long cpu; - -	cpu_notifier_register_begin(); -	for_each_online_cpu(cpu) -		__zswap_cpu_dstmem_notifier(CPU_UP_CANCELED, cpu); -	__unregister_cpu_notifier(&zswap_dstmem_notifier); -	cpu_notifier_register_done();  } -static int __zswap_cpu_comp_notifier(struct zswap_pool *pool, -				     unsigned long action, unsigned long cpu) +static int zswap_cpu_comp_prepare(unsigned int cpu, struct hlist_node *node)  { +	struct zswap_pool *pool = hlist_entry(node, struct zswap_pool, node);  	struct crypto_comp *tfm; -	switch (action) { -	case CPU_UP_PREPARE: -		if (WARN_ON(*per_cpu_ptr(pool->tfm, cpu))) -			break; -		tfm = crypto_alloc_comp(pool->tfm_name, 0, 0); -		if (IS_ERR_OR_NULL(tfm)) { -			pr_err("could not alloc crypto comp %s : %ld\n", -			       pool->tfm_name, PTR_ERR(tfm)); -			return NOTIFY_BAD; -		} -		*per_cpu_ptr(pool->tfm, cpu) = tfm; -		break; -	case CPU_DEAD: -	case CPU_UP_CANCELED: -		tfm = *per_cpu_ptr(pool->tfm, cpu); -		if (!IS_ERR_OR_NULL(tfm)) -			crypto_free_comp(tfm); -		*per_cpu_ptr(pool->tfm, cpu) = NULL; -		break; -	default: -		break; -	} -	return NOTIFY_OK; -} - -static int zswap_cpu_comp_notifier(struct notifier_block *nb, -				   unsigned long action, void *pcpu) -{ -	unsigned long cpu = (unsigned long)pcpu; -	struct zswap_pool *pool = container_of(nb, typeof(*pool), notifier); - -	return __zswap_cpu_comp_notifier(pool, action, cpu); -} +	if (WARN_ON(*per_cpu_ptr(pool->tfm, cpu))) +		return 0; -static int zswap_cpu_comp_init(struct zswap_pool *pool) -{ -	unsigned long cpu; - -	memset(&pool->notifier, 0, sizeof(pool->notifier)); -	pool->notifier.notifier_call = zswap_cpu_comp_notifier; - -	cpu_notifier_register_begin(); -	for_each_online_cpu(cpu) -		if (__zswap_cpu_comp_notifier(pool, CPU_UP_PREPARE, cpu) == -		    NOTIFY_BAD) -			goto cleanup; -	__register_cpu_notifier(&pool->notifier); -	cpu_notifier_register_done(); +	tfm = crypto_alloc_comp(pool->tfm_name, 0, 0); +	if (IS_ERR_OR_NULL(tfm)) { +		pr_err("could not alloc crypto comp %s : %ld\n", +		       pool->tfm_name, PTR_ERR(tfm)); +		return -ENOMEM; +	} +	*per_cpu_ptr(pool->tfm, cpu) = tfm;  	return 0; - -cleanup: -	for_each_online_cpu(cpu) -		__zswap_cpu_comp_notifier(pool, CPU_UP_CANCELED, cpu); -	cpu_notifier_register_done(); -	return -ENOMEM;  } -static void zswap_cpu_comp_destroy(struct zswap_pool *pool) +static int zswap_cpu_comp_dead(unsigned int cpu, struct hlist_node *node)  { -	unsigned long cpu; +	struct zswap_pool *pool = hlist_entry(node, struct zswap_pool, node); +	struct crypto_comp *tfm; -	cpu_notifier_register_begin(); -	for_each_online_cpu(cpu) -		__zswap_cpu_comp_notifier(pool, CPU_UP_CANCELED, cpu); -	__unregister_cpu_notifier(&pool->notifier); -	cpu_notifier_register_done(); +	tfm = *per_cpu_ptr(pool->tfm, cpu); +	if (!IS_ERR_OR_NULL(tfm)) +		crypto_free_comp(tfm); +	*per_cpu_ptr(pool->tfm, cpu) = NULL; +	return 0;  }  /********************************* @@ -569,6 +484,7 @@ static struct zswap_pool *zswap_pool_create(char *type, char *compressor)  	struct zswap_pool *pool;  	char name[38]; /* 'zswap' + 32 char (max) num + \0 */  	gfp_t gfp = __GFP_NORETRY | __GFP_NOWARN | __GFP_KSWAPD_RECLAIM; +	int ret;  	pool = kzalloc(sizeof(*pool), GFP_KERNEL);  	if (!pool) { @@ -593,7 +509,9 @@ static struct zswap_pool *zswap_pool_create(char *type, char *compressor)  		goto error;  	} -	if (zswap_cpu_comp_init(pool)) +	ret = cpuhp_state_add_instance(CPUHP_MM_ZSWP_POOL_PREPARE, +				       &pool->node); +	if (ret)  		goto error;  	pr_debug("using %s compressor\n", pool->tfm_name); @@ -647,7 +565,7 @@ static void zswap_pool_destroy(struct zswap_pool *pool)  {  	zswap_pool_debug("destroying", pool); -	zswap_cpu_comp_destroy(pool); +	cpuhp_state_remove_instance(CPUHP_MM_ZSWP_POOL_PREPARE, &pool->node);  	free_percpu(pool->tfm);  	zpool_destroy_pool(pool->zpool);  	kfree(pool); @@ -1238,6 +1156,7 @@ static void __exit zswap_debugfs_exit(void) { }  static int __init init_zswap(void)  {  	struct zswap_pool *pool; +	int ret;  	zswap_init_started = true; @@ -1246,11 +1165,20 @@ static int __init init_zswap(void)  		goto cache_fail;  	} -	if (zswap_cpu_dstmem_init()) { +	ret = cpuhp_setup_state(CPUHP_MM_ZSWP_MEM_PREPARE, "mm/zswap:prepare", +				zswap_dstmem_prepare, zswap_dstmem_dead); +	if (ret) {  		pr_err("dstmem alloc failed\n");  		goto dstmem_fail;  	} +	ret = cpuhp_setup_state_multi(CPUHP_MM_ZSWP_POOL_PREPARE, +				      "mm/zswap_pool:prepare", +				      zswap_cpu_comp_prepare, +				      zswap_cpu_comp_dead); +	if (ret) +		goto hp_fail; +  	pool = __zswap_pool_create_fallback();  	if (!pool) {  		pr_err("pool creation failed\n"); @@ -1267,7 +1195,9 @@ static int __init init_zswap(void)  	return 0;  pool_fail: -	zswap_cpu_dstmem_destroy(); +	cpuhp_remove_state_nocalls(CPUHP_MM_ZSWP_POOL_PREPARE); +hp_fail: +	cpuhp_remove_state(CPUHP_MM_ZSWP_MEM_PREPARE);  dstmem_fail:  	zswap_entry_cache_destroy();  cache_fail: |