162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * zswap.c - zswap driver file 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * zswap is a cache that takes pages that are in the process 662306a36Sopenharmony_ci * of being swapped out and attempts to compress and store them in a 762306a36Sopenharmony_ci * RAM-based memory pool. This can result in a significant I/O reduction on 862306a36Sopenharmony_ci * the swap device and, in the case where decompressing from RAM is faster 962306a36Sopenharmony_ci * than reading from the swap device, can also improve workload performance. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Copyright (C) 2012 Seth Jennings <sjenning@linux.vnet.ibm.com> 1262306a36Sopenharmony_ci*/ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/cpu.h> 1862306a36Sopenharmony_ci#include <linux/highmem.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/spinlock.h> 2162306a36Sopenharmony_ci#include <linux/types.h> 2262306a36Sopenharmony_ci#include <linux/atomic.h> 2362306a36Sopenharmony_ci#include <linux/rbtree.h> 2462306a36Sopenharmony_ci#include <linux/swap.h> 2562306a36Sopenharmony_ci#include <linux/crypto.h> 2662306a36Sopenharmony_ci#include <linux/scatterlist.h> 2762306a36Sopenharmony_ci#include <linux/mempool.h> 2862306a36Sopenharmony_ci#include <linux/zpool.h> 2962306a36Sopenharmony_ci#include <crypto/acompress.h> 3062306a36Sopenharmony_ci#include <linux/zswap.h> 3162306a36Sopenharmony_ci#include <linux/mm_types.h> 3262306a36Sopenharmony_ci#include <linux/page-flags.h> 3362306a36Sopenharmony_ci#include <linux/swapops.h> 3462306a36Sopenharmony_ci#include <linux/writeback.h> 3562306a36Sopenharmony_ci#include <linux/pagemap.h> 3662306a36Sopenharmony_ci#include <linux/workqueue.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include "swap.h" 3962306a36Sopenharmony_ci#include "internal.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/********************************* 4262306a36Sopenharmony_ci* statistics 4362306a36Sopenharmony_ci**********************************/ 4462306a36Sopenharmony_ci/* Total bytes used by the compressed storage */ 4562306a36Sopenharmony_ciu64 zswap_pool_total_size; 4662306a36Sopenharmony_ci/* The number of compressed pages currently stored in zswap */ 4762306a36Sopenharmony_ciatomic_t zswap_stored_pages = ATOMIC_INIT(0); 4862306a36Sopenharmony_ci/* The number of same-value filled pages currently stored in zswap */ 4962306a36Sopenharmony_cistatic atomic_t zswap_same_filled_pages = ATOMIC_INIT(0); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* 5262306a36Sopenharmony_ci * The statistics below are not protected from concurrent access for 5362306a36Sopenharmony_ci * performance reasons so they may not be a 100% accurate. However, 5462306a36Sopenharmony_ci * they do provide useful information on roughly how many times a 5562306a36Sopenharmony_ci * certain event is occurring. 5662306a36Sopenharmony_ci*/ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* Pool limit was hit (see zswap_max_pool_percent) */ 5962306a36Sopenharmony_cistatic u64 zswap_pool_limit_hit; 6062306a36Sopenharmony_ci/* Pages written back when pool limit was reached */ 6162306a36Sopenharmony_cistatic u64 zswap_written_back_pages; 6262306a36Sopenharmony_ci/* Store failed due to a reclaim failure after pool limit was reached */ 6362306a36Sopenharmony_cistatic u64 zswap_reject_reclaim_fail; 6462306a36Sopenharmony_ci/* Compressed page was too big for the allocator to (optimally) store */ 6562306a36Sopenharmony_cistatic u64 zswap_reject_compress_poor; 6662306a36Sopenharmony_ci/* Store failed because underlying allocator could not get memory */ 6762306a36Sopenharmony_cistatic u64 zswap_reject_alloc_fail; 6862306a36Sopenharmony_ci/* Store failed because the entry metadata could not be allocated (rare) */ 6962306a36Sopenharmony_cistatic u64 zswap_reject_kmemcache_fail; 7062306a36Sopenharmony_ci/* Duplicate store was encountered (rare) */ 7162306a36Sopenharmony_cistatic u64 zswap_duplicate_entry; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* Shrinker work queue */ 7462306a36Sopenharmony_cistatic struct workqueue_struct *shrink_wq; 7562306a36Sopenharmony_ci/* Pool limit was hit, we need to calm down */ 7662306a36Sopenharmony_cistatic bool zswap_pool_reached_full; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/********************************* 7962306a36Sopenharmony_ci* tunables 8062306a36Sopenharmony_ci**********************************/ 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#define ZSWAP_PARAM_UNSET "" 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int zswap_setup(void); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* Enable/disable zswap */ 8762306a36Sopenharmony_cistatic bool zswap_enabled = IS_ENABLED(CONFIG_ZSWAP_DEFAULT_ON); 8862306a36Sopenharmony_cistatic int zswap_enabled_param_set(const char *, 8962306a36Sopenharmony_ci const struct kernel_param *); 9062306a36Sopenharmony_cistatic const struct kernel_param_ops zswap_enabled_param_ops = { 9162306a36Sopenharmony_ci .set = zswap_enabled_param_set, 9262306a36Sopenharmony_ci .get = param_get_bool, 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_cimodule_param_cb(enabled, &zswap_enabled_param_ops, &zswap_enabled, 0644); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* Crypto compressor to use */ 9762306a36Sopenharmony_cistatic char *zswap_compressor = CONFIG_ZSWAP_COMPRESSOR_DEFAULT; 9862306a36Sopenharmony_cistatic int zswap_compressor_param_set(const char *, 9962306a36Sopenharmony_ci const struct kernel_param *); 10062306a36Sopenharmony_cistatic const struct kernel_param_ops zswap_compressor_param_ops = { 10162306a36Sopenharmony_ci .set = zswap_compressor_param_set, 10262306a36Sopenharmony_ci .get = param_get_charp, 10362306a36Sopenharmony_ci .free = param_free_charp, 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_cimodule_param_cb(compressor, &zswap_compressor_param_ops, 10662306a36Sopenharmony_ci &zswap_compressor, 0644); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* Compressed storage zpool to use */ 10962306a36Sopenharmony_cistatic char *zswap_zpool_type = CONFIG_ZSWAP_ZPOOL_DEFAULT; 11062306a36Sopenharmony_cistatic int zswap_zpool_param_set(const char *, const struct kernel_param *); 11162306a36Sopenharmony_cistatic const struct kernel_param_ops zswap_zpool_param_ops = { 11262306a36Sopenharmony_ci .set = zswap_zpool_param_set, 11362306a36Sopenharmony_ci .get = param_get_charp, 11462306a36Sopenharmony_ci .free = param_free_charp, 11562306a36Sopenharmony_ci}; 11662306a36Sopenharmony_cimodule_param_cb(zpool, &zswap_zpool_param_ops, &zswap_zpool_type, 0644); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* The maximum percentage of memory that the compressed pool can occupy */ 11962306a36Sopenharmony_cistatic unsigned int zswap_max_pool_percent = 20; 12062306a36Sopenharmony_cimodule_param_named(max_pool_percent, zswap_max_pool_percent, uint, 0644); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* The threshold for accepting new pages after the max_pool_percent was hit */ 12362306a36Sopenharmony_cistatic unsigned int zswap_accept_thr_percent = 90; /* of max pool size */ 12462306a36Sopenharmony_cimodule_param_named(accept_threshold_percent, zswap_accept_thr_percent, 12562306a36Sopenharmony_ci uint, 0644); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* 12862306a36Sopenharmony_ci * Enable/disable handling same-value filled pages (enabled by default). 12962306a36Sopenharmony_ci * If disabled every page is considered non-same-value filled. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_cistatic bool zswap_same_filled_pages_enabled = true; 13262306a36Sopenharmony_cimodule_param_named(same_filled_pages_enabled, zswap_same_filled_pages_enabled, 13362306a36Sopenharmony_ci bool, 0644); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* Enable/disable handling non-same-value filled pages (enabled by default) */ 13662306a36Sopenharmony_cistatic bool zswap_non_same_filled_pages_enabled = true; 13762306a36Sopenharmony_cimodule_param_named(non_same_filled_pages_enabled, zswap_non_same_filled_pages_enabled, 13862306a36Sopenharmony_ci bool, 0644); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic bool zswap_exclusive_loads_enabled = IS_ENABLED( 14162306a36Sopenharmony_ci CONFIG_ZSWAP_EXCLUSIVE_LOADS_DEFAULT_ON); 14262306a36Sopenharmony_cimodule_param_named(exclusive_loads, zswap_exclusive_loads_enabled, bool, 0644); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* Number of zpools in zswap_pool (empirically determined for scalability) */ 14562306a36Sopenharmony_ci#define ZSWAP_NR_ZPOOLS 32 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/********************************* 14862306a36Sopenharmony_ci* data structures 14962306a36Sopenharmony_ci**********************************/ 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistruct crypto_acomp_ctx { 15262306a36Sopenharmony_ci struct crypto_acomp *acomp; 15362306a36Sopenharmony_ci struct acomp_req *req; 15462306a36Sopenharmony_ci struct crypto_wait wait; 15562306a36Sopenharmony_ci u8 *dstmem; 15662306a36Sopenharmony_ci struct mutex *mutex; 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* 16062306a36Sopenharmony_ci * The lock ordering is zswap_tree.lock -> zswap_pool.lru_lock. 16162306a36Sopenharmony_ci * The only case where lru_lock is not acquired while holding tree.lock is 16262306a36Sopenharmony_ci * when a zswap_entry is taken off the lru for writeback, in that case it 16362306a36Sopenharmony_ci * needs to be verified that it's still valid in the tree. 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_cistruct zswap_pool { 16662306a36Sopenharmony_ci struct zpool *zpools[ZSWAP_NR_ZPOOLS]; 16762306a36Sopenharmony_ci struct crypto_acomp_ctx __percpu *acomp_ctx; 16862306a36Sopenharmony_ci struct kref kref; 16962306a36Sopenharmony_ci struct list_head list; 17062306a36Sopenharmony_ci struct work_struct release_work; 17162306a36Sopenharmony_ci struct work_struct shrink_work; 17262306a36Sopenharmony_ci struct hlist_node node; 17362306a36Sopenharmony_ci char tfm_name[CRYPTO_MAX_ALG_NAME]; 17462306a36Sopenharmony_ci struct list_head lru; 17562306a36Sopenharmony_ci spinlock_t lru_lock; 17662306a36Sopenharmony_ci}; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* 17962306a36Sopenharmony_ci * struct zswap_entry 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci * This structure contains the metadata for tracking a single compressed 18262306a36Sopenharmony_ci * page within zswap. 18362306a36Sopenharmony_ci * 18462306a36Sopenharmony_ci * rbnode - links the entry into red-black tree for the appropriate swap type 18562306a36Sopenharmony_ci * swpentry - associated swap entry, the offset indexes into the red-black tree 18662306a36Sopenharmony_ci * refcount - the number of outstanding reference to the entry. This is needed 18762306a36Sopenharmony_ci * to protect against premature freeing of the entry by code 18862306a36Sopenharmony_ci * concurrent calls to load, invalidate, and writeback. The lock 18962306a36Sopenharmony_ci * for the zswap_tree structure that contains the entry must 19062306a36Sopenharmony_ci * be held while changing the refcount. Since the lock must 19162306a36Sopenharmony_ci * be held, there is no reason to also make refcount atomic. 19262306a36Sopenharmony_ci * length - the length in bytes of the compressed page data. Needed during 19362306a36Sopenharmony_ci * decompression. For a same value filled page length is 0, and both 19462306a36Sopenharmony_ci * pool and lru are invalid and must be ignored. 19562306a36Sopenharmony_ci * pool - the zswap_pool the entry's data is in 19662306a36Sopenharmony_ci * handle - zpool allocation handle that stores the compressed page data 19762306a36Sopenharmony_ci * value - value of the same-value filled pages which have same content 19862306a36Sopenharmony_ci * objcg - the obj_cgroup that the compressed memory is charged to 19962306a36Sopenharmony_ci * lru - handle to the pool's lru used to evict pages. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_cistruct zswap_entry { 20262306a36Sopenharmony_ci struct rb_node rbnode; 20362306a36Sopenharmony_ci swp_entry_t swpentry; 20462306a36Sopenharmony_ci int refcount; 20562306a36Sopenharmony_ci unsigned int length; 20662306a36Sopenharmony_ci struct zswap_pool *pool; 20762306a36Sopenharmony_ci union { 20862306a36Sopenharmony_ci unsigned long handle; 20962306a36Sopenharmony_ci unsigned long value; 21062306a36Sopenharmony_ci }; 21162306a36Sopenharmony_ci struct obj_cgroup *objcg; 21262306a36Sopenharmony_ci struct list_head lru; 21362306a36Sopenharmony_ci}; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci/* 21662306a36Sopenharmony_ci * The tree lock in the zswap_tree struct protects a few things: 21762306a36Sopenharmony_ci * - the rbtree 21862306a36Sopenharmony_ci * - the refcount field of each entry in the tree 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_cistruct zswap_tree { 22162306a36Sopenharmony_ci struct rb_root rbroot; 22262306a36Sopenharmony_ci spinlock_t lock; 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic struct zswap_tree *zswap_trees[MAX_SWAPFILES]; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/* RCU-protected iteration */ 22862306a36Sopenharmony_cistatic LIST_HEAD(zswap_pools); 22962306a36Sopenharmony_ci/* protects zswap_pools list modification */ 23062306a36Sopenharmony_cistatic DEFINE_SPINLOCK(zswap_pools_lock); 23162306a36Sopenharmony_ci/* pool counter to provide unique names to zpool */ 23262306a36Sopenharmony_cistatic atomic_t zswap_pools_count = ATOMIC_INIT(0); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cienum zswap_init_type { 23562306a36Sopenharmony_ci ZSWAP_UNINIT, 23662306a36Sopenharmony_ci ZSWAP_INIT_SUCCEED, 23762306a36Sopenharmony_ci ZSWAP_INIT_FAILED 23862306a36Sopenharmony_ci}; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic enum zswap_init_type zswap_init_state; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* used to ensure the integrity of initialization */ 24362306a36Sopenharmony_cistatic DEFINE_MUTEX(zswap_init_lock); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci/* init completed, but couldn't create the initial pool */ 24662306a36Sopenharmony_cistatic bool zswap_has_pool; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci/********************************* 24962306a36Sopenharmony_ci* helpers and fwd declarations 25062306a36Sopenharmony_ci**********************************/ 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci#define zswap_pool_debug(msg, p) \ 25362306a36Sopenharmony_ci pr_debug("%s pool %s/%s\n", msg, (p)->tfm_name, \ 25462306a36Sopenharmony_ci zpool_get_type((p)->zpools[0])) 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic int zswap_writeback_entry(struct zswap_entry *entry, 25762306a36Sopenharmony_ci struct zswap_tree *tree); 25862306a36Sopenharmony_cistatic int zswap_pool_get(struct zswap_pool *pool); 25962306a36Sopenharmony_cistatic void zswap_pool_put(struct zswap_pool *pool); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic bool zswap_is_full(void) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci return totalram_pages() * zswap_max_pool_percent / 100 < 26462306a36Sopenharmony_ci DIV_ROUND_UP(zswap_pool_total_size, PAGE_SIZE); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic bool zswap_can_accept(void) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci return totalram_pages() * zswap_accept_thr_percent / 100 * 27062306a36Sopenharmony_ci zswap_max_pool_percent / 100 > 27162306a36Sopenharmony_ci DIV_ROUND_UP(zswap_pool_total_size, PAGE_SIZE); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic void zswap_update_total_size(void) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct zswap_pool *pool; 27762306a36Sopenharmony_ci u64 total = 0; 27862306a36Sopenharmony_ci int i; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci rcu_read_lock(); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci list_for_each_entry_rcu(pool, &zswap_pools, list) 28362306a36Sopenharmony_ci for (i = 0; i < ZSWAP_NR_ZPOOLS; i++) 28462306a36Sopenharmony_ci total += zpool_get_total_size(pool->zpools[i]); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci rcu_read_unlock(); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci zswap_pool_total_size = total; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/********************************* 29262306a36Sopenharmony_ci* zswap entry functions 29362306a36Sopenharmony_ci**********************************/ 29462306a36Sopenharmony_cistatic struct kmem_cache *zswap_entry_cache; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic struct zswap_entry *zswap_entry_cache_alloc(gfp_t gfp) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct zswap_entry *entry; 29962306a36Sopenharmony_ci entry = kmem_cache_alloc(zswap_entry_cache, gfp); 30062306a36Sopenharmony_ci if (!entry) 30162306a36Sopenharmony_ci return NULL; 30262306a36Sopenharmony_ci entry->refcount = 1; 30362306a36Sopenharmony_ci RB_CLEAR_NODE(&entry->rbnode); 30462306a36Sopenharmony_ci return entry; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic void zswap_entry_cache_free(struct zswap_entry *entry) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci kmem_cache_free(zswap_entry_cache, entry); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci/********************************* 31362306a36Sopenharmony_ci* rbtree functions 31462306a36Sopenharmony_ci**********************************/ 31562306a36Sopenharmony_cistatic struct zswap_entry *zswap_rb_search(struct rb_root *root, pgoff_t offset) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct rb_node *node = root->rb_node; 31862306a36Sopenharmony_ci struct zswap_entry *entry; 31962306a36Sopenharmony_ci pgoff_t entry_offset; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci while (node) { 32262306a36Sopenharmony_ci entry = rb_entry(node, struct zswap_entry, rbnode); 32362306a36Sopenharmony_ci entry_offset = swp_offset(entry->swpentry); 32462306a36Sopenharmony_ci if (entry_offset > offset) 32562306a36Sopenharmony_ci node = node->rb_left; 32662306a36Sopenharmony_ci else if (entry_offset < offset) 32762306a36Sopenharmony_ci node = node->rb_right; 32862306a36Sopenharmony_ci else 32962306a36Sopenharmony_ci return entry; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci return NULL; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci/* 33562306a36Sopenharmony_ci * In the case that a entry with the same offset is found, a pointer to 33662306a36Sopenharmony_ci * the existing entry is stored in dupentry and the function returns -EEXIST 33762306a36Sopenharmony_ci */ 33862306a36Sopenharmony_cistatic int zswap_rb_insert(struct rb_root *root, struct zswap_entry *entry, 33962306a36Sopenharmony_ci struct zswap_entry **dupentry) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct rb_node **link = &root->rb_node, *parent = NULL; 34262306a36Sopenharmony_ci struct zswap_entry *myentry; 34362306a36Sopenharmony_ci pgoff_t myentry_offset, entry_offset = swp_offset(entry->swpentry); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci while (*link) { 34662306a36Sopenharmony_ci parent = *link; 34762306a36Sopenharmony_ci myentry = rb_entry(parent, struct zswap_entry, rbnode); 34862306a36Sopenharmony_ci myentry_offset = swp_offset(myentry->swpentry); 34962306a36Sopenharmony_ci if (myentry_offset > entry_offset) 35062306a36Sopenharmony_ci link = &(*link)->rb_left; 35162306a36Sopenharmony_ci else if (myentry_offset < entry_offset) 35262306a36Sopenharmony_ci link = &(*link)->rb_right; 35362306a36Sopenharmony_ci else { 35462306a36Sopenharmony_ci *dupentry = myentry; 35562306a36Sopenharmony_ci return -EEXIST; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci rb_link_node(&entry->rbnode, parent, link); 35962306a36Sopenharmony_ci rb_insert_color(&entry->rbnode, root); 36062306a36Sopenharmony_ci return 0; 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic bool zswap_rb_erase(struct rb_root *root, struct zswap_entry *entry) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci if (!RB_EMPTY_NODE(&entry->rbnode)) { 36662306a36Sopenharmony_ci rb_erase(&entry->rbnode, root); 36762306a36Sopenharmony_ci RB_CLEAR_NODE(&entry->rbnode); 36862306a36Sopenharmony_ci return true; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci return false; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic struct zpool *zswap_find_zpool(struct zswap_entry *entry) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci int i = 0; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (ZSWAP_NR_ZPOOLS > 1) 37862306a36Sopenharmony_ci i = hash_ptr(entry, ilog2(ZSWAP_NR_ZPOOLS)); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return entry->pool->zpools[i]; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci/* 38462306a36Sopenharmony_ci * Carries out the common pattern of freeing and entry's zpool allocation, 38562306a36Sopenharmony_ci * freeing the entry itself, and decrementing the number of stored pages. 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_cistatic void zswap_free_entry(struct zswap_entry *entry) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci if (entry->objcg) { 39062306a36Sopenharmony_ci obj_cgroup_uncharge_zswap(entry->objcg, entry->length); 39162306a36Sopenharmony_ci obj_cgroup_put(entry->objcg); 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci if (!entry->length) 39462306a36Sopenharmony_ci atomic_dec(&zswap_same_filled_pages); 39562306a36Sopenharmony_ci else { 39662306a36Sopenharmony_ci spin_lock(&entry->pool->lru_lock); 39762306a36Sopenharmony_ci list_del(&entry->lru); 39862306a36Sopenharmony_ci spin_unlock(&entry->pool->lru_lock); 39962306a36Sopenharmony_ci zpool_free(zswap_find_zpool(entry), entry->handle); 40062306a36Sopenharmony_ci zswap_pool_put(entry->pool); 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci zswap_entry_cache_free(entry); 40362306a36Sopenharmony_ci atomic_dec(&zswap_stored_pages); 40462306a36Sopenharmony_ci zswap_update_total_size(); 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci/* caller must hold the tree lock */ 40862306a36Sopenharmony_cistatic void zswap_entry_get(struct zswap_entry *entry) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci entry->refcount++; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci/* caller must hold the tree lock 41462306a36Sopenharmony_ci* remove from the tree and free it, if nobody reference the entry 41562306a36Sopenharmony_ci*/ 41662306a36Sopenharmony_cistatic void zswap_entry_put(struct zswap_tree *tree, 41762306a36Sopenharmony_ci struct zswap_entry *entry) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci int refcount = --entry->refcount; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci WARN_ON_ONCE(refcount < 0); 42262306a36Sopenharmony_ci if (refcount == 0) { 42362306a36Sopenharmony_ci WARN_ON_ONCE(!RB_EMPTY_NODE(&entry->rbnode)); 42462306a36Sopenharmony_ci zswap_free_entry(entry); 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci/* caller must hold the tree lock */ 42962306a36Sopenharmony_cistatic struct zswap_entry *zswap_entry_find_get(struct rb_root *root, 43062306a36Sopenharmony_ci pgoff_t offset) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci struct zswap_entry *entry; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci entry = zswap_rb_search(root, offset); 43562306a36Sopenharmony_ci if (entry) 43662306a36Sopenharmony_ci zswap_entry_get(entry); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci return entry; 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/********************************* 44262306a36Sopenharmony_ci* per-cpu code 44362306a36Sopenharmony_ci**********************************/ 44462306a36Sopenharmony_cistatic DEFINE_PER_CPU(u8 *, zswap_dstmem); 44562306a36Sopenharmony_ci/* 44662306a36Sopenharmony_ci * If users dynamically change the zpool type and compressor at runtime, i.e. 44762306a36Sopenharmony_ci * zswap is running, zswap can have more than one zpool on one cpu, but they 44862306a36Sopenharmony_ci * are sharing dtsmem. So we need this mutex to be per-cpu. 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct mutex *, zswap_mutex); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic int zswap_dstmem_prepare(unsigned int cpu) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct mutex *mutex; 45562306a36Sopenharmony_ci u8 *dst; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci dst = kmalloc_node(PAGE_SIZE * 2, GFP_KERNEL, cpu_to_node(cpu)); 45862306a36Sopenharmony_ci if (!dst) 45962306a36Sopenharmony_ci return -ENOMEM; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci mutex = kmalloc_node(sizeof(*mutex), GFP_KERNEL, cpu_to_node(cpu)); 46262306a36Sopenharmony_ci if (!mutex) { 46362306a36Sopenharmony_ci kfree(dst); 46462306a36Sopenharmony_ci return -ENOMEM; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci mutex_init(mutex); 46862306a36Sopenharmony_ci per_cpu(zswap_dstmem, cpu) = dst; 46962306a36Sopenharmony_ci per_cpu(zswap_mutex, cpu) = mutex; 47062306a36Sopenharmony_ci return 0; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic int zswap_dstmem_dead(unsigned int cpu) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct mutex *mutex; 47662306a36Sopenharmony_ci u8 *dst; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci mutex = per_cpu(zswap_mutex, cpu); 47962306a36Sopenharmony_ci kfree(mutex); 48062306a36Sopenharmony_ci per_cpu(zswap_mutex, cpu) = NULL; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci dst = per_cpu(zswap_dstmem, cpu); 48362306a36Sopenharmony_ci kfree(dst); 48462306a36Sopenharmony_ci per_cpu(zswap_dstmem, cpu) = NULL; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return 0; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic int zswap_cpu_comp_prepare(unsigned int cpu, struct hlist_node *node) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci struct zswap_pool *pool = hlist_entry(node, struct zswap_pool, node); 49262306a36Sopenharmony_ci struct crypto_acomp_ctx *acomp_ctx = per_cpu_ptr(pool->acomp_ctx, cpu); 49362306a36Sopenharmony_ci struct crypto_acomp *acomp; 49462306a36Sopenharmony_ci struct acomp_req *req; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci acomp = crypto_alloc_acomp_node(pool->tfm_name, 0, 0, cpu_to_node(cpu)); 49762306a36Sopenharmony_ci if (IS_ERR(acomp)) { 49862306a36Sopenharmony_ci pr_err("could not alloc crypto acomp %s : %ld\n", 49962306a36Sopenharmony_ci pool->tfm_name, PTR_ERR(acomp)); 50062306a36Sopenharmony_ci return PTR_ERR(acomp); 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci acomp_ctx->acomp = acomp; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci req = acomp_request_alloc(acomp_ctx->acomp); 50562306a36Sopenharmony_ci if (!req) { 50662306a36Sopenharmony_ci pr_err("could not alloc crypto acomp_request %s\n", 50762306a36Sopenharmony_ci pool->tfm_name); 50862306a36Sopenharmony_ci crypto_free_acomp(acomp_ctx->acomp); 50962306a36Sopenharmony_ci return -ENOMEM; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci acomp_ctx->req = req; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci crypto_init_wait(&acomp_ctx->wait); 51462306a36Sopenharmony_ci /* 51562306a36Sopenharmony_ci * if the backend of acomp is async zip, crypto_req_done() will wakeup 51662306a36Sopenharmony_ci * crypto_wait_req(); if the backend of acomp is scomp, the callback 51762306a36Sopenharmony_ci * won't be called, crypto_wait_req() will return without blocking. 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_ci acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 52062306a36Sopenharmony_ci crypto_req_done, &acomp_ctx->wait); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci acomp_ctx->mutex = per_cpu(zswap_mutex, cpu); 52362306a36Sopenharmony_ci acomp_ctx->dstmem = per_cpu(zswap_dstmem, cpu); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci return 0; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic int zswap_cpu_comp_dead(unsigned int cpu, struct hlist_node *node) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct zswap_pool *pool = hlist_entry(node, struct zswap_pool, node); 53162306a36Sopenharmony_ci struct crypto_acomp_ctx *acomp_ctx = per_cpu_ptr(pool->acomp_ctx, cpu); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(acomp_ctx)) { 53462306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(acomp_ctx->req)) 53562306a36Sopenharmony_ci acomp_request_free(acomp_ctx->req); 53662306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(acomp_ctx->acomp)) 53762306a36Sopenharmony_ci crypto_free_acomp(acomp_ctx->acomp); 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci return 0; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci/********************************* 54462306a36Sopenharmony_ci* pool functions 54562306a36Sopenharmony_ci**********************************/ 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic struct zswap_pool *__zswap_pool_current(void) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct zswap_pool *pool; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci pool = list_first_or_null_rcu(&zswap_pools, typeof(*pool), list); 55262306a36Sopenharmony_ci WARN_ONCE(!pool && zswap_has_pool, 55362306a36Sopenharmony_ci "%s: no page storage pool!\n", __func__); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci return pool; 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic struct zswap_pool *zswap_pool_current(void) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci assert_spin_locked(&zswap_pools_lock); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return __zswap_pool_current(); 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic struct zswap_pool *zswap_pool_current_get(void) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci struct zswap_pool *pool; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci rcu_read_lock(); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci pool = __zswap_pool_current(); 57262306a36Sopenharmony_ci if (!zswap_pool_get(pool)) 57362306a36Sopenharmony_ci pool = NULL; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci rcu_read_unlock(); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return pool; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic struct zswap_pool *zswap_pool_last_get(void) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci struct zswap_pool *pool, *last = NULL; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci rcu_read_lock(); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci list_for_each_entry_rcu(pool, &zswap_pools, list) 58762306a36Sopenharmony_ci last = pool; 58862306a36Sopenharmony_ci WARN_ONCE(!last && zswap_has_pool, 58962306a36Sopenharmony_ci "%s: no page storage pool!\n", __func__); 59062306a36Sopenharmony_ci if (!zswap_pool_get(last)) 59162306a36Sopenharmony_ci last = NULL; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci rcu_read_unlock(); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci return last; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci/* type and compressor must be null-terminated */ 59962306a36Sopenharmony_cistatic struct zswap_pool *zswap_pool_find_get(char *type, char *compressor) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct zswap_pool *pool; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci assert_spin_locked(&zswap_pools_lock); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci list_for_each_entry_rcu(pool, &zswap_pools, list) { 60662306a36Sopenharmony_ci if (strcmp(pool->tfm_name, compressor)) 60762306a36Sopenharmony_ci continue; 60862306a36Sopenharmony_ci /* all zpools share the same type */ 60962306a36Sopenharmony_ci if (strcmp(zpool_get_type(pool->zpools[0]), type)) 61062306a36Sopenharmony_ci continue; 61162306a36Sopenharmony_ci /* if we can't get it, it's about to be destroyed */ 61262306a36Sopenharmony_ci if (!zswap_pool_get(pool)) 61362306a36Sopenharmony_ci continue; 61462306a36Sopenharmony_ci return pool; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci return NULL; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci/* 62162306a36Sopenharmony_ci * If the entry is still valid in the tree, drop the initial ref and remove it 62262306a36Sopenharmony_ci * from the tree. This function must be called with an additional ref held, 62362306a36Sopenharmony_ci * otherwise it may race with another invalidation freeing the entry. 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_cistatic void zswap_invalidate_entry(struct zswap_tree *tree, 62662306a36Sopenharmony_ci struct zswap_entry *entry) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci if (zswap_rb_erase(&tree->rbroot, entry)) 62962306a36Sopenharmony_ci zswap_entry_put(tree, entry); 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic int zswap_reclaim_entry(struct zswap_pool *pool) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci struct zswap_entry *entry; 63562306a36Sopenharmony_ci struct zswap_tree *tree; 63662306a36Sopenharmony_ci pgoff_t swpoffset; 63762306a36Sopenharmony_ci int ret; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci /* Get an entry off the LRU */ 64062306a36Sopenharmony_ci spin_lock(&pool->lru_lock); 64162306a36Sopenharmony_ci if (list_empty(&pool->lru)) { 64262306a36Sopenharmony_ci spin_unlock(&pool->lru_lock); 64362306a36Sopenharmony_ci return -EINVAL; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci entry = list_last_entry(&pool->lru, struct zswap_entry, lru); 64662306a36Sopenharmony_ci list_del_init(&entry->lru); 64762306a36Sopenharmony_ci /* 64862306a36Sopenharmony_ci * Once the lru lock is dropped, the entry might get freed. The 64962306a36Sopenharmony_ci * swpoffset is copied to the stack, and entry isn't deref'd again 65062306a36Sopenharmony_ci * until the entry is verified to still be alive in the tree. 65162306a36Sopenharmony_ci */ 65262306a36Sopenharmony_ci swpoffset = swp_offset(entry->swpentry); 65362306a36Sopenharmony_ci tree = zswap_trees[swp_type(entry->swpentry)]; 65462306a36Sopenharmony_ci spin_unlock(&pool->lru_lock); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* Check for invalidate() race */ 65762306a36Sopenharmony_ci spin_lock(&tree->lock); 65862306a36Sopenharmony_ci if (entry != zswap_rb_search(&tree->rbroot, swpoffset)) { 65962306a36Sopenharmony_ci ret = -EAGAIN; 66062306a36Sopenharmony_ci goto unlock; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci /* Hold a reference to prevent a free during writeback */ 66362306a36Sopenharmony_ci zswap_entry_get(entry); 66462306a36Sopenharmony_ci spin_unlock(&tree->lock); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci ret = zswap_writeback_entry(entry, tree); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci spin_lock(&tree->lock); 66962306a36Sopenharmony_ci if (ret) { 67062306a36Sopenharmony_ci /* Writeback failed, put entry back on LRU */ 67162306a36Sopenharmony_ci spin_lock(&pool->lru_lock); 67262306a36Sopenharmony_ci list_move(&entry->lru, &pool->lru); 67362306a36Sopenharmony_ci spin_unlock(&pool->lru_lock); 67462306a36Sopenharmony_ci goto put_unlock; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* 67862306a36Sopenharmony_ci * Writeback started successfully, the page now belongs to the 67962306a36Sopenharmony_ci * swapcache. Drop the entry from zswap - unless invalidate already 68062306a36Sopenharmony_ci * took it out while we had the tree->lock released for IO. 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_ci zswap_invalidate_entry(tree, entry); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ciput_unlock: 68562306a36Sopenharmony_ci /* Drop local reference */ 68662306a36Sopenharmony_ci zswap_entry_put(tree, entry); 68762306a36Sopenharmony_ciunlock: 68862306a36Sopenharmony_ci spin_unlock(&tree->lock); 68962306a36Sopenharmony_ci return ret ? -EAGAIN : 0; 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic void shrink_worker(struct work_struct *w) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci struct zswap_pool *pool = container_of(w, typeof(*pool), 69562306a36Sopenharmony_ci shrink_work); 69662306a36Sopenharmony_ci int ret, failures = 0; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci do { 69962306a36Sopenharmony_ci ret = zswap_reclaim_entry(pool); 70062306a36Sopenharmony_ci if (ret) { 70162306a36Sopenharmony_ci zswap_reject_reclaim_fail++; 70262306a36Sopenharmony_ci if (ret != -EAGAIN) 70362306a36Sopenharmony_ci break; 70462306a36Sopenharmony_ci if (++failures == MAX_RECLAIM_RETRIES) 70562306a36Sopenharmony_ci break; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci cond_resched(); 70862306a36Sopenharmony_ci } while (!zswap_can_accept()); 70962306a36Sopenharmony_ci zswap_pool_put(pool); 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic struct zswap_pool *zswap_pool_create(char *type, char *compressor) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci int i; 71562306a36Sopenharmony_ci struct zswap_pool *pool; 71662306a36Sopenharmony_ci char name[38]; /* 'zswap' + 32 char (max) num + \0 */ 71762306a36Sopenharmony_ci gfp_t gfp = __GFP_NORETRY | __GFP_NOWARN | __GFP_KSWAPD_RECLAIM; 71862306a36Sopenharmony_ci int ret; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci if (!zswap_has_pool) { 72162306a36Sopenharmony_ci /* if either are unset, pool initialization failed, and we 72262306a36Sopenharmony_ci * need both params to be set correctly before trying to 72362306a36Sopenharmony_ci * create a pool. 72462306a36Sopenharmony_ci */ 72562306a36Sopenharmony_ci if (!strcmp(type, ZSWAP_PARAM_UNSET)) 72662306a36Sopenharmony_ci return NULL; 72762306a36Sopenharmony_ci if (!strcmp(compressor, ZSWAP_PARAM_UNSET)) 72862306a36Sopenharmony_ci return NULL; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci pool = kzalloc(sizeof(*pool), GFP_KERNEL); 73262306a36Sopenharmony_ci if (!pool) 73362306a36Sopenharmony_ci return NULL; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci for (i = 0; i < ZSWAP_NR_ZPOOLS; i++) { 73662306a36Sopenharmony_ci /* unique name for each pool specifically required by zsmalloc */ 73762306a36Sopenharmony_ci snprintf(name, 38, "zswap%x", 73862306a36Sopenharmony_ci atomic_inc_return(&zswap_pools_count)); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci pool->zpools[i] = zpool_create_pool(type, name, gfp); 74162306a36Sopenharmony_ci if (!pool->zpools[i]) { 74262306a36Sopenharmony_ci pr_err("%s zpool not available\n", type); 74362306a36Sopenharmony_ci goto error; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci pr_debug("using %s zpool\n", zpool_get_type(pool->zpools[0])); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci strscpy(pool->tfm_name, compressor, sizeof(pool->tfm_name)); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci pool->acomp_ctx = alloc_percpu(*pool->acomp_ctx); 75162306a36Sopenharmony_ci if (!pool->acomp_ctx) { 75262306a36Sopenharmony_ci pr_err("percpu alloc failed\n"); 75362306a36Sopenharmony_ci goto error; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci ret = cpuhp_state_add_instance(CPUHP_MM_ZSWP_POOL_PREPARE, 75762306a36Sopenharmony_ci &pool->node); 75862306a36Sopenharmony_ci if (ret) 75962306a36Sopenharmony_ci goto error; 76062306a36Sopenharmony_ci pr_debug("using %s compressor\n", pool->tfm_name); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci /* being the current pool takes 1 ref; this func expects the 76362306a36Sopenharmony_ci * caller to always add the new pool as the current pool 76462306a36Sopenharmony_ci */ 76562306a36Sopenharmony_ci kref_init(&pool->kref); 76662306a36Sopenharmony_ci INIT_LIST_HEAD(&pool->list); 76762306a36Sopenharmony_ci INIT_LIST_HEAD(&pool->lru); 76862306a36Sopenharmony_ci spin_lock_init(&pool->lru_lock); 76962306a36Sopenharmony_ci INIT_WORK(&pool->shrink_work, shrink_worker); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci zswap_pool_debug("created", pool); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci return pool; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_cierror: 77662306a36Sopenharmony_ci if (pool->acomp_ctx) 77762306a36Sopenharmony_ci free_percpu(pool->acomp_ctx); 77862306a36Sopenharmony_ci while (i--) 77962306a36Sopenharmony_ci zpool_destroy_pool(pool->zpools[i]); 78062306a36Sopenharmony_ci kfree(pool); 78162306a36Sopenharmony_ci return NULL; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic struct zswap_pool *__zswap_pool_create_fallback(void) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci bool has_comp, has_zpool; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci has_comp = crypto_has_acomp(zswap_compressor, 0, 0); 78962306a36Sopenharmony_ci if (!has_comp && strcmp(zswap_compressor, 79062306a36Sopenharmony_ci CONFIG_ZSWAP_COMPRESSOR_DEFAULT)) { 79162306a36Sopenharmony_ci pr_err("compressor %s not available, using default %s\n", 79262306a36Sopenharmony_ci zswap_compressor, CONFIG_ZSWAP_COMPRESSOR_DEFAULT); 79362306a36Sopenharmony_ci param_free_charp(&zswap_compressor); 79462306a36Sopenharmony_ci zswap_compressor = CONFIG_ZSWAP_COMPRESSOR_DEFAULT; 79562306a36Sopenharmony_ci has_comp = crypto_has_acomp(zswap_compressor, 0, 0); 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci if (!has_comp) { 79862306a36Sopenharmony_ci pr_err("default compressor %s not available\n", 79962306a36Sopenharmony_ci zswap_compressor); 80062306a36Sopenharmony_ci param_free_charp(&zswap_compressor); 80162306a36Sopenharmony_ci zswap_compressor = ZSWAP_PARAM_UNSET; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci has_zpool = zpool_has_pool(zswap_zpool_type); 80562306a36Sopenharmony_ci if (!has_zpool && strcmp(zswap_zpool_type, 80662306a36Sopenharmony_ci CONFIG_ZSWAP_ZPOOL_DEFAULT)) { 80762306a36Sopenharmony_ci pr_err("zpool %s not available, using default %s\n", 80862306a36Sopenharmony_ci zswap_zpool_type, CONFIG_ZSWAP_ZPOOL_DEFAULT); 80962306a36Sopenharmony_ci param_free_charp(&zswap_zpool_type); 81062306a36Sopenharmony_ci zswap_zpool_type = CONFIG_ZSWAP_ZPOOL_DEFAULT; 81162306a36Sopenharmony_ci has_zpool = zpool_has_pool(zswap_zpool_type); 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci if (!has_zpool) { 81462306a36Sopenharmony_ci pr_err("default zpool %s not available\n", 81562306a36Sopenharmony_ci zswap_zpool_type); 81662306a36Sopenharmony_ci param_free_charp(&zswap_zpool_type); 81762306a36Sopenharmony_ci zswap_zpool_type = ZSWAP_PARAM_UNSET; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (!has_comp || !has_zpool) 82162306a36Sopenharmony_ci return NULL; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci return zswap_pool_create(zswap_zpool_type, zswap_compressor); 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cistatic void zswap_pool_destroy(struct zswap_pool *pool) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci int i; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci zswap_pool_debug("destroying", pool); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci cpuhp_state_remove_instance(CPUHP_MM_ZSWP_POOL_PREPARE, &pool->node); 83362306a36Sopenharmony_ci free_percpu(pool->acomp_ctx); 83462306a36Sopenharmony_ci for (i = 0; i < ZSWAP_NR_ZPOOLS; i++) 83562306a36Sopenharmony_ci zpool_destroy_pool(pool->zpools[i]); 83662306a36Sopenharmony_ci kfree(pool); 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_cistatic int __must_check zswap_pool_get(struct zswap_pool *pool) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci if (!pool) 84262306a36Sopenharmony_ci return 0; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci return kref_get_unless_zero(&pool->kref); 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic void __zswap_pool_release(struct work_struct *work) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci struct zswap_pool *pool = container_of(work, typeof(*pool), 85062306a36Sopenharmony_ci release_work); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci synchronize_rcu(); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* nobody should have been able to get a kref... */ 85562306a36Sopenharmony_ci WARN_ON(kref_get_unless_zero(&pool->kref)); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci /* pool is now off zswap_pools list and has no references. */ 85862306a36Sopenharmony_ci zswap_pool_destroy(pool); 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic void __zswap_pool_empty(struct kref *kref) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci struct zswap_pool *pool; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci pool = container_of(kref, typeof(*pool), kref); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci spin_lock(&zswap_pools_lock); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci WARN_ON(pool == zswap_pool_current()); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci list_del_rcu(&pool->list); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci INIT_WORK(&pool->release_work, __zswap_pool_release); 87462306a36Sopenharmony_ci schedule_work(&pool->release_work); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci spin_unlock(&zswap_pools_lock); 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic void zswap_pool_put(struct zswap_pool *pool) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci kref_put(&pool->kref, __zswap_pool_empty); 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci/********************************* 88562306a36Sopenharmony_ci* param callbacks 88662306a36Sopenharmony_ci**********************************/ 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic bool zswap_pool_changed(const char *s, const struct kernel_param *kp) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci /* no change required */ 89162306a36Sopenharmony_ci if (!strcmp(s, *(char **)kp->arg) && zswap_has_pool) 89262306a36Sopenharmony_ci return false; 89362306a36Sopenharmony_ci return true; 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci/* val must be a null-terminated string */ 89762306a36Sopenharmony_cistatic int __zswap_param_set(const char *val, const struct kernel_param *kp, 89862306a36Sopenharmony_ci char *type, char *compressor) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci struct zswap_pool *pool, *put_pool = NULL; 90162306a36Sopenharmony_ci char *s = strstrip((char *)val); 90262306a36Sopenharmony_ci int ret = 0; 90362306a36Sopenharmony_ci bool new_pool = false; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci mutex_lock(&zswap_init_lock); 90662306a36Sopenharmony_ci switch (zswap_init_state) { 90762306a36Sopenharmony_ci case ZSWAP_UNINIT: 90862306a36Sopenharmony_ci /* if this is load-time (pre-init) param setting, 90962306a36Sopenharmony_ci * don't create a pool; that's done during init. 91062306a36Sopenharmony_ci */ 91162306a36Sopenharmony_ci ret = param_set_charp(s, kp); 91262306a36Sopenharmony_ci break; 91362306a36Sopenharmony_ci case ZSWAP_INIT_SUCCEED: 91462306a36Sopenharmony_ci new_pool = zswap_pool_changed(s, kp); 91562306a36Sopenharmony_ci break; 91662306a36Sopenharmony_ci case ZSWAP_INIT_FAILED: 91762306a36Sopenharmony_ci pr_err("can't set param, initialization failed\n"); 91862306a36Sopenharmony_ci ret = -ENODEV; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci mutex_unlock(&zswap_init_lock); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci /* no need to create a new pool, return directly */ 92362306a36Sopenharmony_ci if (!new_pool) 92462306a36Sopenharmony_ci return ret; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (!type) { 92762306a36Sopenharmony_ci if (!zpool_has_pool(s)) { 92862306a36Sopenharmony_ci pr_err("zpool %s not available\n", s); 92962306a36Sopenharmony_ci return -ENOENT; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci type = s; 93262306a36Sopenharmony_ci } else if (!compressor) { 93362306a36Sopenharmony_ci if (!crypto_has_acomp(s, 0, 0)) { 93462306a36Sopenharmony_ci pr_err("compressor %s not available\n", s); 93562306a36Sopenharmony_ci return -ENOENT; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci compressor = s; 93862306a36Sopenharmony_ci } else { 93962306a36Sopenharmony_ci WARN_ON(1); 94062306a36Sopenharmony_ci return -EINVAL; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci spin_lock(&zswap_pools_lock); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci pool = zswap_pool_find_get(type, compressor); 94662306a36Sopenharmony_ci if (pool) { 94762306a36Sopenharmony_ci zswap_pool_debug("using existing", pool); 94862306a36Sopenharmony_ci WARN_ON(pool == zswap_pool_current()); 94962306a36Sopenharmony_ci list_del_rcu(&pool->list); 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci spin_unlock(&zswap_pools_lock); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci if (!pool) 95562306a36Sopenharmony_ci pool = zswap_pool_create(type, compressor); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (pool) 95862306a36Sopenharmony_ci ret = param_set_charp(s, kp); 95962306a36Sopenharmony_ci else 96062306a36Sopenharmony_ci ret = -EINVAL; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci spin_lock(&zswap_pools_lock); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if (!ret) { 96562306a36Sopenharmony_ci put_pool = zswap_pool_current(); 96662306a36Sopenharmony_ci list_add_rcu(&pool->list, &zswap_pools); 96762306a36Sopenharmony_ci zswap_has_pool = true; 96862306a36Sopenharmony_ci } else if (pool) { 96962306a36Sopenharmony_ci /* add the possibly pre-existing pool to the end of the pools 97062306a36Sopenharmony_ci * list; if it's new (and empty) then it'll be removed and 97162306a36Sopenharmony_ci * destroyed by the put after we drop the lock 97262306a36Sopenharmony_ci */ 97362306a36Sopenharmony_ci list_add_tail_rcu(&pool->list, &zswap_pools); 97462306a36Sopenharmony_ci put_pool = pool; 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci spin_unlock(&zswap_pools_lock); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci if (!zswap_has_pool && !pool) { 98062306a36Sopenharmony_ci /* if initial pool creation failed, and this pool creation also 98162306a36Sopenharmony_ci * failed, maybe both compressor and zpool params were bad. 98262306a36Sopenharmony_ci * Allow changing this param, so pool creation will succeed 98362306a36Sopenharmony_ci * when the other param is changed. We already verified this 98462306a36Sopenharmony_ci * param is ok in the zpool_has_pool() or crypto_has_acomp() 98562306a36Sopenharmony_ci * checks above. 98662306a36Sopenharmony_ci */ 98762306a36Sopenharmony_ci ret = param_set_charp(s, kp); 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* drop the ref from either the old current pool, 99162306a36Sopenharmony_ci * or the new pool we failed to add 99262306a36Sopenharmony_ci */ 99362306a36Sopenharmony_ci if (put_pool) 99462306a36Sopenharmony_ci zswap_pool_put(put_pool); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci return ret; 99762306a36Sopenharmony_ci} 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_cistatic int zswap_compressor_param_set(const char *val, 100062306a36Sopenharmony_ci const struct kernel_param *kp) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci return __zswap_param_set(val, kp, zswap_zpool_type, NULL); 100362306a36Sopenharmony_ci} 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_cistatic int zswap_zpool_param_set(const char *val, 100662306a36Sopenharmony_ci const struct kernel_param *kp) 100762306a36Sopenharmony_ci{ 100862306a36Sopenharmony_ci return __zswap_param_set(val, kp, NULL, zswap_compressor); 100962306a36Sopenharmony_ci} 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_cistatic int zswap_enabled_param_set(const char *val, 101262306a36Sopenharmony_ci const struct kernel_param *kp) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci int ret = -ENODEV; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* if this is load-time (pre-init) param setting, only set param. */ 101762306a36Sopenharmony_ci if (system_state != SYSTEM_RUNNING) 101862306a36Sopenharmony_ci return param_set_bool(val, kp); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci mutex_lock(&zswap_init_lock); 102162306a36Sopenharmony_ci switch (zswap_init_state) { 102262306a36Sopenharmony_ci case ZSWAP_UNINIT: 102362306a36Sopenharmony_ci if (zswap_setup()) 102462306a36Sopenharmony_ci break; 102562306a36Sopenharmony_ci fallthrough; 102662306a36Sopenharmony_ci case ZSWAP_INIT_SUCCEED: 102762306a36Sopenharmony_ci if (!zswap_has_pool) 102862306a36Sopenharmony_ci pr_err("can't enable, no pool configured\n"); 102962306a36Sopenharmony_ci else 103062306a36Sopenharmony_ci ret = param_set_bool(val, kp); 103162306a36Sopenharmony_ci break; 103262306a36Sopenharmony_ci case ZSWAP_INIT_FAILED: 103362306a36Sopenharmony_ci pr_err("can't enable, initialization failed\n"); 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci mutex_unlock(&zswap_init_lock); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci return ret; 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci/********************************* 104162306a36Sopenharmony_ci* writeback code 104262306a36Sopenharmony_ci**********************************/ 104362306a36Sopenharmony_ci/* 104462306a36Sopenharmony_ci * Attempts to free an entry by adding a page to the swap cache, 104562306a36Sopenharmony_ci * decompressing the entry data into the page, and issuing a 104662306a36Sopenharmony_ci * bio write to write the page back to the swap device. 104762306a36Sopenharmony_ci * 104862306a36Sopenharmony_ci * This can be thought of as a "resumed writeback" of the page 104962306a36Sopenharmony_ci * to the swap device. We are basically resuming the same swap 105062306a36Sopenharmony_ci * writeback path that was intercepted with the zswap_store() 105162306a36Sopenharmony_ci * in the first place. After the page has been decompressed into 105262306a36Sopenharmony_ci * the swap cache, the compressed version stored by zswap can be 105362306a36Sopenharmony_ci * freed. 105462306a36Sopenharmony_ci */ 105562306a36Sopenharmony_cistatic int zswap_writeback_entry(struct zswap_entry *entry, 105662306a36Sopenharmony_ci struct zswap_tree *tree) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci swp_entry_t swpentry = entry->swpentry; 105962306a36Sopenharmony_ci struct page *page; 106062306a36Sopenharmony_ci struct scatterlist input, output; 106162306a36Sopenharmony_ci struct crypto_acomp_ctx *acomp_ctx; 106262306a36Sopenharmony_ci struct zpool *pool = zswap_find_zpool(entry); 106362306a36Sopenharmony_ci bool page_was_allocated; 106462306a36Sopenharmony_ci u8 *src, *tmp = NULL; 106562306a36Sopenharmony_ci unsigned int dlen; 106662306a36Sopenharmony_ci int ret; 106762306a36Sopenharmony_ci struct writeback_control wbc = { 106862306a36Sopenharmony_ci .sync_mode = WB_SYNC_NONE, 106962306a36Sopenharmony_ci }; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci if (!zpool_can_sleep_mapped(pool)) { 107262306a36Sopenharmony_ci tmp = kmalloc(PAGE_SIZE, GFP_KERNEL); 107362306a36Sopenharmony_ci if (!tmp) 107462306a36Sopenharmony_ci return -ENOMEM; 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci /* try to allocate swap cache page */ 107862306a36Sopenharmony_ci page = __read_swap_cache_async(swpentry, GFP_KERNEL, NULL, 0, 107962306a36Sopenharmony_ci &page_was_allocated); 108062306a36Sopenharmony_ci if (!page) { 108162306a36Sopenharmony_ci ret = -ENOMEM; 108262306a36Sopenharmony_ci goto fail; 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci /* Found an existing page, we raced with load/swapin */ 108662306a36Sopenharmony_ci if (!page_was_allocated) { 108762306a36Sopenharmony_ci put_page(page); 108862306a36Sopenharmony_ci ret = -EEXIST; 108962306a36Sopenharmony_ci goto fail; 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci /* 109362306a36Sopenharmony_ci * Page is locked, and the swapcache is now secured against 109462306a36Sopenharmony_ci * concurrent swapping to and from the slot. Verify that the 109562306a36Sopenharmony_ci * swap entry hasn't been invalidated and recycled behind our 109662306a36Sopenharmony_ci * backs (our zswap_entry reference doesn't prevent that), to 109762306a36Sopenharmony_ci * avoid overwriting a new swap page with old compressed data. 109862306a36Sopenharmony_ci */ 109962306a36Sopenharmony_ci spin_lock(&tree->lock); 110062306a36Sopenharmony_ci if (zswap_rb_search(&tree->rbroot, swp_offset(entry->swpentry)) != entry) { 110162306a36Sopenharmony_ci spin_unlock(&tree->lock); 110262306a36Sopenharmony_ci delete_from_swap_cache(page_folio(page)); 110362306a36Sopenharmony_ci unlock_page(page); 110462306a36Sopenharmony_ci put_page(page); 110562306a36Sopenharmony_ci ret = -ENOMEM; 110662306a36Sopenharmony_ci goto fail; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci spin_unlock(&tree->lock); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci /* decompress */ 111162306a36Sopenharmony_ci acomp_ctx = raw_cpu_ptr(entry->pool->acomp_ctx); 111262306a36Sopenharmony_ci dlen = PAGE_SIZE; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci src = zpool_map_handle(pool, entry->handle, ZPOOL_MM_RO); 111562306a36Sopenharmony_ci if (!zpool_can_sleep_mapped(pool)) { 111662306a36Sopenharmony_ci memcpy(tmp, src, entry->length); 111762306a36Sopenharmony_ci src = tmp; 111862306a36Sopenharmony_ci zpool_unmap_handle(pool, entry->handle); 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci mutex_lock(acomp_ctx->mutex); 112262306a36Sopenharmony_ci sg_init_one(&input, src, entry->length); 112362306a36Sopenharmony_ci sg_init_table(&output, 1); 112462306a36Sopenharmony_ci sg_set_page(&output, page, PAGE_SIZE, 0); 112562306a36Sopenharmony_ci acomp_request_set_params(acomp_ctx->req, &input, &output, entry->length, dlen); 112662306a36Sopenharmony_ci ret = crypto_wait_req(crypto_acomp_decompress(acomp_ctx->req), &acomp_ctx->wait); 112762306a36Sopenharmony_ci dlen = acomp_ctx->req->dlen; 112862306a36Sopenharmony_ci mutex_unlock(acomp_ctx->mutex); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci if (!zpool_can_sleep_mapped(pool)) 113162306a36Sopenharmony_ci kfree(tmp); 113262306a36Sopenharmony_ci else 113362306a36Sopenharmony_ci zpool_unmap_handle(pool, entry->handle); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci BUG_ON(ret); 113662306a36Sopenharmony_ci BUG_ON(dlen != PAGE_SIZE); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci /* page is up to date */ 113962306a36Sopenharmony_ci SetPageUptodate(page); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci /* move it to the tail of the inactive list after end_writeback */ 114262306a36Sopenharmony_ci SetPageReclaim(page); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci /* start writeback */ 114562306a36Sopenharmony_ci __swap_writepage(page, &wbc); 114662306a36Sopenharmony_ci put_page(page); 114762306a36Sopenharmony_ci zswap_written_back_pages++; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci return ret; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_cifail: 115262306a36Sopenharmony_ci if (!zpool_can_sleep_mapped(pool)) 115362306a36Sopenharmony_ci kfree(tmp); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci /* 115662306a36Sopenharmony_ci * If we get here because the page is already in swapcache, a 115762306a36Sopenharmony_ci * load may be happening concurrently. It is safe and okay to 115862306a36Sopenharmony_ci * not free the entry. It is also okay to return !0. 115962306a36Sopenharmony_ci */ 116062306a36Sopenharmony_ci return ret; 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_cistatic int zswap_is_page_same_filled(void *ptr, unsigned long *value) 116462306a36Sopenharmony_ci{ 116562306a36Sopenharmony_ci unsigned long *page; 116662306a36Sopenharmony_ci unsigned long val; 116762306a36Sopenharmony_ci unsigned int pos, last_pos = PAGE_SIZE / sizeof(*page) - 1; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci page = (unsigned long *)ptr; 117062306a36Sopenharmony_ci val = page[0]; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci if (val != page[last_pos]) 117362306a36Sopenharmony_ci return 0; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci for (pos = 1; pos < last_pos; pos++) { 117662306a36Sopenharmony_ci if (val != page[pos]) 117762306a36Sopenharmony_ci return 0; 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci *value = val; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci return 1; 118362306a36Sopenharmony_ci} 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_cistatic void zswap_fill_page(void *ptr, unsigned long value) 118662306a36Sopenharmony_ci{ 118762306a36Sopenharmony_ci unsigned long *page; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci page = (unsigned long *)ptr; 119062306a36Sopenharmony_ci memset_l(page, value, PAGE_SIZE / sizeof(unsigned long)); 119162306a36Sopenharmony_ci} 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_cibool zswap_store(struct folio *folio) 119462306a36Sopenharmony_ci{ 119562306a36Sopenharmony_ci swp_entry_t swp = folio->swap; 119662306a36Sopenharmony_ci int type = swp_type(swp); 119762306a36Sopenharmony_ci pgoff_t offset = swp_offset(swp); 119862306a36Sopenharmony_ci struct page *page = &folio->page; 119962306a36Sopenharmony_ci struct zswap_tree *tree = zswap_trees[type]; 120062306a36Sopenharmony_ci struct zswap_entry *entry, *dupentry; 120162306a36Sopenharmony_ci struct scatterlist input, output; 120262306a36Sopenharmony_ci struct crypto_acomp_ctx *acomp_ctx; 120362306a36Sopenharmony_ci struct obj_cgroup *objcg = NULL; 120462306a36Sopenharmony_ci struct zswap_pool *pool; 120562306a36Sopenharmony_ci struct zpool *zpool; 120662306a36Sopenharmony_ci unsigned int dlen = PAGE_SIZE; 120762306a36Sopenharmony_ci unsigned long handle, value; 120862306a36Sopenharmony_ci char *buf; 120962306a36Sopenharmony_ci u8 *src, *dst; 121062306a36Sopenharmony_ci gfp_t gfp; 121162306a36Sopenharmony_ci int ret; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci VM_WARN_ON_ONCE(!folio_test_locked(folio)); 121462306a36Sopenharmony_ci VM_WARN_ON_ONCE(!folio_test_swapcache(folio)); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci /* Large folios aren't supported */ 121762306a36Sopenharmony_ci if (folio_test_large(folio)) 121862306a36Sopenharmony_ci return false; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (!tree) 122162306a36Sopenharmony_ci return false; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci /* 122462306a36Sopenharmony_ci * If this is a duplicate, it must be removed before attempting to store 122562306a36Sopenharmony_ci * it, otherwise, if the store fails the old page won't be removed from 122662306a36Sopenharmony_ci * the tree, and it might be written back overriding the new data. 122762306a36Sopenharmony_ci */ 122862306a36Sopenharmony_ci spin_lock(&tree->lock); 122962306a36Sopenharmony_ci dupentry = zswap_rb_search(&tree->rbroot, offset); 123062306a36Sopenharmony_ci if (dupentry) { 123162306a36Sopenharmony_ci zswap_duplicate_entry++; 123262306a36Sopenharmony_ci zswap_invalidate_entry(tree, dupentry); 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci spin_unlock(&tree->lock); 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci if (!zswap_enabled) 123762306a36Sopenharmony_ci return false; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci /* 124062306a36Sopenharmony_ci * XXX: zswap reclaim does not work with cgroups yet. Without a 124162306a36Sopenharmony_ci * cgroup-aware entry LRU, we will push out entries system-wide based on 124262306a36Sopenharmony_ci * local cgroup limits. 124362306a36Sopenharmony_ci */ 124462306a36Sopenharmony_ci objcg = get_obj_cgroup_from_folio(folio); 124562306a36Sopenharmony_ci if (objcg && !obj_cgroup_may_zswap(objcg)) 124662306a36Sopenharmony_ci goto reject; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci /* reclaim space if needed */ 124962306a36Sopenharmony_ci if (zswap_is_full()) { 125062306a36Sopenharmony_ci zswap_pool_limit_hit++; 125162306a36Sopenharmony_ci zswap_pool_reached_full = true; 125262306a36Sopenharmony_ci goto shrink; 125362306a36Sopenharmony_ci } 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci if (zswap_pool_reached_full) { 125662306a36Sopenharmony_ci if (!zswap_can_accept()) 125762306a36Sopenharmony_ci goto shrink; 125862306a36Sopenharmony_ci else 125962306a36Sopenharmony_ci zswap_pool_reached_full = false; 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci /* allocate entry */ 126362306a36Sopenharmony_ci entry = zswap_entry_cache_alloc(GFP_KERNEL); 126462306a36Sopenharmony_ci if (!entry) { 126562306a36Sopenharmony_ci zswap_reject_kmemcache_fail++; 126662306a36Sopenharmony_ci goto reject; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (zswap_same_filled_pages_enabled) { 127062306a36Sopenharmony_ci src = kmap_atomic(page); 127162306a36Sopenharmony_ci if (zswap_is_page_same_filled(src, &value)) { 127262306a36Sopenharmony_ci kunmap_atomic(src); 127362306a36Sopenharmony_ci entry->swpentry = swp_entry(type, offset); 127462306a36Sopenharmony_ci entry->length = 0; 127562306a36Sopenharmony_ci entry->value = value; 127662306a36Sopenharmony_ci atomic_inc(&zswap_same_filled_pages); 127762306a36Sopenharmony_ci goto insert_entry; 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci kunmap_atomic(src); 128062306a36Sopenharmony_ci } 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci if (!zswap_non_same_filled_pages_enabled) 128362306a36Sopenharmony_ci goto freepage; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci /* if entry is successfully added, it keeps the reference */ 128662306a36Sopenharmony_ci entry->pool = zswap_pool_current_get(); 128762306a36Sopenharmony_ci if (!entry->pool) 128862306a36Sopenharmony_ci goto freepage; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci /* compress */ 129162306a36Sopenharmony_ci acomp_ctx = raw_cpu_ptr(entry->pool->acomp_ctx); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci mutex_lock(acomp_ctx->mutex); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci dst = acomp_ctx->dstmem; 129662306a36Sopenharmony_ci sg_init_table(&input, 1); 129762306a36Sopenharmony_ci sg_set_page(&input, page, PAGE_SIZE, 0); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci /* zswap_dstmem is of size (PAGE_SIZE * 2). Reflect same in sg_list */ 130062306a36Sopenharmony_ci sg_init_one(&output, dst, PAGE_SIZE * 2); 130162306a36Sopenharmony_ci acomp_request_set_params(acomp_ctx->req, &input, &output, PAGE_SIZE, dlen); 130262306a36Sopenharmony_ci /* 130362306a36Sopenharmony_ci * it maybe looks a little bit silly that we send an asynchronous request, 130462306a36Sopenharmony_ci * then wait for its completion synchronously. This makes the process look 130562306a36Sopenharmony_ci * synchronous in fact. 130662306a36Sopenharmony_ci * Theoretically, acomp supports users send multiple acomp requests in one 130762306a36Sopenharmony_ci * acomp instance, then get those requests done simultaneously. but in this 130862306a36Sopenharmony_ci * case, zswap actually does store and load page by page, there is no 130962306a36Sopenharmony_ci * existing method to send the second page before the first page is done 131062306a36Sopenharmony_ci * in one thread doing zwap. 131162306a36Sopenharmony_ci * but in different threads running on different cpu, we have different 131262306a36Sopenharmony_ci * acomp instance, so multiple threads can do (de)compression in parallel. 131362306a36Sopenharmony_ci */ 131462306a36Sopenharmony_ci ret = crypto_wait_req(crypto_acomp_compress(acomp_ctx->req), &acomp_ctx->wait); 131562306a36Sopenharmony_ci dlen = acomp_ctx->req->dlen; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci if (ret) 131862306a36Sopenharmony_ci goto put_dstmem; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci /* store */ 132162306a36Sopenharmony_ci zpool = zswap_find_zpool(entry); 132262306a36Sopenharmony_ci gfp = __GFP_NORETRY | __GFP_NOWARN | __GFP_KSWAPD_RECLAIM; 132362306a36Sopenharmony_ci if (zpool_malloc_support_movable(zpool)) 132462306a36Sopenharmony_ci gfp |= __GFP_HIGHMEM | __GFP_MOVABLE; 132562306a36Sopenharmony_ci ret = zpool_malloc(zpool, dlen, gfp, &handle); 132662306a36Sopenharmony_ci if (ret == -ENOSPC) { 132762306a36Sopenharmony_ci zswap_reject_compress_poor++; 132862306a36Sopenharmony_ci goto put_dstmem; 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci if (ret) { 133162306a36Sopenharmony_ci zswap_reject_alloc_fail++; 133262306a36Sopenharmony_ci goto put_dstmem; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci buf = zpool_map_handle(zpool, handle, ZPOOL_MM_WO); 133562306a36Sopenharmony_ci memcpy(buf, dst, dlen); 133662306a36Sopenharmony_ci zpool_unmap_handle(zpool, handle); 133762306a36Sopenharmony_ci mutex_unlock(acomp_ctx->mutex); 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci /* populate entry */ 134062306a36Sopenharmony_ci entry->swpentry = swp_entry(type, offset); 134162306a36Sopenharmony_ci entry->handle = handle; 134262306a36Sopenharmony_ci entry->length = dlen; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ciinsert_entry: 134562306a36Sopenharmony_ci entry->objcg = objcg; 134662306a36Sopenharmony_ci if (objcg) { 134762306a36Sopenharmony_ci obj_cgroup_charge_zswap(objcg, entry->length); 134862306a36Sopenharmony_ci /* Account before objcg ref is moved to tree */ 134962306a36Sopenharmony_ci count_objcg_event(objcg, ZSWPOUT); 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci /* map */ 135362306a36Sopenharmony_ci spin_lock(&tree->lock); 135462306a36Sopenharmony_ci /* 135562306a36Sopenharmony_ci * A duplicate entry should have been removed at the beginning of this 135662306a36Sopenharmony_ci * function. Since the swap entry should be pinned, if a duplicate is 135762306a36Sopenharmony_ci * found again here it means that something went wrong in the swap 135862306a36Sopenharmony_ci * cache. 135962306a36Sopenharmony_ci */ 136062306a36Sopenharmony_ci while (zswap_rb_insert(&tree->rbroot, entry, &dupentry) == -EEXIST) { 136162306a36Sopenharmony_ci WARN_ON(1); 136262306a36Sopenharmony_ci zswap_duplicate_entry++; 136362306a36Sopenharmony_ci zswap_invalidate_entry(tree, dupentry); 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci if (entry->length) { 136662306a36Sopenharmony_ci spin_lock(&entry->pool->lru_lock); 136762306a36Sopenharmony_ci list_add(&entry->lru, &entry->pool->lru); 136862306a36Sopenharmony_ci spin_unlock(&entry->pool->lru_lock); 136962306a36Sopenharmony_ci } 137062306a36Sopenharmony_ci spin_unlock(&tree->lock); 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci /* update stats */ 137362306a36Sopenharmony_ci atomic_inc(&zswap_stored_pages); 137462306a36Sopenharmony_ci zswap_update_total_size(); 137562306a36Sopenharmony_ci count_vm_event(ZSWPOUT); 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci return true; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ciput_dstmem: 138062306a36Sopenharmony_ci mutex_unlock(acomp_ctx->mutex); 138162306a36Sopenharmony_ci zswap_pool_put(entry->pool); 138262306a36Sopenharmony_cifreepage: 138362306a36Sopenharmony_ci zswap_entry_cache_free(entry); 138462306a36Sopenharmony_cireject: 138562306a36Sopenharmony_ci if (objcg) 138662306a36Sopenharmony_ci obj_cgroup_put(objcg); 138762306a36Sopenharmony_ci return false; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_cishrink: 139062306a36Sopenharmony_ci pool = zswap_pool_last_get(); 139162306a36Sopenharmony_ci if (pool && !queue_work(shrink_wq, &pool->shrink_work)) 139262306a36Sopenharmony_ci zswap_pool_put(pool); 139362306a36Sopenharmony_ci goto reject; 139462306a36Sopenharmony_ci} 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_cibool zswap_load(struct folio *folio) 139762306a36Sopenharmony_ci{ 139862306a36Sopenharmony_ci swp_entry_t swp = folio->swap; 139962306a36Sopenharmony_ci int type = swp_type(swp); 140062306a36Sopenharmony_ci pgoff_t offset = swp_offset(swp); 140162306a36Sopenharmony_ci struct page *page = &folio->page; 140262306a36Sopenharmony_ci struct zswap_tree *tree = zswap_trees[type]; 140362306a36Sopenharmony_ci struct zswap_entry *entry; 140462306a36Sopenharmony_ci struct scatterlist input, output; 140562306a36Sopenharmony_ci struct crypto_acomp_ctx *acomp_ctx; 140662306a36Sopenharmony_ci u8 *src, *dst, *tmp; 140762306a36Sopenharmony_ci struct zpool *zpool; 140862306a36Sopenharmony_ci unsigned int dlen; 140962306a36Sopenharmony_ci bool ret; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci VM_WARN_ON_ONCE(!folio_test_locked(folio)); 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci /* find */ 141462306a36Sopenharmony_ci spin_lock(&tree->lock); 141562306a36Sopenharmony_ci entry = zswap_entry_find_get(&tree->rbroot, offset); 141662306a36Sopenharmony_ci if (!entry) { 141762306a36Sopenharmony_ci spin_unlock(&tree->lock); 141862306a36Sopenharmony_ci return false; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci spin_unlock(&tree->lock); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci if (!entry->length) { 142362306a36Sopenharmony_ci dst = kmap_atomic(page); 142462306a36Sopenharmony_ci zswap_fill_page(dst, entry->value); 142562306a36Sopenharmony_ci kunmap_atomic(dst); 142662306a36Sopenharmony_ci ret = true; 142762306a36Sopenharmony_ci goto stats; 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci zpool = zswap_find_zpool(entry); 143162306a36Sopenharmony_ci if (!zpool_can_sleep_mapped(zpool)) { 143262306a36Sopenharmony_ci tmp = kmalloc(entry->length, GFP_KERNEL); 143362306a36Sopenharmony_ci if (!tmp) { 143462306a36Sopenharmony_ci ret = false; 143562306a36Sopenharmony_ci goto freeentry; 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci /* decompress */ 144062306a36Sopenharmony_ci dlen = PAGE_SIZE; 144162306a36Sopenharmony_ci src = zpool_map_handle(zpool, entry->handle, ZPOOL_MM_RO); 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci if (!zpool_can_sleep_mapped(zpool)) { 144462306a36Sopenharmony_ci memcpy(tmp, src, entry->length); 144562306a36Sopenharmony_ci src = tmp; 144662306a36Sopenharmony_ci zpool_unmap_handle(zpool, entry->handle); 144762306a36Sopenharmony_ci } 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci acomp_ctx = raw_cpu_ptr(entry->pool->acomp_ctx); 145062306a36Sopenharmony_ci mutex_lock(acomp_ctx->mutex); 145162306a36Sopenharmony_ci sg_init_one(&input, src, entry->length); 145262306a36Sopenharmony_ci sg_init_table(&output, 1); 145362306a36Sopenharmony_ci sg_set_page(&output, page, PAGE_SIZE, 0); 145462306a36Sopenharmony_ci acomp_request_set_params(acomp_ctx->req, &input, &output, entry->length, dlen); 145562306a36Sopenharmony_ci if (crypto_wait_req(crypto_acomp_decompress(acomp_ctx->req), &acomp_ctx->wait)) 145662306a36Sopenharmony_ci WARN_ON(1); 145762306a36Sopenharmony_ci mutex_unlock(acomp_ctx->mutex); 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci if (zpool_can_sleep_mapped(zpool)) 146062306a36Sopenharmony_ci zpool_unmap_handle(zpool, entry->handle); 146162306a36Sopenharmony_ci else 146262306a36Sopenharmony_ci kfree(tmp); 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci ret = true; 146562306a36Sopenharmony_cistats: 146662306a36Sopenharmony_ci count_vm_event(ZSWPIN); 146762306a36Sopenharmony_ci if (entry->objcg) 146862306a36Sopenharmony_ci count_objcg_event(entry->objcg, ZSWPIN); 146962306a36Sopenharmony_cifreeentry: 147062306a36Sopenharmony_ci spin_lock(&tree->lock); 147162306a36Sopenharmony_ci if (ret && zswap_exclusive_loads_enabled) { 147262306a36Sopenharmony_ci zswap_invalidate_entry(tree, entry); 147362306a36Sopenharmony_ci folio_mark_dirty(folio); 147462306a36Sopenharmony_ci } else if (entry->length) { 147562306a36Sopenharmony_ci spin_lock(&entry->pool->lru_lock); 147662306a36Sopenharmony_ci list_move(&entry->lru, &entry->pool->lru); 147762306a36Sopenharmony_ci spin_unlock(&entry->pool->lru_lock); 147862306a36Sopenharmony_ci } 147962306a36Sopenharmony_ci zswap_entry_put(tree, entry); 148062306a36Sopenharmony_ci spin_unlock(&tree->lock); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci return ret; 148362306a36Sopenharmony_ci} 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_civoid zswap_invalidate(int type, pgoff_t offset) 148662306a36Sopenharmony_ci{ 148762306a36Sopenharmony_ci struct zswap_tree *tree = zswap_trees[type]; 148862306a36Sopenharmony_ci struct zswap_entry *entry; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci /* find */ 149162306a36Sopenharmony_ci spin_lock(&tree->lock); 149262306a36Sopenharmony_ci entry = zswap_rb_search(&tree->rbroot, offset); 149362306a36Sopenharmony_ci if (!entry) { 149462306a36Sopenharmony_ci /* entry was written back */ 149562306a36Sopenharmony_ci spin_unlock(&tree->lock); 149662306a36Sopenharmony_ci return; 149762306a36Sopenharmony_ci } 149862306a36Sopenharmony_ci zswap_invalidate_entry(tree, entry); 149962306a36Sopenharmony_ci spin_unlock(&tree->lock); 150062306a36Sopenharmony_ci} 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_civoid zswap_swapon(int type) 150362306a36Sopenharmony_ci{ 150462306a36Sopenharmony_ci struct zswap_tree *tree; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci tree = kzalloc(sizeof(*tree), GFP_KERNEL); 150762306a36Sopenharmony_ci if (!tree) { 150862306a36Sopenharmony_ci pr_err("alloc failed, zswap disabled for swap type %d\n", type); 150962306a36Sopenharmony_ci return; 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci tree->rbroot = RB_ROOT; 151362306a36Sopenharmony_ci spin_lock_init(&tree->lock); 151462306a36Sopenharmony_ci zswap_trees[type] = tree; 151562306a36Sopenharmony_ci} 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_civoid zswap_swapoff(int type) 151862306a36Sopenharmony_ci{ 151962306a36Sopenharmony_ci struct zswap_tree *tree = zswap_trees[type]; 152062306a36Sopenharmony_ci struct zswap_entry *entry, *n; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci if (!tree) 152362306a36Sopenharmony_ci return; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci /* walk the tree and free everything */ 152662306a36Sopenharmony_ci spin_lock(&tree->lock); 152762306a36Sopenharmony_ci rbtree_postorder_for_each_entry_safe(entry, n, &tree->rbroot, rbnode) 152862306a36Sopenharmony_ci zswap_free_entry(entry); 152962306a36Sopenharmony_ci tree->rbroot = RB_ROOT; 153062306a36Sopenharmony_ci spin_unlock(&tree->lock); 153162306a36Sopenharmony_ci kfree(tree); 153262306a36Sopenharmony_ci zswap_trees[type] = NULL; 153362306a36Sopenharmony_ci} 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci/********************************* 153662306a36Sopenharmony_ci* debugfs functions 153762306a36Sopenharmony_ci**********************************/ 153862306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 153962306a36Sopenharmony_ci#include <linux/debugfs.h> 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_cistatic struct dentry *zswap_debugfs_root; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_cistatic int zswap_debugfs_init(void) 154462306a36Sopenharmony_ci{ 154562306a36Sopenharmony_ci if (!debugfs_initialized()) 154662306a36Sopenharmony_ci return -ENODEV; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci zswap_debugfs_root = debugfs_create_dir("zswap", NULL); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci debugfs_create_u64("pool_limit_hit", 0444, 155162306a36Sopenharmony_ci zswap_debugfs_root, &zswap_pool_limit_hit); 155262306a36Sopenharmony_ci debugfs_create_u64("reject_reclaim_fail", 0444, 155362306a36Sopenharmony_ci zswap_debugfs_root, &zswap_reject_reclaim_fail); 155462306a36Sopenharmony_ci debugfs_create_u64("reject_alloc_fail", 0444, 155562306a36Sopenharmony_ci zswap_debugfs_root, &zswap_reject_alloc_fail); 155662306a36Sopenharmony_ci debugfs_create_u64("reject_kmemcache_fail", 0444, 155762306a36Sopenharmony_ci zswap_debugfs_root, &zswap_reject_kmemcache_fail); 155862306a36Sopenharmony_ci debugfs_create_u64("reject_compress_poor", 0444, 155962306a36Sopenharmony_ci zswap_debugfs_root, &zswap_reject_compress_poor); 156062306a36Sopenharmony_ci debugfs_create_u64("written_back_pages", 0444, 156162306a36Sopenharmony_ci zswap_debugfs_root, &zswap_written_back_pages); 156262306a36Sopenharmony_ci debugfs_create_u64("duplicate_entry", 0444, 156362306a36Sopenharmony_ci zswap_debugfs_root, &zswap_duplicate_entry); 156462306a36Sopenharmony_ci debugfs_create_u64("pool_total_size", 0444, 156562306a36Sopenharmony_ci zswap_debugfs_root, &zswap_pool_total_size); 156662306a36Sopenharmony_ci debugfs_create_atomic_t("stored_pages", 0444, 156762306a36Sopenharmony_ci zswap_debugfs_root, &zswap_stored_pages); 156862306a36Sopenharmony_ci debugfs_create_atomic_t("same_filled_pages", 0444, 156962306a36Sopenharmony_ci zswap_debugfs_root, &zswap_same_filled_pages); 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci return 0; 157262306a36Sopenharmony_ci} 157362306a36Sopenharmony_ci#else 157462306a36Sopenharmony_cistatic int zswap_debugfs_init(void) 157562306a36Sopenharmony_ci{ 157662306a36Sopenharmony_ci return 0; 157762306a36Sopenharmony_ci} 157862306a36Sopenharmony_ci#endif 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci/********************************* 158162306a36Sopenharmony_ci* module init and exit 158262306a36Sopenharmony_ci**********************************/ 158362306a36Sopenharmony_cistatic int zswap_setup(void) 158462306a36Sopenharmony_ci{ 158562306a36Sopenharmony_ci struct zswap_pool *pool; 158662306a36Sopenharmony_ci int ret; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci zswap_entry_cache = KMEM_CACHE(zswap_entry, 0); 158962306a36Sopenharmony_ci if (!zswap_entry_cache) { 159062306a36Sopenharmony_ci pr_err("entry cache creation failed\n"); 159162306a36Sopenharmony_ci goto cache_fail; 159262306a36Sopenharmony_ci } 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci ret = cpuhp_setup_state(CPUHP_MM_ZSWP_MEM_PREPARE, "mm/zswap:prepare", 159562306a36Sopenharmony_ci zswap_dstmem_prepare, zswap_dstmem_dead); 159662306a36Sopenharmony_ci if (ret) { 159762306a36Sopenharmony_ci pr_err("dstmem alloc failed\n"); 159862306a36Sopenharmony_ci goto dstmem_fail; 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci ret = cpuhp_setup_state_multi(CPUHP_MM_ZSWP_POOL_PREPARE, 160262306a36Sopenharmony_ci "mm/zswap_pool:prepare", 160362306a36Sopenharmony_ci zswap_cpu_comp_prepare, 160462306a36Sopenharmony_ci zswap_cpu_comp_dead); 160562306a36Sopenharmony_ci if (ret) 160662306a36Sopenharmony_ci goto hp_fail; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci pool = __zswap_pool_create_fallback(); 160962306a36Sopenharmony_ci if (pool) { 161062306a36Sopenharmony_ci pr_info("loaded using pool %s/%s\n", pool->tfm_name, 161162306a36Sopenharmony_ci zpool_get_type(pool->zpools[0])); 161262306a36Sopenharmony_ci list_add(&pool->list, &zswap_pools); 161362306a36Sopenharmony_ci zswap_has_pool = true; 161462306a36Sopenharmony_ci } else { 161562306a36Sopenharmony_ci pr_err("pool creation failed\n"); 161662306a36Sopenharmony_ci zswap_enabled = false; 161762306a36Sopenharmony_ci } 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci shrink_wq = create_workqueue("zswap-shrink"); 162062306a36Sopenharmony_ci if (!shrink_wq) 162162306a36Sopenharmony_ci goto fallback_fail; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci if (zswap_debugfs_init()) 162462306a36Sopenharmony_ci pr_warn("debugfs initialization failed\n"); 162562306a36Sopenharmony_ci zswap_init_state = ZSWAP_INIT_SUCCEED; 162662306a36Sopenharmony_ci return 0; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_cifallback_fail: 162962306a36Sopenharmony_ci if (pool) 163062306a36Sopenharmony_ci zswap_pool_destroy(pool); 163162306a36Sopenharmony_cihp_fail: 163262306a36Sopenharmony_ci cpuhp_remove_state(CPUHP_MM_ZSWP_MEM_PREPARE); 163362306a36Sopenharmony_cidstmem_fail: 163462306a36Sopenharmony_ci kmem_cache_destroy(zswap_entry_cache); 163562306a36Sopenharmony_cicache_fail: 163662306a36Sopenharmony_ci /* if built-in, we aren't unloaded on failure; don't allow use */ 163762306a36Sopenharmony_ci zswap_init_state = ZSWAP_INIT_FAILED; 163862306a36Sopenharmony_ci zswap_enabled = false; 163962306a36Sopenharmony_ci return -ENOMEM; 164062306a36Sopenharmony_ci} 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_cistatic int __init zswap_init(void) 164362306a36Sopenharmony_ci{ 164462306a36Sopenharmony_ci if (!zswap_enabled) 164562306a36Sopenharmony_ci return 0; 164662306a36Sopenharmony_ci return zswap_setup(); 164762306a36Sopenharmony_ci} 164862306a36Sopenharmony_ci/* must be late so crypto has time to come up */ 164962306a36Sopenharmony_cilate_initcall(zswap_init); 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ciMODULE_AUTHOR("Seth Jennings <sjennings@variantweb.net>"); 165262306a36Sopenharmony_ciMODULE_DESCRIPTION("Compressed cache for swap pages"); 1653