xref: /linux/mm/z3fold.c (revision 2c0f351434785626beb5cb49962b4e873459fd38)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29a001fc1SVitaly Wool /*
39a001fc1SVitaly Wool  * z3fold.c
49a001fc1SVitaly Wool  *
59a001fc1SVitaly Wool  * Author: Vitaly Wool <vitaly.wool@konsulko.com>
69a001fc1SVitaly Wool  * Copyright (C) 2016, Sony Mobile Communications Inc.
79a001fc1SVitaly Wool  *
89a001fc1SVitaly Wool  * This implementation is based on zbud written by Seth Jennings.
99a001fc1SVitaly Wool  *
109a001fc1SVitaly Wool  * z3fold is an special purpose allocator for storing compressed pages. It
119a001fc1SVitaly Wool  * can store up to three compressed pages per page which improves the
129a001fc1SVitaly Wool  * compression ratio of zbud while retaining its main concepts (e. g. always
139a001fc1SVitaly Wool  * storing an integral number of objects per page) and simplicity.
149a001fc1SVitaly Wool  * It still has simple and deterministic reclaim properties that make it
159a001fc1SVitaly Wool  * preferable to a higher density approach (with no requirement on integral
169a001fc1SVitaly Wool  * number of object per page) when reclaim is used.
179a001fc1SVitaly Wool  *
189a001fc1SVitaly Wool  * As in zbud, pages are divided into "chunks".  The size of the chunks is
199a001fc1SVitaly Wool  * fixed at compile time and is determined by NCHUNKS_ORDER below.
209a001fc1SVitaly Wool  *
219a001fc1SVitaly Wool  * z3fold doesn't export any API and is meant to be used via zpool API.
229a001fc1SVitaly Wool  */
239a001fc1SVitaly Wool 
249a001fc1SVitaly Wool #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
259a001fc1SVitaly Wool 
269a001fc1SVitaly Wool #include <linux/atomic.h>
27d30561c5SVitaly Wool #include <linux/sched.h>
281f862989SVitaly Wool #include <linux/cpumask.h>
299a001fc1SVitaly Wool #include <linux/list.h>
309a001fc1SVitaly Wool #include <linux/mm.h>
319a001fc1SVitaly Wool #include <linux/module.h>
321f862989SVitaly Wool #include <linux/page-flags.h>
331f862989SVitaly Wool #include <linux/migrate.h>
341f862989SVitaly Wool #include <linux/node.h>
351f862989SVitaly Wool #include <linux/compaction.h>
36d30561c5SVitaly Wool #include <linux/percpu.h>
371f862989SVitaly Wool #include <linux/mount.h>
38ea8157abSDavid Howells #include <linux/pseudo_fs.h>
391f862989SVitaly Wool #include <linux/fs.h>
409a001fc1SVitaly Wool #include <linux/preempt.h>
41d30561c5SVitaly Wool #include <linux/workqueue.h>
429a001fc1SVitaly Wool #include <linux/slab.h>
439a001fc1SVitaly Wool #include <linux/spinlock.h>
449a001fc1SVitaly Wool #include <linux/zpool.h>
45ea8157abSDavid Howells #include <linux/magic.h>
46af4798a5SQian Cai #include <linux/kmemleak.h>
479a001fc1SVitaly Wool 
489a001fc1SVitaly Wool /*
499a001fc1SVitaly Wool  * NCHUNKS_ORDER determines the internal allocation granularity, effectively
509a001fc1SVitaly Wool  * adjusting internal fragmentation.  It also determines the number of
519a001fc1SVitaly Wool  * freelists maintained in each pool. NCHUNKS_ORDER of 6 means that the
52ede93213SVitaly Wool  * allocation granularity will be in chunks of size PAGE_SIZE/64. Some chunks
53ede93213SVitaly Wool  * in the beginning of an allocated page are occupied by z3fold header, so
54ede93213SVitaly Wool  * NCHUNKS will be calculated to 63 (or 62 in case CONFIG_DEBUG_SPINLOCK=y),
55ede93213SVitaly Wool  * which shows the max number of free chunks in z3fold page, also there will
56ede93213SVitaly Wool  * be 63, or 62, respectively, freelists per pool.
579a001fc1SVitaly Wool  */
589a001fc1SVitaly Wool #define NCHUNKS_ORDER	6
599a001fc1SVitaly Wool 
609a001fc1SVitaly Wool #define CHUNK_SHIFT	(PAGE_SHIFT - NCHUNKS_ORDER)
619a001fc1SVitaly Wool #define CHUNK_SIZE	(1 << CHUNK_SHIFT)
62ede93213SVitaly Wool #define ZHDR_SIZE_ALIGNED round_up(sizeof(struct z3fold_header), CHUNK_SIZE)
63ede93213SVitaly Wool #define ZHDR_CHUNKS	(ZHDR_SIZE_ALIGNED >> CHUNK_SHIFT)
64ede93213SVitaly Wool #define TOTAL_CHUNKS	(PAGE_SIZE >> CHUNK_SHIFT)
65e3c0db4fSMiaohe Lin #define NCHUNKS		(TOTAL_CHUNKS - ZHDR_CHUNKS)
669a001fc1SVitaly Wool 
67f201ebd8Szhong jiang #define BUDDY_MASK	(0x3)
68ca0246bbSVitaly Wool #define BUDDY_SHIFT	2
697c2b8baaSVitaly Wool #define SLOTS_ALIGN	(0x40)
707c2b8baaSVitaly Wool 
717c2b8baaSVitaly Wool /*****************
727c2b8baaSVitaly Wool  * Structures
737c2b8baaSVitaly Wool *****************/
747c2b8baaSVitaly Wool struct z3fold_pool;
757c2b8baaSVitaly Wool struct z3fold_ops {
767c2b8baaSVitaly Wool 	int (*evict)(struct z3fold_pool *pool, unsigned long handle);
777c2b8baaSVitaly Wool };
787c2b8baaSVitaly Wool 
797c2b8baaSVitaly Wool enum buddy {
807c2b8baaSVitaly Wool 	HEADLESS = 0,
817c2b8baaSVitaly Wool 	FIRST,
827c2b8baaSVitaly Wool 	MIDDLE,
837c2b8baaSVitaly Wool 	LAST,
847c2b8baaSVitaly Wool 	BUDDIES_MAX = LAST
857c2b8baaSVitaly Wool };
867c2b8baaSVitaly Wool 
877c2b8baaSVitaly Wool struct z3fold_buddy_slots {
887c2b8baaSVitaly Wool 	/*
897c2b8baaSVitaly Wool 	 * we are using BUDDY_MASK in handle_to_buddy etc. so there should
907c2b8baaSVitaly Wool 	 * be enough slots to hold all possible variants
917c2b8baaSVitaly Wool 	 */
927c2b8baaSVitaly Wool 	unsigned long slot[BUDDY_MASK + 1];
93fc548865SVitaly Wool 	unsigned long pool; /* back link */
944a3ac931SVitaly Wool 	rwlock_t lock;
957c2b8baaSVitaly Wool };
967c2b8baaSVitaly Wool #define HANDLE_FLAG_MASK	(0x03)
977c2b8baaSVitaly Wool 
987c2b8baaSVitaly Wool /*
997c2b8baaSVitaly Wool  * struct z3fold_header - z3fold page metadata occupying first chunks of each
1007c2b8baaSVitaly Wool  *			z3fold page, except for HEADLESS pages
1017c2b8baaSVitaly Wool  * @buddy:		links the z3fold page into the relevant list in the
1027c2b8baaSVitaly Wool  *			pool
1037c2b8baaSVitaly Wool  * @page_lock:		per-page lock
1047c2b8baaSVitaly Wool  * @refcount:		reference count for the z3fold page
1057c2b8baaSVitaly Wool  * @work:		work_struct for page layout optimization
1067c2b8baaSVitaly Wool  * @slots:		pointer to the structure holding buddy slots
107bb9a374dSVitaly Wool  * @pool:		pointer to the containing pool
1087c2b8baaSVitaly Wool  * @cpu:		CPU which this page "belongs" to
1097c2b8baaSVitaly Wool  * @first_chunks:	the size of the first buddy in chunks, 0 if free
1107c2b8baaSVitaly Wool  * @middle_chunks:	the size of the middle buddy in chunks, 0 if free
1117c2b8baaSVitaly Wool  * @last_chunks:	the size of the last buddy in chunks, 0 if free
1127c2b8baaSVitaly Wool  * @first_num:		the starting number (for the first handle)
1131f862989SVitaly Wool  * @mapped_count:	the number of objects currently mapped
1147c2b8baaSVitaly Wool  */
1157c2b8baaSVitaly Wool struct z3fold_header {
1167c2b8baaSVitaly Wool 	struct list_head buddy;
1177c2b8baaSVitaly Wool 	spinlock_t page_lock;
1187c2b8baaSVitaly Wool 	struct kref refcount;
1197c2b8baaSVitaly Wool 	struct work_struct work;
1207c2b8baaSVitaly Wool 	struct z3fold_buddy_slots *slots;
121bb9a374dSVitaly Wool 	struct z3fold_pool *pool;
1227c2b8baaSVitaly Wool 	short cpu;
1237c2b8baaSVitaly Wool 	unsigned short first_chunks;
1247c2b8baaSVitaly Wool 	unsigned short middle_chunks;
1257c2b8baaSVitaly Wool 	unsigned short last_chunks;
1267c2b8baaSVitaly Wool 	unsigned short start_middle;
1277c2b8baaSVitaly Wool 	unsigned short first_num:2;
1281f862989SVitaly Wool 	unsigned short mapped_count:2;
1294a3ac931SVitaly Wool 	unsigned short foreign_handles:2;
1307c2b8baaSVitaly Wool };
1319a001fc1SVitaly Wool 
1329a001fc1SVitaly Wool /**
1339a001fc1SVitaly Wool  * struct z3fold_pool - stores metadata for each z3fold pool
134d30561c5SVitaly Wool  * @name:	pool name
135d30561c5SVitaly Wool  * @lock:	protects pool unbuddied/lru lists
136d30561c5SVitaly Wool  * @stale_lock:	protects pool stale page list
137d30561c5SVitaly Wool  * @unbuddied:	per-cpu array of lists tracking z3fold pages that contain 2-
138d30561c5SVitaly Wool  *		buddies; the list each z3fold page is added to depends on
139d30561c5SVitaly Wool  *		the size of its free region.
1409a001fc1SVitaly Wool  * @lru:	list tracking the z3fold pages in LRU order by most recently
1419a001fc1SVitaly Wool  *		added buddy.
142d30561c5SVitaly Wool  * @stale:	list of pages marked for freeing
1439a001fc1SVitaly Wool  * @pages_nr:	number of z3fold pages in the pool.
1447c2b8baaSVitaly Wool  * @c_handle:	cache for z3fold_buddy_slots allocation
1459a001fc1SVitaly Wool  * @ops:	pointer to a structure of user defined operations specified at
1469a001fc1SVitaly Wool  *		pool creation time.
14730522175SMel Gorman  * @zpool:	zpool driver
14830522175SMel Gorman  * @zpool_ops:	zpool operations structure with an evict callback
149d30561c5SVitaly Wool  * @compact_wq:	workqueue for page layout background optimization
150d30561c5SVitaly Wool  * @release_wq:	workqueue for safe page release
151d30561c5SVitaly Wool  * @work:	work_struct for safe page release
1521f862989SVitaly Wool  * @inode:	inode for z3fold pseudo filesystem
1539a001fc1SVitaly Wool  *
1549a001fc1SVitaly Wool  * This structure is allocated at pool creation time and maintains metadata
1559a001fc1SVitaly Wool  * pertaining to a particular z3fold pool.
1569a001fc1SVitaly Wool  */
1579a001fc1SVitaly Wool struct z3fold_pool {
158d30561c5SVitaly Wool 	const char *name;
1599a001fc1SVitaly Wool 	spinlock_t lock;
160d30561c5SVitaly Wool 	spinlock_t stale_lock;
161d30561c5SVitaly Wool 	struct list_head *unbuddied;
1629a001fc1SVitaly Wool 	struct list_head lru;
163d30561c5SVitaly Wool 	struct list_head stale;
16412d59ae6SVitaly Wool 	atomic64_t pages_nr;
1657c2b8baaSVitaly Wool 	struct kmem_cache *c_handle;
1669a001fc1SVitaly Wool 	const struct z3fold_ops *ops;
1679a001fc1SVitaly Wool 	struct zpool *zpool;
1689a001fc1SVitaly Wool 	const struct zpool_ops *zpool_ops;
169d30561c5SVitaly Wool 	struct workqueue_struct *compact_wq;
170d30561c5SVitaly Wool 	struct workqueue_struct *release_wq;
171d30561c5SVitaly Wool 	struct work_struct work;
1721f862989SVitaly Wool 	struct inode *inode;
1739a001fc1SVitaly Wool };
1749a001fc1SVitaly Wool 
1759a001fc1SVitaly Wool /*
1769a001fc1SVitaly Wool  * Internal z3fold page flags
1779a001fc1SVitaly Wool  */
1789a001fc1SVitaly Wool enum z3fold_page_flags {
1795a27aa82SVitaly Wool 	PAGE_HEADLESS = 0,
1809a001fc1SVitaly Wool 	MIDDLE_CHUNK_MAPPED,
181d30561c5SVitaly Wool 	NEEDS_COMPACTING,
1826098d7e1SVitaly Wool 	PAGE_STALE,
183ca0246bbSVitaly Wool 	PAGE_CLAIMED, /* by either reclaim or free */
1849a001fc1SVitaly Wool };
1859a001fc1SVitaly Wool 
1864a3ac931SVitaly Wool /*
187dcf5aedbSVitaly Wool  * handle flags, go under HANDLE_FLAG_MASK
188dcf5aedbSVitaly Wool  */
189dcf5aedbSVitaly Wool enum z3fold_handle_flags {
190dcf5aedbSVitaly Wool 	HANDLES_NOFREE = 0,
191dcf5aedbSVitaly Wool };
192dcf5aedbSVitaly Wool 
193dcf5aedbSVitaly Wool /*
1944a3ac931SVitaly Wool  * Forward declarations
1954a3ac931SVitaly Wool  */
1964a3ac931SVitaly Wool static struct z3fold_header *__z3fold_alloc(struct z3fold_pool *, size_t, bool);
1974a3ac931SVitaly Wool static void compact_page_work(struct work_struct *w);
1984a3ac931SVitaly Wool 
1999a001fc1SVitaly Wool /*****************
2009a001fc1SVitaly Wool  * Helpers
2019a001fc1SVitaly Wool *****************/
2029a001fc1SVitaly Wool 
2039a001fc1SVitaly Wool /* Converts an allocation size in bytes to size in z3fold chunks */
2049a001fc1SVitaly Wool static int size_to_chunks(size_t size)
2059a001fc1SVitaly Wool {
2069a001fc1SVitaly Wool 	return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
2079a001fc1SVitaly Wool }
2089a001fc1SVitaly Wool 
2099a001fc1SVitaly Wool #define for_each_unbuddied_list(_iter, _begin) \
2109a001fc1SVitaly Wool 	for ((_iter) = (_begin); (_iter) < NCHUNKS; (_iter)++)
2119a001fc1SVitaly Wool 
212bb9f6f63SVitaly Wool static inline struct z3fold_buddy_slots *alloc_slots(struct z3fold_pool *pool,
213bb9f6f63SVitaly Wool 							gfp_t gfp)
2147c2b8baaSVitaly Wool {
215f1549cb5SHenry Burns 	struct z3fold_buddy_slots *slots;
216f1549cb5SHenry Burns 
217f94afee9SHui Su 	slots = kmem_cache_zalloc(pool->c_handle,
218f1549cb5SHenry Burns 				 (gfp & ~(__GFP_HIGHMEM | __GFP_MOVABLE)));
2197c2b8baaSVitaly Wool 
2207c2b8baaSVitaly Wool 	if (slots) {
221af4798a5SQian Cai 		/* It will be freed separately in free_handle(). */
222af4798a5SQian Cai 		kmemleak_not_leak(slots);
2237c2b8baaSVitaly Wool 		slots->pool = (unsigned long)pool;
2244a3ac931SVitaly Wool 		rwlock_init(&slots->lock);
2257c2b8baaSVitaly Wool 	}
2267c2b8baaSVitaly Wool 
2277c2b8baaSVitaly Wool 	return slots;
2287c2b8baaSVitaly Wool }
2297c2b8baaSVitaly Wool 
2307c2b8baaSVitaly Wool static inline struct z3fold_pool *slots_to_pool(struct z3fold_buddy_slots *s)
2317c2b8baaSVitaly Wool {
2327c2b8baaSVitaly Wool 	return (struct z3fold_pool *)(s->pool & ~HANDLE_FLAG_MASK);
2337c2b8baaSVitaly Wool }
2347c2b8baaSVitaly Wool 
2357c2b8baaSVitaly Wool static inline struct z3fold_buddy_slots *handle_to_slots(unsigned long handle)
2367c2b8baaSVitaly Wool {
2377c2b8baaSVitaly Wool 	return (struct z3fold_buddy_slots *)(handle & ~(SLOTS_ALIGN - 1));
2387c2b8baaSVitaly Wool }
2397c2b8baaSVitaly Wool 
2404a3ac931SVitaly Wool /* Lock a z3fold page */
2414a3ac931SVitaly Wool static inline void z3fold_page_lock(struct z3fold_header *zhdr)
2424a3ac931SVitaly Wool {
2434a3ac931SVitaly Wool 	spin_lock(&zhdr->page_lock);
2444a3ac931SVitaly Wool }
2454a3ac931SVitaly Wool 
2464a3ac931SVitaly Wool /* Try to lock a z3fold page */
2474a3ac931SVitaly Wool static inline int z3fold_page_trylock(struct z3fold_header *zhdr)
2484a3ac931SVitaly Wool {
2494a3ac931SVitaly Wool 	return spin_trylock(&zhdr->page_lock);
2504a3ac931SVitaly Wool }
2514a3ac931SVitaly Wool 
2524a3ac931SVitaly Wool /* Unlock a z3fold page */
2534a3ac931SVitaly Wool static inline void z3fold_page_unlock(struct z3fold_header *zhdr)
2544a3ac931SVitaly Wool {
2554a3ac931SVitaly Wool 	spin_unlock(&zhdr->page_lock);
2564a3ac931SVitaly Wool }
2574a3ac931SVitaly Wool 
258767cc6c5SMiaohe Lin /* return locked z3fold page if it's not headless */
259767cc6c5SMiaohe Lin static inline struct z3fold_header *get_z3fold_header(unsigned long handle)
2604a3ac931SVitaly Wool {
2614a3ac931SVitaly Wool 	struct z3fold_buddy_slots *slots;
2624a3ac931SVitaly Wool 	struct z3fold_header *zhdr;
2634a3ac931SVitaly Wool 	int locked = 0;
2644a3ac931SVitaly Wool 
2654a3ac931SVitaly Wool 	if (!(handle & (1 << PAGE_HEADLESS))) {
2664a3ac931SVitaly Wool 		slots = handle_to_slots(handle);
2674a3ac931SVitaly Wool 		do {
2684a3ac931SVitaly Wool 			unsigned long addr;
2694a3ac931SVitaly Wool 
2704a3ac931SVitaly Wool 			read_lock(&slots->lock);
2714a3ac931SVitaly Wool 			addr = *(unsigned long *)handle;
2724a3ac931SVitaly Wool 			zhdr = (struct z3fold_header *)(addr & PAGE_MASK);
2734a3ac931SVitaly Wool 			locked = z3fold_page_trylock(zhdr);
2744a3ac931SVitaly Wool 			read_unlock(&slots->lock);
2754a3ac931SVitaly Wool 			if (locked)
2764a3ac931SVitaly Wool 				break;
2774a3ac931SVitaly Wool 			cpu_relax();
278767cc6c5SMiaohe Lin 		} while (true);
2794a3ac931SVitaly Wool 	} else {
2804a3ac931SVitaly Wool 		zhdr = (struct z3fold_header *)(handle & PAGE_MASK);
2814a3ac931SVitaly Wool 	}
2824a3ac931SVitaly Wool 
2834a3ac931SVitaly Wool 	return zhdr;
2844a3ac931SVitaly Wool }
2854a3ac931SVitaly Wool 
2864a3ac931SVitaly Wool static inline void put_z3fold_header(struct z3fold_header *zhdr)
2874a3ac931SVitaly Wool {
2884a3ac931SVitaly Wool 	struct page *page = virt_to_page(zhdr);
2894a3ac931SVitaly Wool 
2904a3ac931SVitaly Wool 	if (!test_bit(PAGE_HEADLESS, &page->private))
2914a3ac931SVitaly Wool 		z3fold_page_unlock(zhdr);
2924a3ac931SVitaly Wool }
2934a3ac931SVitaly Wool 
294fc548865SVitaly Wool static inline void free_handle(unsigned long handle, struct z3fold_header *zhdr)
2957c2b8baaSVitaly Wool {
2967c2b8baaSVitaly Wool 	struct z3fold_buddy_slots *slots;
2977c2b8baaSVitaly Wool 	int i;
2987c2b8baaSVitaly Wool 	bool is_free;
2997c2b8baaSVitaly Wool 
3004a3ac931SVitaly Wool 	if (WARN_ON(*(unsigned long *)handle == 0))
3014a3ac931SVitaly Wool 		return;
3024a3ac931SVitaly Wool 
3037c2b8baaSVitaly Wool 	slots = handle_to_slots(handle);
3044a3ac931SVitaly Wool 	write_lock(&slots->lock);
3054a3ac931SVitaly Wool 	*(unsigned long *)handle = 0;
306dcf5aedbSVitaly Wool 
307dcf5aedbSVitaly Wool 	if (test_bit(HANDLES_NOFREE, &slots->pool)) {
308dcf5aedbSVitaly Wool 		write_unlock(&slots->lock);
309dcf5aedbSVitaly Wool 		return; /* simple case, nothing else to do */
310dcf5aedbSVitaly Wool 	}
311dcf5aedbSVitaly Wool 
312fc548865SVitaly Wool 	if (zhdr->slots != slots)
3134a3ac931SVitaly Wool 		zhdr->foreign_handles--;
314fc548865SVitaly Wool 
3157c2b8baaSVitaly Wool 	is_free = true;
3167c2b8baaSVitaly Wool 	for (i = 0; i <= BUDDY_MASK; i++) {
3177c2b8baaSVitaly Wool 		if (slots->slot[i]) {
3187c2b8baaSVitaly Wool 			is_free = false;
3197c2b8baaSVitaly Wool 			break;
3207c2b8baaSVitaly Wool 		}
3217c2b8baaSVitaly Wool 	}
322d8f117abSUladzislau Rezki 	write_unlock(&slots->lock);
3237c2b8baaSVitaly Wool 
3247c2b8baaSVitaly Wool 	if (is_free) {
3257c2b8baaSVitaly Wool 		struct z3fold_pool *pool = slots_to_pool(slots);
3267c2b8baaSVitaly Wool 
327fc548865SVitaly Wool 		if (zhdr->slots == slots)
328fc548865SVitaly Wool 			zhdr->slots = NULL;
3297c2b8baaSVitaly Wool 		kmem_cache_free(pool->c_handle, slots);
3307c2b8baaSVitaly Wool 	}
3317c2b8baaSVitaly Wool }
3327c2b8baaSVitaly Wool 
333ea8157abSDavid Howells static int z3fold_init_fs_context(struct fs_context *fc)
3341f862989SVitaly Wool {
335ea8157abSDavid Howells 	return init_pseudo(fc, Z3FOLD_MAGIC) ? 0 : -ENOMEM;
3361f862989SVitaly Wool }
3371f862989SVitaly Wool 
3381f862989SVitaly Wool static struct file_system_type z3fold_fs = {
3391f862989SVitaly Wool 	.name		= "z3fold",
340ea8157abSDavid Howells 	.init_fs_context = z3fold_init_fs_context,
3411f862989SVitaly Wool 	.kill_sb	= kill_anon_super,
3421f862989SVitaly Wool };
3431f862989SVitaly Wool 
3441f862989SVitaly Wool static struct vfsmount *z3fold_mnt;
345dc3a1f30SMiaohe Lin static int __init z3fold_mount(void)
3461f862989SVitaly Wool {
3471f862989SVitaly Wool 	int ret = 0;
3481f862989SVitaly Wool 
3491f862989SVitaly Wool 	z3fold_mnt = kern_mount(&z3fold_fs);
3501f862989SVitaly Wool 	if (IS_ERR(z3fold_mnt))
3511f862989SVitaly Wool 		ret = PTR_ERR(z3fold_mnt);
3521f862989SVitaly Wool 
3531f862989SVitaly Wool 	return ret;
3541f862989SVitaly Wool }
3551f862989SVitaly Wool 
3561f862989SVitaly Wool static void z3fold_unmount(void)
3571f862989SVitaly Wool {
3581f862989SVitaly Wool 	kern_unmount(z3fold_mnt);
3591f862989SVitaly Wool }
3601f862989SVitaly Wool 
3611f862989SVitaly Wool static const struct address_space_operations z3fold_aops;
3621f862989SVitaly Wool static int z3fold_register_migration(struct z3fold_pool *pool)
3631f862989SVitaly Wool {
3641f862989SVitaly Wool 	pool->inode = alloc_anon_inode(z3fold_mnt->mnt_sb);
3651f862989SVitaly Wool 	if (IS_ERR(pool->inode)) {
3661f862989SVitaly Wool 		pool->inode = NULL;
3671f862989SVitaly Wool 		return 1;
3681f862989SVitaly Wool 	}
3691f862989SVitaly Wool 
3701f862989SVitaly Wool 	pool->inode->i_mapping->private_data = pool;
3711f862989SVitaly Wool 	pool->inode->i_mapping->a_ops = &z3fold_aops;
3721f862989SVitaly Wool 	return 0;
3731f862989SVitaly Wool }
3741f862989SVitaly Wool 
3751f862989SVitaly Wool static void z3fold_unregister_migration(struct z3fold_pool *pool)
3761f862989SVitaly Wool {
3771f862989SVitaly Wool 	if (pool->inode)
3781f862989SVitaly Wool 		iput(pool->inode);
3791f862989SVitaly Wool }
3801f862989SVitaly Wool 
3819a001fc1SVitaly Wool /* Initializes the z3fold header of a newly allocated z3fold page */
38263398413SVitaly Wool static struct z3fold_header *init_z3fold_page(struct page *page, bool headless,
383bb9f6f63SVitaly Wool 					struct z3fold_pool *pool, gfp_t gfp)
3849a001fc1SVitaly Wool {
3859a001fc1SVitaly Wool 	struct z3fold_header *zhdr = page_address(page);
38663398413SVitaly Wool 	struct z3fold_buddy_slots *slots;
3879a001fc1SVitaly Wool 
3889a001fc1SVitaly Wool 	INIT_LIST_HEAD(&page->lru);
3899a001fc1SVitaly Wool 	clear_bit(PAGE_HEADLESS, &page->private);
3909a001fc1SVitaly Wool 	clear_bit(MIDDLE_CHUNK_MAPPED, &page->private);
391d30561c5SVitaly Wool 	clear_bit(NEEDS_COMPACTING, &page->private);
392d30561c5SVitaly Wool 	clear_bit(PAGE_STALE, &page->private);
393ca0246bbSVitaly Wool 	clear_bit(PAGE_CLAIMED, &page->private);
39463398413SVitaly Wool 	if (headless)
39563398413SVitaly Wool 		return zhdr;
39663398413SVitaly Wool 
39763398413SVitaly Wool 	slots = alloc_slots(pool, gfp);
39863398413SVitaly Wool 	if (!slots)
39963398413SVitaly Wool 		return NULL;
4009a001fc1SVitaly Wool 
401c457cd96SMiaohe Lin 	memset(zhdr, 0, sizeof(*zhdr));
4022f1e5e4dSVitaly Wool 	spin_lock_init(&zhdr->page_lock);
4035a27aa82SVitaly Wool 	kref_init(&zhdr->refcount);
404d30561c5SVitaly Wool 	zhdr->cpu = -1;
4057c2b8baaSVitaly Wool 	zhdr->slots = slots;
406bb9a374dSVitaly Wool 	zhdr->pool = pool;
4079a001fc1SVitaly Wool 	INIT_LIST_HEAD(&zhdr->buddy);
408d30561c5SVitaly Wool 	INIT_WORK(&zhdr->work, compact_page_work);
4099a001fc1SVitaly Wool 	return zhdr;
4109a001fc1SVitaly Wool }
4119a001fc1SVitaly Wool 
4129a001fc1SVitaly Wool /* Resets the struct page fields and frees the page */
4131f862989SVitaly Wool static void free_z3fold_page(struct page *page, bool headless)
4149a001fc1SVitaly Wool {
4151f862989SVitaly Wool 	if (!headless) {
4161f862989SVitaly Wool 		lock_page(page);
4171f862989SVitaly Wool 		__ClearPageMovable(page);
4181f862989SVitaly Wool 		unlock_page(page);
4191f862989SVitaly Wool 	}
4205a27aa82SVitaly Wool 	__free_page(page);
4215a27aa82SVitaly Wool }
4225a27aa82SVitaly Wool 
4237c2b8baaSVitaly Wool /* Helper function to build the index */
4247c2b8baaSVitaly Wool static inline int __idx(struct z3fold_header *zhdr, enum buddy bud)
4257c2b8baaSVitaly Wool {
4267c2b8baaSVitaly Wool 	return (bud + zhdr->first_num) & BUDDY_MASK;
4277c2b8baaSVitaly Wool }
4287c2b8baaSVitaly Wool 
4299a001fc1SVitaly Wool /*
4309a001fc1SVitaly Wool  * Encodes the handle of a particular buddy within a z3fold page
4319a001fc1SVitaly Wool  * Pool lock should be held as this function accesses first_num
4329a001fc1SVitaly Wool  */
4333f9d2b57SVitaly Wool static unsigned long __encode_handle(struct z3fold_header *zhdr,
4343f9d2b57SVitaly Wool 				struct z3fold_buddy_slots *slots,
4353f9d2b57SVitaly Wool 				enum buddy bud)
4369a001fc1SVitaly Wool {
4377c2b8baaSVitaly Wool 	unsigned long h = (unsigned long)zhdr;
4387c2b8baaSVitaly Wool 	int idx = 0;
4399a001fc1SVitaly Wool 
4407c2b8baaSVitaly Wool 	/*
4417c2b8baaSVitaly Wool 	 * For a headless page, its handle is its pointer with the extra
4427c2b8baaSVitaly Wool 	 * PAGE_HEADLESS bit set
4437c2b8baaSVitaly Wool 	 */
4447c2b8baaSVitaly Wool 	if (bud == HEADLESS)
4457c2b8baaSVitaly Wool 		return h | (1 << PAGE_HEADLESS);
4467c2b8baaSVitaly Wool 
4477c2b8baaSVitaly Wool 	/* otherwise, return pointer to encoded handle */
4487c2b8baaSVitaly Wool 	idx = __idx(zhdr, bud);
4497c2b8baaSVitaly Wool 	h += idx;
450ca0246bbSVitaly Wool 	if (bud == LAST)
4517c2b8baaSVitaly Wool 		h |= (zhdr->last_chunks << BUDDY_SHIFT);
4527c2b8baaSVitaly Wool 
4534a3ac931SVitaly Wool 	write_lock(&slots->lock);
4547c2b8baaSVitaly Wool 	slots->slot[idx] = h;
4554a3ac931SVitaly Wool 	write_unlock(&slots->lock);
4567c2b8baaSVitaly Wool 	return (unsigned long)&slots->slot[idx];
4579a001fc1SVitaly Wool }
4589a001fc1SVitaly Wool 
4593f9d2b57SVitaly Wool static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud)
4603f9d2b57SVitaly Wool {
4613f9d2b57SVitaly Wool 	return __encode_handle(zhdr, zhdr->slots, bud);
4623f9d2b57SVitaly Wool }
4633f9d2b57SVitaly Wool 
464ca0246bbSVitaly Wool /* only for LAST bud, returns zero otherwise */
465ca0246bbSVitaly Wool static unsigned short handle_to_chunks(unsigned long handle)
466ca0246bbSVitaly Wool {
4674a3ac931SVitaly Wool 	struct z3fold_buddy_slots *slots = handle_to_slots(handle);
4684a3ac931SVitaly Wool 	unsigned long addr;
4697c2b8baaSVitaly Wool 
4704a3ac931SVitaly Wool 	read_lock(&slots->lock);
4714a3ac931SVitaly Wool 	addr = *(unsigned long *)handle;
4724a3ac931SVitaly Wool 	read_unlock(&slots->lock);
4737c2b8baaSVitaly Wool 	return (addr & ~PAGE_MASK) >> BUDDY_SHIFT;
474ca0246bbSVitaly Wool }
475ca0246bbSVitaly Wool 
476f201ebd8Szhong jiang /*
477f201ebd8Szhong jiang  * (handle & BUDDY_MASK) < zhdr->first_num is possible in encode_handle
478f201ebd8Szhong jiang  *  but that doesn't matter. because the masking will result in the
479f201ebd8Szhong jiang  *  correct buddy number.
480f201ebd8Szhong jiang  */
4819a001fc1SVitaly Wool static enum buddy handle_to_buddy(unsigned long handle)
4829a001fc1SVitaly Wool {
4837c2b8baaSVitaly Wool 	struct z3fold_header *zhdr;
4844a3ac931SVitaly Wool 	struct z3fold_buddy_slots *slots = handle_to_slots(handle);
4857c2b8baaSVitaly Wool 	unsigned long addr;
4867c2b8baaSVitaly Wool 
4874a3ac931SVitaly Wool 	read_lock(&slots->lock);
4887c2b8baaSVitaly Wool 	WARN_ON(handle & (1 << PAGE_HEADLESS));
4897c2b8baaSVitaly Wool 	addr = *(unsigned long *)handle;
4904a3ac931SVitaly Wool 	read_unlock(&slots->lock);
4917c2b8baaSVitaly Wool 	zhdr = (struct z3fold_header *)(addr & PAGE_MASK);
4927c2b8baaSVitaly Wool 	return (addr - zhdr->first_num) & BUDDY_MASK;
4939a001fc1SVitaly Wool }
4949a001fc1SVitaly Wool 
4959050cce1SVitaly Wool static inline struct z3fold_pool *zhdr_to_pool(struct z3fold_header *zhdr)
4969050cce1SVitaly Wool {
497bb9a374dSVitaly Wool 	return zhdr->pool;
4989050cce1SVitaly Wool }
4999050cce1SVitaly Wool 
500d30561c5SVitaly Wool static void __release_z3fold_page(struct z3fold_header *zhdr, bool locked)
501d30561c5SVitaly Wool {
502d30561c5SVitaly Wool 	struct page *page = virt_to_page(zhdr);
5039050cce1SVitaly Wool 	struct z3fold_pool *pool = zhdr_to_pool(zhdr);
504d30561c5SVitaly Wool 
505d30561c5SVitaly Wool 	WARN_ON(!list_empty(&zhdr->buddy));
506d30561c5SVitaly Wool 	set_bit(PAGE_STALE, &page->private);
50735529357SVitaly Wool 	clear_bit(NEEDS_COMPACTING, &page->private);
508d30561c5SVitaly Wool 	spin_lock(&pool->lock);
509d30561c5SVitaly Wool 	if (!list_empty(&page->lru))
5101f862989SVitaly Wool 		list_del_init(&page->lru);
511d30561c5SVitaly Wool 	spin_unlock(&pool->lock);
5124a3ac931SVitaly Wool 
513d30561c5SVitaly Wool 	if (locked)
514d30561c5SVitaly Wool 		z3fold_page_unlock(zhdr);
5154a3ac931SVitaly Wool 
516d30561c5SVitaly Wool 	spin_lock(&pool->stale_lock);
517d30561c5SVitaly Wool 	list_add(&zhdr->buddy, &pool->stale);
518d30561c5SVitaly Wool 	queue_work(pool->release_wq, &pool->work);
519d30561c5SVitaly Wool 	spin_unlock(&pool->stale_lock);
5205e36c25bSMiaohe Lin 
5215e36c25bSMiaohe Lin 	atomic64_dec(&pool->pages_nr);
522d30561c5SVitaly Wool }
523d30561c5SVitaly Wool 
52470ad3196SMiaohe Lin static void release_z3fold_page(struct kref *ref)
525d30561c5SVitaly Wool {
526d30561c5SVitaly Wool 	struct z3fold_header *zhdr = container_of(ref, struct z3fold_header,
527d30561c5SVitaly Wool 						refcount);
528d30561c5SVitaly Wool 	__release_z3fold_page(zhdr, false);
529d30561c5SVitaly Wool }
530d30561c5SVitaly Wool 
531d30561c5SVitaly Wool static void release_z3fold_page_locked(struct kref *ref)
532d30561c5SVitaly Wool {
533d30561c5SVitaly Wool 	struct z3fold_header *zhdr = container_of(ref, struct z3fold_header,
534d30561c5SVitaly Wool 						refcount);
535d30561c5SVitaly Wool 	WARN_ON(z3fold_page_trylock(zhdr));
536d30561c5SVitaly Wool 	__release_z3fold_page(zhdr, true);
537d30561c5SVitaly Wool }
538d30561c5SVitaly Wool 
539d30561c5SVitaly Wool static void release_z3fold_page_locked_list(struct kref *ref)
540d30561c5SVitaly Wool {
541d30561c5SVitaly Wool 	struct z3fold_header *zhdr = container_of(ref, struct z3fold_header,
542d30561c5SVitaly Wool 					       refcount);
5439050cce1SVitaly Wool 	struct z3fold_pool *pool = zhdr_to_pool(zhdr);
5444a3ac931SVitaly Wool 
5459050cce1SVitaly Wool 	spin_lock(&pool->lock);
546d30561c5SVitaly Wool 	list_del_init(&zhdr->buddy);
5479050cce1SVitaly Wool 	spin_unlock(&pool->lock);
548d30561c5SVitaly Wool 
549d30561c5SVitaly Wool 	WARN_ON(z3fold_page_trylock(zhdr));
550d30561c5SVitaly Wool 	__release_z3fold_page(zhdr, true);
551d30561c5SVitaly Wool }
552d30561c5SVitaly Wool 
553d30561c5SVitaly Wool static void free_pages_work(struct work_struct *w)
554d30561c5SVitaly Wool {
555d30561c5SVitaly Wool 	struct z3fold_pool *pool = container_of(w, struct z3fold_pool, work);
556d30561c5SVitaly Wool 
557d30561c5SVitaly Wool 	spin_lock(&pool->stale_lock);
558d30561c5SVitaly Wool 	while (!list_empty(&pool->stale)) {
559d30561c5SVitaly Wool 		struct z3fold_header *zhdr = list_first_entry(&pool->stale,
560d30561c5SVitaly Wool 						struct z3fold_header, buddy);
561d30561c5SVitaly Wool 		struct page *page = virt_to_page(zhdr);
562d30561c5SVitaly Wool 
563d30561c5SVitaly Wool 		list_del(&zhdr->buddy);
564d30561c5SVitaly Wool 		if (WARN_ON(!test_bit(PAGE_STALE, &page->private)))
565d30561c5SVitaly Wool 			continue;
566d30561c5SVitaly Wool 		spin_unlock(&pool->stale_lock);
567d30561c5SVitaly Wool 		cancel_work_sync(&zhdr->work);
5681f862989SVitaly Wool 		free_z3fold_page(page, false);
569d30561c5SVitaly Wool 		cond_resched();
570d30561c5SVitaly Wool 		spin_lock(&pool->stale_lock);
571d30561c5SVitaly Wool 	}
572d30561c5SVitaly Wool 	spin_unlock(&pool->stale_lock);
573d30561c5SVitaly Wool }
574d30561c5SVitaly Wool 
5759a001fc1SVitaly Wool /*
5769a001fc1SVitaly Wool  * Returns the number of free chunks in a z3fold page.
5779a001fc1SVitaly Wool  * NB: can't be used with HEADLESS pages.
5789a001fc1SVitaly Wool  */
5799a001fc1SVitaly Wool static int num_free_chunks(struct z3fold_header *zhdr)
5809a001fc1SVitaly Wool {
5819a001fc1SVitaly Wool 	int nfree;
5829a001fc1SVitaly Wool 	/*
5839a001fc1SVitaly Wool 	 * If there is a middle object, pick up the bigger free space
5849a001fc1SVitaly Wool 	 * either before or after it. Otherwise just subtract the number
5859a001fc1SVitaly Wool 	 * of chunks occupied by the first and the last objects.
5869a001fc1SVitaly Wool 	 */
5879a001fc1SVitaly Wool 	if (zhdr->middle_chunks != 0) {
5889a001fc1SVitaly Wool 		int nfree_before = zhdr->first_chunks ?
589ede93213SVitaly Wool 			0 : zhdr->start_middle - ZHDR_CHUNKS;
5909a001fc1SVitaly Wool 		int nfree_after = zhdr->last_chunks ?
591ede93213SVitaly Wool 			0 : TOTAL_CHUNKS -
592ede93213SVitaly Wool 				(zhdr->start_middle + zhdr->middle_chunks);
5939a001fc1SVitaly Wool 		nfree = max(nfree_before, nfree_after);
5949a001fc1SVitaly Wool 	} else
5959a001fc1SVitaly Wool 		nfree = NCHUNKS - zhdr->first_chunks - zhdr->last_chunks;
5969a001fc1SVitaly Wool 	return nfree;
5979a001fc1SVitaly Wool }
5989a001fc1SVitaly Wool 
5999050cce1SVitaly Wool /* Add to the appropriate unbuddied list */
6009050cce1SVitaly Wool static inline void add_to_unbuddied(struct z3fold_pool *pool,
6019050cce1SVitaly Wool 				struct z3fold_header *zhdr)
6029050cce1SVitaly Wool {
6039050cce1SVitaly Wool 	if (zhdr->first_chunks == 0 || zhdr->last_chunks == 0 ||
6049050cce1SVitaly Wool 			zhdr->middle_chunks == 0) {
605135f97fdSVitaly Wool 		struct list_head *unbuddied;
6069050cce1SVitaly Wool 		int freechunks = num_free_chunks(zhdr);
607135f97fdSVitaly Wool 
608135f97fdSVitaly Wool 		migrate_disable();
609135f97fdSVitaly Wool 		unbuddied = this_cpu_ptr(pool->unbuddied);
6109050cce1SVitaly Wool 		spin_lock(&pool->lock);
6119050cce1SVitaly Wool 		list_add(&zhdr->buddy, &unbuddied[freechunks]);
6129050cce1SVitaly Wool 		spin_unlock(&pool->lock);
6139050cce1SVitaly Wool 		zhdr->cpu = smp_processor_id();
614135f97fdSVitaly Wool 		migrate_enable();
6159050cce1SVitaly Wool 	}
6169050cce1SVitaly Wool }
6179050cce1SVitaly Wool 
618dcf5aedbSVitaly Wool static inline enum buddy get_free_buddy(struct z3fold_header *zhdr, int chunks)
619dcf5aedbSVitaly Wool {
620dcf5aedbSVitaly Wool 	enum buddy bud = HEADLESS;
621dcf5aedbSVitaly Wool 
622dcf5aedbSVitaly Wool 	if (zhdr->middle_chunks) {
623dcf5aedbSVitaly Wool 		if (!zhdr->first_chunks &&
624dcf5aedbSVitaly Wool 		    chunks <= zhdr->start_middle - ZHDR_CHUNKS)
625dcf5aedbSVitaly Wool 			bud = FIRST;
626dcf5aedbSVitaly Wool 		else if (!zhdr->last_chunks)
627dcf5aedbSVitaly Wool 			bud = LAST;
628dcf5aedbSVitaly Wool 	} else {
629dcf5aedbSVitaly Wool 		if (!zhdr->first_chunks)
630dcf5aedbSVitaly Wool 			bud = FIRST;
631dcf5aedbSVitaly Wool 		else if (!zhdr->last_chunks)
632dcf5aedbSVitaly Wool 			bud = LAST;
633dcf5aedbSVitaly Wool 		else
634dcf5aedbSVitaly Wool 			bud = MIDDLE;
635dcf5aedbSVitaly Wool 	}
636dcf5aedbSVitaly Wool 
637dcf5aedbSVitaly Wool 	return bud;
638dcf5aedbSVitaly Wool }
639dcf5aedbSVitaly Wool 
640ede93213SVitaly Wool static inline void *mchunk_memmove(struct z3fold_header *zhdr,
641ede93213SVitaly Wool 				unsigned short dst_chunk)
642ede93213SVitaly Wool {
643ede93213SVitaly Wool 	void *beg = zhdr;
644ede93213SVitaly Wool 	return memmove(beg + (dst_chunk << CHUNK_SHIFT),
645ede93213SVitaly Wool 		       beg + (zhdr->start_middle << CHUNK_SHIFT),
646ede93213SVitaly Wool 		       zhdr->middle_chunks << CHUNK_SHIFT);
647ede93213SVitaly Wool }
648ede93213SVitaly Wool 
6494a3ac931SVitaly Wool static inline bool buddy_single(struct z3fold_header *zhdr)
6504a3ac931SVitaly Wool {
6514a3ac931SVitaly Wool 	return !((zhdr->first_chunks && zhdr->middle_chunks) ||
6524a3ac931SVitaly Wool 			(zhdr->first_chunks && zhdr->last_chunks) ||
6534a3ac931SVitaly Wool 			(zhdr->middle_chunks && zhdr->last_chunks));
6544a3ac931SVitaly Wool }
6554a3ac931SVitaly Wool 
6564a3ac931SVitaly Wool static struct z3fold_header *compact_single_buddy(struct z3fold_header *zhdr)
6574a3ac931SVitaly Wool {
6584a3ac931SVitaly Wool 	struct z3fold_pool *pool = zhdr_to_pool(zhdr);
6594a3ac931SVitaly Wool 	void *p = zhdr;
6604a3ac931SVitaly Wool 	unsigned long old_handle = 0;
6614a3ac931SVitaly Wool 	size_t sz = 0;
6624a3ac931SVitaly Wool 	struct z3fold_header *new_zhdr = NULL;
6634a3ac931SVitaly Wool 	int first_idx = __idx(zhdr, FIRST);
6644a3ac931SVitaly Wool 	int middle_idx = __idx(zhdr, MIDDLE);
6654a3ac931SVitaly Wool 	int last_idx = __idx(zhdr, LAST);
6664a3ac931SVitaly Wool 	unsigned short *moved_chunks = NULL;
6674a3ac931SVitaly Wool 
6684a3ac931SVitaly Wool 	/*
6694a3ac931SVitaly Wool 	 * No need to protect slots here -- all the slots are "local" and
6704a3ac931SVitaly Wool 	 * the page lock is already taken
6714a3ac931SVitaly Wool 	 */
6724a3ac931SVitaly Wool 	if (zhdr->first_chunks && zhdr->slots->slot[first_idx]) {
6734a3ac931SVitaly Wool 		p += ZHDR_SIZE_ALIGNED;
6744a3ac931SVitaly Wool 		sz = zhdr->first_chunks << CHUNK_SHIFT;
6754a3ac931SVitaly Wool 		old_handle = (unsigned long)&zhdr->slots->slot[first_idx];
6764a3ac931SVitaly Wool 		moved_chunks = &zhdr->first_chunks;
6774a3ac931SVitaly Wool 	} else if (zhdr->middle_chunks && zhdr->slots->slot[middle_idx]) {
6784a3ac931SVitaly Wool 		p += zhdr->start_middle << CHUNK_SHIFT;
6794a3ac931SVitaly Wool 		sz = zhdr->middle_chunks << CHUNK_SHIFT;
6804a3ac931SVitaly Wool 		old_handle = (unsigned long)&zhdr->slots->slot[middle_idx];
6814a3ac931SVitaly Wool 		moved_chunks = &zhdr->middle_chunks;
6824a3ac931SVitaly Wool 	} else if (zhdr->last_chunks && zhdr->slots->slot[last_idx]) {
6834a3ac931SVitaly Wool 		p += PAGE_SIZE - (zhdr->last_chunks << CHUNK_SHIFT);
6844a3ac931SVitaly Wool 		sz = zhdr->last_chunks << CHUNK_SHIFT;
6854a3ac931SVitaly Wool 		old_handle = (unsigned long)&zhdr->slots->slot[last_idx];
6864a3ac931SVitaly Wool 		moved_chunks = &zhdr->last_chunks;
6874a3ac931SVitaly Wool 	}
6884a3ac931SVitaly Wool 
6894a3ac931SVitaly Wool 	if (sz > 0) {
6904a3ac931SVitaly Wool 		enum buddy new_bud = HEADLESS;
6914a3ac931SVitaly Wool 		short chunks = size_to_chunks(sz);
6924a3ac931SVitaly Wool 		void *q;
6934a3ac931SVitaly Wool 
6944a3ac931SVitaly Wool 		new_zhdr = __z3fold_alloc(pool, sz, false);
6954a3ac931SVitaly Wool 		if (!new_zhdr)
6964a3ac931SVitaly Wool 			return NULL;
6974a3ac931SVitaly Wool 
6984a3ac931SVitaly Wool 		if (WARN_ON(new_zhdr == zhdr))
6994a3ac931SVitaly Wool 			goto out_fail;
7004a3ac931SVitaly Wool 
701dcf5aedbSVitaly Wool 		new_bud = get_free_buddy(new_zhdr, chunks);
7024a3ac931SVitaly Wool 		q = new_zhdr;
7034a3ac931SVitaly Wool 		switch (new_bud) {
7044a3ac931SVitaly Wool 		case FIRST:
7054a3ac931SVitaly Wool 			new_zhdr->first_chunks = chunks;
7064a3ac931SVitaly Wool 			q += ZHDR_SIZE_ALIGNED;
7074a3ac931SVitaly Wool 			break;
7084a3ac931SVitaly Wool 		case MIDDLE:
7094a3ac931SVitaly Wool 			new_zhdr->middle_chunks = chunks;
7104a3ac931SVitaly Wool 			new_zhdr->start_middle =
7114a3ac931SVitaly Wool 				new_zhdr->first_chunks + ZHDR_CHUNKS;
7124a3ac931SVitaly Wool 			q += new_zhdr->start_middle << CHUNK_SHIFT;
7134a3ac931SVitaly Wool 			break;
7144a3ac931SVitaly Wool 		case LAST:
7154a3ac931SVitaly Wool 			new_zhdr->last_chunks = chunks;
7164a3ac931SVitaly Wool 			q += PAGE_SIZE - (new_zhdr->last_chunks << CHUNK_SHIFT);
7174a3ac931SVitaly Wool 			break;
7184a3ac931SVitaly Wool 		default:
7194a3ac931SVitaly Wool 			goto out_fail;
7204a3ac931SVitaly Wool 		}
7214a3ac931SVitaly Wool 		new_zhdr->foreign_handles++;
7224a3ac931SVitaly Wool 		memcpy(q, p, sz);
7234a3ac931SVitaly Wool 		write_lock(&zhdr->slots->lock);
7244a3ac931SVitaly Wool 		*(unsigned long *)old_handle = (unsigned long)new_zhdr +
7254a3ac931SVitaly Wool 			__idx(new_zhdr, new_bud);
7264a3ac931SVitaly Wool 		if (new_bud == LAST)
7274a3ac931SVitaly Wool 			*(unsigned long *)old_handle |=
7284a3ac931SVitaly Wool 					(new_zhdr->last_chunks << BUDDY_SHIFT);
7294a3ac931SVitaly Wool 		write_unlock(&zhdr->slots->lock);
7304a3ac931SVitaly Wool 		add_to_unbuddied(pool, new_zhdr);
7314a3ac931SVitaly Wool 		z3fold_page_unlock(new_zhdr);
7324a3ac931SVitaly Wool 
7334a3ac931SVitaly Wool 		*moved_chunks = 0;
7344a3ac931SVitaly Wool 	}
7354a3ac931SVitaly Wool 
7364a3ac931SVitaly Wool 	return new_zhdr;
7374a3ac931SVitaly Wool 
7384a3ac931SVitaly Wool out_fail:
7395e36c25bSMiaohe Lin 	if (new_zhdr && !kref_put(&new_zhdr->refcount, release_z3fold_page_locked)) {
7404a3ac931SVitaly Wool 		add_to_unbuddied(pool, new_zhdr);
7414a3ac931SVitaly Wool 		z3fold_page_unlock(new_zhdr);
7424a3ac931SVitaly Wool 	}
7434a3ac931SVitaly Wool 	return NULL;
7444a3ac931SVitaly Wool 
7454a3ac931SVitaly Wool }
7464a3ac931SVitaly Wool 
7471b096e5aSVitaly Wool #define BIG_CHUNK_GAP	3
7489a001fc1SVitaly Wool /* Has to be called with lock held */
7499a001fc1SVitaly Wool static int z3fold_compact_page(struct z3fold_header *zhdr)
7509a001fc1SVitaly Wool {
7519a001fc1SVitaly Wool 	struct page *page = virt_to_page(zhdr);
7529a001fc1SVitaly Wool 
753ede93213SVitaly Wool 	if (test_bit(MIDDLE_CHUNK_MAPPED, &page->private))
754ede93213SVitaly Wool 		return 0; /* can't move middle chunk, it's used */
7559a001fc1SVitaly Wool 
7561f862989SVitaly Wool 	if (unlikely(PageIsolated(page)))
7571f862989SVitaly Wool 		return 0;
7581f862989SVitaly Wool 
759ede93213SVitaly Wool 	if (zhdr->middle_chunks == 0)
760ede93213SVitaly Wool 		return 0; /* nothing to compact */
761ede93213SVitaly Wool 
762ede93213SVitaly Wool 	if (zhdr->first_chunks == 0 && zhdr->last_chunks == 0) {
763ede93213SVitaly Wool 		/* move to the beginning */
764ede93213SVitaly Wool 		mchunk_memmove(zhdr, ZHDR_CHUNKS);
7659a001fc1SVitaly Wool 		zhdr->first_chunks = zhdr->middle_chunks;
7669a001fc1SVitaly Wool 		zhdr->middle_chunks = 0;
7679a001fc1SVitaly Wool 		zhdr->start_middle = 0;
7689a001fc1SVitaly Wool 		zhdr->first_num++;
769ede93213SVitaly Wool 		return 1;
7709a001fc1SVitaly Wool 	}
7719a001fc1SVitaly Wool 
7721b096e5aSVitaly Wool 	/*
7731b096e5aSVitaly Wool 	 * moving data is expensive, so let's only do that if
7741b096e5aSVitaly Wool 	 * there's substantial gain (at least BIG_CHUNK_GAP chunks)
7751b096e5aSVitaly Wool 	 */
7761b096e5aSVitaly Wool 	if (zhdr->first_chunks != 0 && zhdr->last_chunks == 0 &&
7771b096e5aSVitaly Wool 	    zhdr->start_middle - (zhdr->first_chunks + ZHDR_CHUNKS) >=
7781b096e5aSVitaly Wool 			BIG_CHUNK_GAP) {
7791b096e5aSVitaly Wool 		mchunk_memmove(zhdr, zhdr->first_chunks + ZHDR_CHUNKS);
7801b096e5aSVitaly Wool 		zhdr->start_middle = zhdr->first_chunks + ZHDR_CHUNKS;
7811b096e5aSVitaly Wool 		return 1;
7821b096e5aSVitaly Wool 	} else if (zhdr->last_chunks != 0 && zhdr->first_chunks == 0 &&
7831b096e5aSVitaly Wool 		   TOTAL_CHUNKS - (zhdr->last_chunks + zhdr->start_middle
7841b096e5aSVitaly Wool 					+ zhdr->middle_chunks) >=
7851b096e5aSVitaly Wool 			BIG_CHUNK_GAP) {
7861b096e5aSVitaly Wool 		unsigned short new_start = TOTAL_CHUNKS - zhdr->last_chunks -
7871b096e5aSVitaly Wool 			zhdr->middle_chunks;
7881b096e5aSVitaly Wool 		mchunk_memmove(zhdr, new_start);
7891b096e5aSVitaly Wool 		zhdr->start_middle = new_start;
7901b096e5aSVitaly Wool 		return 1;
7911b096e5aSVitaly Wool 	}
7921b096e5aSVitaly Wool 
7931b096e5aSVitaly Wool 	return 0;
7941b096e5aSVitaly Wool }
7951b096e5aSVitaly Wool 
796d30561c5SVitaly Wool static void do_compact_page(struct z3fold_header *zhdr, bool locked)
797d30561c5SVitaly Wool {
7989050cce1SVitaly Wool 	struct z3fold_pool *pool = zhdr_to_pool(zhdr);
799d30561c5SVitaly Wool 	struct page *page;
800d30561c5SVitaly Wool 
801d30561c5SVitaly Wool 	page = virt_to_page(zhdr);
802d30561c5SVitaly Wool 	if (locked)
803d30561c5SVitaly Wool 		WARN_ON(z3fold_page_trylock(zhdr));
804d30561c5SVitaly Wool 	else
805d30561c5SVitaly Wool 		z3fold_page_lock(zhdr);
8065d03a661SVitaly Wool 	if (WARN_ON(!test_and_clear_bit(NEEDS_COMPACTING, &page->private))) {
807d30561c5SVitaly Wool 		z3fold_page_unlock(zhdr);
808d30561c5SVitaly Wool 		return;
809d30561c5SVitaly Wool 	}
810d30561c5SVitaly Wool 	spin_lock(&pool->lock);
811d30561c5SVitaly Wool 	list_del_init(&zhdr->buddy);
812d30561c5SVitaly Wool 	spin_unlock(&pool->lock);
813d30561c5SVitaly Wool 
8145e36c25bSMiaohe Lin 	if (kref_put(&zhdr->refcount, release_z3fold_page_locked))
8155d03a661SVitaly Wool 		return;
8165d03a661SVitaly Wool 
817dcf5aedbSVitaly Wool 	if (test_bit(PAGE_STALE, &page->private) ||
818dcf5aedbSVitaly Wool 	    test_and_set_bit(PAGE_CLAIMED, &page->private)) {
8191f862989SVitaly Wool 		z3fold_page_unlock(zhdr);
8201f862989SVitaly Wool 		return;
8211f862989SVitaly Wool 	}
8221f862989SVitaly Wool 
8234a3ac931SVitaly Wool 	if (!zhdr->foreign_handles && buddy_single(zhdr) &&
8244a3ac931SVitaly Wool 	    zhdr->mapped_count == 0 && compact_single_buddy(zhdr)) {
8255e36c25bSMiaohe Lin 		if (!kref_put(&zhdr->refcount, release_z3fold_page_locked)) {
826dcf5aedbSVitaly Wool 			clear_bit(PAGE_CLAIMED, &page->private);
8274a3ac931SVitaly Wool 			z3fold_page_unlock(zhdr);
828dcf5aedbSVitaly Wool 		}
8294a3ac931SVitaly Wool 		return;
8304a3ac931SVitaly Wool 	}
8314a3ac931SVitaly Wool 
832d30561c5SVitaly Wool 	z3fold_compact_page(zhdr);
8339050cce1SVitaly Wool 	add_to_unbuddied(pool, zhdr);
834dcf5aedbSVitaly Wool 	clear_bit(PAGE_CLAIMED, &page->private);
835d30561c5SVitaly Wool 	z3fold_page_unlock(zhdr);
836d30561c5SVitaly Wool }
837d30561c5SVitaly Wool 
838d30561c5SVitaly Wool static void compact_page_work(struct work_struct *w)
839d30561c5SVitaly Wool {
840d30561c5SVitaly Wool 	struct z3fold_header *zhdr = container_of(w, struct z3fold_header,
841d30561c5SVitaly Wool 						work);
842d30561c5SVitaly Wool 
843d30561c5SVitaly Wool 	do_compact_page(zhdr, false);
844d30561c5SVitaly Wool }
845d30561c5SVitaly Wool 
8469050cce1SVitaly Wool /* returns _locked_ z3fold page header or NULL */
8479050cce1SVitaly Wool static inline struct z3fold_header *__z3fold_alloc(struct z3fold_pool *pool,
8489050cce1SVitaly Wool 						size_t size, bool can_sleep)
8499050cce1SVitaly Wool {
8509050cce1SVitaly Wool 	struct z3fold_header *zhdr = NULL;
8519050cce1SVitaly Wool 	struct page *page;
8529050cce1SVitaly Wool 	struct list_head *unbuddied;
8539050cce1SVitaly Wool 	int chunks = size_to_chunks(size), i;
8549050cce1SVitaly Wool 
8559050cce1SVitaly Wool lookup:
856135f97fdSVitaly Wool 	migrate_disable();
8579050cce1SVitaly Wool 	/* First, try to find an unbuddied z3fold page. */
858135f97fdSVitaly Wool 	unbuddied = this_cpu_ptr(pool->unbuddied);
8599050cce1SVitaly Wool 	for_each_unbuddied_list(i, chunks) {
8609050cce1SVitaly Wool 		struct list_head *l = &unbuddied[i];
8619050cce1SVitaly Wool 
8629050cce1SVitaly Wool 		zhdr = list_first_entry_or_null(READ_ONCE(l),
8639050cce1SVitaly Wool 					struct z3fold_header, buddy);
8649050cce1SVitaly Wool 
8659050cce1SVitaly Wool 		if (!zhdr)
8669050cce1SVitaly Wool 			continue;
8679050cce1SVitaly Wool 
8689050cce1SVitaly Wool 		/* Re-check under lock. */
8699050cce1SVitaly Wool 		spin_lock(&pool->lock);
8709050cce1SVitaly Wool 		if (unlikely(zhdr != list_first_entry(READ_ONCE(l),
8719050cce1SVitaly Wool 						struct z3fold_header, buddy)) ||
8729050cce1SVitaly Wool 		    !z3fold_page_trylock(zhdr)) {
8739050cce1SVitaly Wool 			spin_unlock(&pool->lock);
8749050cce1SVitaly Wool 			zhdr = NULL;
875135f97fdSVitaly Wool 			migrate_enable();
8769050cce1SVitaly Wool 			if (can_sleep)
8779050cce1SVitaly Wool 				cond_resched();
8789050cce1SVitaly Wool 			goto lookup;
8799050cce1SVitaly Wool 		}
8809050cce1SVitaly Wool 		list_del_init(&zhdr->buddy);
8819050cce1SVitaly Wool 		zhdr->cpu = -1;
8829050cce1SVitaly Wool 		spin_unlock(&pool->lock);
8839050cce1SVitaly Wool 
8849050cce1SVitaly Wool 		page = virt_to_page(zhdr);
8854a3ac931SVitaly Wool 		if (test_bit(NEEDS_COMPACTING, &page->private) ||
8864a3ac931SVitaly Wool 		    test_bit(PAGE_CLAIMED, &page->private)) {
8879050cce1SVitaly Wool 			z3fold_page_unlock(zhdr);
8889050cce1SVitaly Wool 			zhdr = NULL;
889135f97fdSVitaly Wool 			migrate_enable();
8909050cce1SVitaly Wool 			if (can_sleep)
8919050cce1SVitaly Wool 				cond_resched();
8929050cce1SVitaly Wool 			goto lookup;
8939050cce1SVitaly Wool 		}
8949050cce1SVitaly Wool 
8959050cce1SVitaly Wool 		/*
8969050cce1SVitaly Wool 		 * this page could not be removed from its unbuddied
8979050cce1SVitaly Wool 		 * list while pool lock was held, and then we've taken
8989050cce1SVitaly Wool 		 * page lock so kref_put could not be called before
8999050cce1SVitaly Wool 		 * we got here, so it's safe to just call kref_get()
9009050cce1SVitaly Wool 		 */
9019050cce1SVitaly Wool 		kref_get(&zhdr->refcount);
9029050cce1SVitaly Wool 		break;
9039050cce1SVitaly Wool 	}
904135f97fdSVitaly Wool 	migrate_enable();
9059050cce1SVitaly Wool 
906351618b2SVitaly Wool 	if (!zhdr) {
907351618b2SVitaly Wool 		int cpu;
908351618b2SVitaly Wool 
909351618b2SVitaly Wool 		/* look for _exact_ match on other cpus' lists */
910351618b2SVitaly Wool 		for_each_online_cpu(cpu) {
911351618b2SVitaly Wool 			struct list_head *l;
912351618b2SVitaly Wool 
913351618b2SVitaly Wool 			unbuddied = per_cpu_ptr(pool->unbuddied, cpu);
914351618b2SVitaly Wool 			spin_lock(&pool->lock);
915351618b2SVitaly Wool 			l = &unbuddied[chunks];
916351618b2SVitaly Wool 
917351618b2SVitaly Wool 			zhdr = list_first_entry_or_null(READ_ONCE(l),
918351618b2SVitaly Wool 						struct z3fold_header, buddy);
919351618b2SVitaly Wool 
920351618b2SVitaly Wool 			if (!zhdr || !z3fold_page_trylock(zhdr)) {
921351618b2SVitaly Wool 				spin_unlock(&pool->lock);
922351618b2SVitaly Wool 				zhdr = NULL;
923351618b2SVitaly Wool 				continue;
924351618b2SVitaly Wool 			}
925351618b2SVitaly Wool 			list_del_init(&zhdr->buddy);
926351618b2SVitaly Wool 			zhdr->cpu = -1;
927351618b2SVitaly Wool 			spin_unlock(&pool->lock);
928351618b2SVitaly Wool 
929351618b2SVitaly Wool 			page = virt_to_page(zhdr);
9304a3ac931SVitaly Wool 			if (test_bit(NEEDS_COMPACTING, &page->private) ||
9314a3ac931SVitaly Wool 			    test_bit(PAGE_CLAIMED, &page->private)) {
932351618b2SVitaly Wool 				z3fold_page_unlock(zhdr);
933351618b2SVitaly Wool 				zhdr = NULL;
934351618b2SVitaly Wool 				if (can_sleep)
935351618b2SVitaly Wool 					cond_resched();
936351618b2SVitaly Wool 				continue;
937351618b2SVitaly Wool 			}
938351618b2SVitaly Wool 			kref_get(&zhdr->refcount);
939351618b2SVitaly Wool 			break;
940351618b2SVitaly Wool 		}
941351618b2SVitaly Wool 	}
942351618b2SVitaly Wool 
9437c61c35bSMiaohe Lin 	if (zhdr && !zhdr->slots) {
9444c6bdb36SMiaohe Lin 		zhdr->slots = alloc_slots(pool, GFP_ATOMIC);
9457c61c35bSMiaohe Lin 		if (!zhdr->slots)
9467c61c35bSMiaohe Lin 			goto out_fail;
9477c61c35bSMiaohe Lin 	}
9489050cce1SVitaly Wool 	return zhdr;
9497c61c35bSMiaohe Lin 
9507c61c35bSMiaohe Lin out_fail:
9517c61c35bSMiaohe Lin 	if (!kref_put(&zhdr->refcount, release_z3fold_page_locked)) {
9527c61c35bSMiaohe Lin 		add_to_unbuddied(pool, zhdr);
9537c61c35bSMiaohe Lin 		z3fold_page_unlock(zhdr);
9547c61c35bSMiaohe Lin 	}
9557c61c35bSMiaohe Lin 	return NULL;
9569050cce1SVitaly Wool }
957d30561c5SVitaly Wool 
958d30561c5SVitaly Wool /*
959d30561c5SVitaly Wool  * API Functions
960d30561c5SVitaly Wool  */
961d30561c5SVitaly Wool 
962d30561c5SVitaly Wool /**
963d30561c5SVitaly Wool  * z3fold_create_pool() - create a new z3fold pool
964d30561c5SVitaly Wool  * @name:	pool name
965d30561c5SVitaly Wool  * @gfp:	gfp flags when allocating the z3fold pool structure
966d30561c5SVitaly Wool  * @ops:	user-defined operations for the z3fold pool
967d30561c5SVitaly Wool  *
968d30561c5SVitaly Wool  * Return: pointer to the new z3fold pool or NULL if the metadata allocation
969d30561c5SVitaly Wool  * failed.
970d30561c5SVitaly Wool  */
971d30561c5SVitaly Wool static struct z3fold_pool *z3fold_create_pool(const char *name, gfp_t gfp,
972d30561c5SVitaly Wool 		const struct z3fold_ops *ops)
973d30561c5SVitaly Wool {
974d30561c5SVitaly Wool 	struct z3fold_pool *pool = NULL;
975d30561c5SVitaly Wool 	int i, cpu;
976d30561c5SVitaly Wool 
977d30561c5SVitaly Wool 	pool = kzalloc(sizeof(struct z3fold_pool), gfp);
978d30561c5SVitaly Wool 	if (!pool)
979d30561c5SVitaly Wool 		goto out;
9807c2b8baaSVitaly Wool 	pool->c_handle = kmem_cache_create("z3fold_handle",
9817c2b8baaSVitaly Wool 				sizeof(struct z3fold_buddy_slots),
9827c2b8baaSVitaly Wool 				SLOTS_ALIGN, 0, NULL);
9837c2b8baaSVitaly Wool 	if (!pool->c_handle)
9847c2b8baaSVitaly Wool 		goto out_c;
985d30561c5SVitaly Wool 	spin_lock_init(&pool->lock);
986d30561c5SVitaly Wool 	spin_lock_init(&pool->stale_lock);
987e891f60eSMiaohe Lin 	pool->unbuddied = __alloc_percpu(sizeof(struct list_head) * NCHUNKS,
988e891f60eSMiaohe Lin 					 __alignof__(struct list_head));
9891ec6995dSXidong Wang 	if (!pool->unbuddied)
9901ec6995dSXidong Wang 		goto out_pool;
991d30561c5SVitaly Wool 	for_each_possible_cpu(cpu) {
992d30561c5SVitaly Wool 		struct list_head *unbuddied =
993d30561c5SVitaly Wool 				per_cpu_ptr(pool->unbuddied, cpu);
994d30561c5SVitaly Wool 		for_each_unbuddied_list(i, 0)
995d30561c5SVitaly Wool 			INIT_LIST_HEAD(&unbuddied[i]);
996d30561c5SVitaly Wool 	}
997d30561c5SVitaly Wool 	INIT_LIST_HEAD(&pool->lru);
998d30561c5SVitaly Wool 	INIT_LIST_HEAD(&pool->stale);
999d30561c5SVitaly Wool 	atomic64_set(&pool->pages_nr, 0);
1000d30561c5SVitaly Wool 	pool->name = name;
1001d30561c5SVitaly Wool 	pool->compact_wq = create_singlethread_workqueue(pool->name);
1002d30561c5SVitaly Wool 	if (!pool->compact_wq)
10031ec6995dSXidong Wang 		goto out_unbuddied;
1004d30561c5SVitaly Wool 	pool->release_wq = create_singlethread_workqueue(pool->name);
1005d30561c5SVitaly Wool 	if (!pool->release_wq)
1006d30561c5SVitaly Wool 		goto out_wq;
10071f862989SVitaly Wool 	if (z3fold_register_migration(pool))
10081f862989SVitaly Wool 		goto out_rwq;
1009d30561c5SVitaly Wool 	INIT_WORK(&pool->work, free_pages_work);
1010d30561c5SVitaly Wool 	pool->ops = ops;
1011d30561c5SVitaly Wool 	return pool;
1012d30561c5SVitaly Wool 
10131f862989SVitaly Wool out_rwq:
10141f862989SVitaly Wool 	destroy_workqueue(pool->release_wq);
1015d30561c5SVitaly Wool out_wq:
1016d30561c5SVitaly Wool 	destroy_workqueue(pool->compact_wq);
10171ec6995dSXidong Wang out_unbuddied:
10181ec6995dSXidong Wang 	free_percpu(pool->unbuddied);
10191ec6995dSXidong Wang out_pool:
10207c2b8baaSVitaly Wool 	kmem_cache_destroy(pool->c_handle);
10217c2b8baaSVitaly Wool out_c:
1022d30561c5SVitaly Wool 	kfree(pool);
10231ec6995dSXidong Wang out:
1024d30561c5SVitaly Wool 	return NULL;
1025d30561c5SVitaly Wool }
1026d30561c5SVitaly Wool 
1027d30561c5SVitaly Wool /**
1028d30561c5SVitaly Wool  * z3fold_destroy_pool() - destroys an existing z3fold pool
1029d30561c5SVitaly Wool  * @pool:	the z3fold pool to be destroyed
1030d30561c5SVitaly Wool  *
1031d30561c5SVitaly Wool  * The pool should be emptied before this function is called.
1032d30561c5SVitaly Wool  */
1033d30561c5SVitaly Wool static void z3fold_destroy_pool(struct z3fold_pool *pool)
1034d30561c5SVitaly Wool {
10357c2b8baaSVitaly Wool 	kmem_cache_destroy(pool->c_handle);
10366051d3bdSHenry Burns 
10376051d3bdSHenry Burns 	/*
10386051d3bdSHenry Burns 	 * We need to destroy pool->compact_wq before pool->release_wq,
10396051d3bdSHenry Burns 	 * as any pending work on pool->compact_wq will call
10406051d3bdSHenry Burns 	 * queue_work(pool->release_wq, &pool->work).
1041b997052bSHenry Burns 	 *
1042b997052bSHenry Burns 	 * There are still outstanding pages until both workqueues are drained,
1043b997052bSHenry Burns 	 * so we cannot unregister migration until then.
10446051d3bdSHenry Burns 	 */
10456051d3bdSHenry Burns 
1046d30561c5SVitaly Wool 	destroy_workqueue(pool->compact_wq);
10476051d3bdSHenry Burns 	destroy_workqueue(pool->release_wq);
1048b997052bSHenry Burns 	z3fold_unregister_migration(pool);
1049dac0d1cfSMiaohe Lin 	free_percpu(pool->unbuddied);
1050d30561c5SVitaly Wool 	kfree(pool);
1051d30561c5SVitaly Wool }
1052d30561c5SVitaly Wool 
10539a001fc1SVitaly Wool /**
10549a001fc1SVitaly Wool  * z3fold_alloc() - allocates a region of a given size
10559a001fc1SVitaly Wool  * @pool:	z3fold pool from which to allocate
10569a001fc1SVitaly Wool  * @size:	size in bytes of the desired allocation
10579a001fc1SVitaly Wool  * @gfp:	gfp flags used if the pool needs to grow
10589a001fc1SVitaly Wool  * @handle:	handle of the new allocation
10599a001fc1SVitaly Wool  *
10609a001fc1SVitaly Wool  * This function will attempt to find a free region in the pool large enough to
10619a001fc1SVitaly Wool  * satisfy the allocation request.  A search of the unbuddied lists is
10629a001fc1SVitaly Wool  * performed first. If no suitable free region is found, then a new page is
10639a001fc1SVitaly Wool  * allocated and added to the pool to satisfy the request.
10649a001fc1SVitaly Wool  *
10659a001fc1SVitaly Wool  * Return: 0 if success and handle is set, otherwise -EINVAL if the size or
10669a001fc1SVitaly Wool  * gfp arguments are invalid or -ENOMEM if the pool was unable to allocate
10679a001fc1SVitaly Wool  * a new page.
10689a001fc1SVitaly Wool  */
10699a001fc1SVitaly Wool static int z3fold_alloc(struct z3fold_pool *pool, size_t size, gfp_t gfp,
10709a001fc1SVitaly Wool 			unsigned long *handle)
10719a001fc1SVitaly Wool {
10729050cce1SVitaly Wool 	int chunks = size_to_chunks(size);
10739a001fc1SVitaly Wool 	struct z3fold_header *zhdr = NULL;
1074d30561c5SVitaly Wool 	struct page *page = NULL;
10759a001fc1SVitaly Wool 	enum buddy bud;
10768a97ea54SMatthew Wilcox 	bool can_sleep = gfpflags_allow_blocking(gfp);
10779a001fc1SVitaly Wool 
1078f1549cb5SHenry Burns 	if (!size)
10799a001fc1SVitaly Wool 		return -EINVAL;
10809a001fc1SVitaly Wool 
10819a001fc1SVitaly Wool 	if (size > PAGE_SIZE)
10829a001fc1SVitaly Wool 		return -ENOSPC;
10839a001fc1SVitaly Wool 
10849a001fc1SVitaly Wool 	if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE)
10859a001fc1SVitaly Wool 		bud = HEADLESS;
10869a001fc1SVitaly Wool 	else {
10879050cce1SVitaly Wool retry:
10889050cce1SVitaly Wool 		zhdr = __z3fold_alloc(pool, size, can_sleep);
1089d30561c5SVitaly Wool 		if (zhdr) {
1090dcf5aedbSVitaly Wool 			bud = get_free_buddy(zhdr, chunks);
1091dcf5aedbSVitaly Wool 			if (bud == HEADLESS) {
10925e36c25bSMiaohe Lin 				if (!kref_put(&zhdr->refcount,
1093d30561c5SVitaly Wool 					     release_z3fold_page_locked))
1094d30561c5SVitaly Wool 					z3fold_page_unlock(zhdr);
10959a001fc1SVitaly Wool 				pr_err("No free chunks in unbuddied\n");
10969a001fc1SVitaly Wool 				WARN_ON(1);
10979050cce1SVitaly Wool 				goto retry;
10989a001fc1SVitaly Wool 			}
10999050cce1SVitaly Wool 			page = virt_to_page(zhdr);
11009a001fc1SVitaly Wool 			goto found;
11019a001fc1SVitaly Wool 		}
11029a001fc1SVitaly Wool 		bud = FIRST;
11039a001fc1SVitaly Wool 	}
11049a001fc1SVitaly Wool 
11055c9bab59SVitaly Wool 	page = alloc_page(gfp);
11069a001fc1SVitaly Wool 	if (!page)
11079a001fc1SVitaly Wool 		return -ENOMEM;
11082f1e5e4dSVitaly Wool 
110963398413SVitaly Wool 	zhdr = init_z3fold_page(page, bud == HEADLESS, pool, gfp);
11109050cce1SVitaly Wool 	if (!zhdr) {
11119050cce1SVitaly Wool 		__free_page(page);
11129050cce1SVitaly Wool 		return -ENOMEM;
11139050cce1SVitaly Wool 	}
11149050cce1SVitaly Wool 	atomic64_inc(&pool->pages_nr);
11159a001fc1SVitaly Wool 
11169a001fc1SVitaly Wool 	if (bud == HEADLESS) {
11179a001fc1SVitaly Wool 		set_bit(PAGE_HEADLESS, &page->private);
11189a001fc1SVitaly Wool 		goto headless;
11199a001fc1SVitaly Wool 	}
1120810481a2SHenry Burns 	if (can_sleep) {
1121810481a2SHenry Burns 		lock_page(page);
11221f862989SVitaly Wool 		__SetPageMovable(page, pool->inode->i_mapping);
1123810481a2SHenry Burns 		unlock_page(page);
1124810481a2SHenry Burns 	} else {
1125*2c0f3514SMiaohe Lin 		WARN_ON(!trylock_page(page));
1126810481a2SHenry Burns 		__SetPageMovable(page, pool->inode->i_mapping);
1127810481a2SHenry Burns 		unlock_page(page);
1128810481a2SHenry Burns 	}
11292f1e5e4dSVitaly Wool 	z3fold_page_lock(zhdr);
11309a001fc1SVitaly Wool 
11319a001fc1SVitaly Wool found:
11329a001fc1SVitaly Wool 	if (bud == FIRST)
11339a001fc1SVitaly Wool 		zhdr->first_chunks = chunks;
11349a001fc1SVitaly Wool 	else if (bud == LAST)
11359a001fc1SVitaly Wool 		zhdr->last_chunks = chunks;
11369a001fc1SVitaly Wool 	else {
11379a001fc1SVitaly Wool 		zhdr->middle_chunks = chunks;
1138ede93213SVitaly Wool 		zhdr->start_middle = zhdr->first_chunks + ZHDR_CHUNKS;
11399a001fc1SVitaly Wool 	}
11409050cce1SVitaly Wool 	add_to_unbuddied(pool, zhdr);
11419a001fc1SVitaly Wool 
11429a001fc1SVitaly Wool headless:
1143d30561c5SVitaly Wool 	spin_lock(&pool->lock);
11449a001fc1SVitaly Wool 	/* Add/move z3fold page to beginning of LRU */
11459a001fc1SVitaly Wool 	if (!list_empty(&page->lru))
11469a001fc1SVitaly Wool 		list_del(&page->lru);
11479a001fc1SVitaly Wool 
11489a001fc1SVitaly Wool 	list_add(&page->lru, &pool->lru);
11499a001fc1SVitaly Wool 
11509a001fc1SVitaly Wool 	*handle = encode_handle(zhdr, bud);
11519a001fc1SVitaly Wool 	spin_unlock(&pool->lock);
11522f1e5e4dSVitaly Wool 	if (bud != HEADLESS)
11532f1e5e4dSVitaly Wool 		z3fold_page_unlock(zhdr);
11549a001fc1SVitaly Wool 
11559a001fc1SVitaly Wool 	return 0;
11569a001fc1SVitaly Wool }
11579a001fc1SVitaly Wool 
11589a001fc1SVitaly Wool /**
11599a001fc1SVitaly Wool  * z3fold_free() - frees the allocation associated with the given handle
11609a001fc1SVitaly Wool  * @pool:	pool in which the allocation resided
11619a001fc1SVitaly Wool  * @handle:	handle associated with the allocation returned by z3fold_alloc()
11629a001fc1SVitaly Wool  *
11639a001fc1SVitaly Wool  * In the case that the z3fold page in which the allocation resides is under
1164ed0e5dcaSMiaohe Lin  * reclaim, as indicated by the PAGE_CLAIMED flag being set, this function
1165ed0e5dcaSMiaohe Lin  * only sets the first|middle|last_chunks to 0.  The page is actually freed
1166ed0e5dcaSMiaohe Lin  * once all buddies are evicted (see z3fold_reclaim_page() below).
11679a001fc1SVitaly Wool  */
11689a001fc1SVitaly Wool static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
11699a001fc1SVitaly Wool {
11709a001fc1SVitaly Wool 	struct z3fold_header *zhdr;
11719a001fc1SVitaly Wool 	struct page *page;
11729a001fc1SVitaly Wool 	enum buddy bud;
11735b6807deSVitaly Wool 	bool page_claimed;
11749a001fc1SVitaly Wool 
11754a3ac931SVitaly Wool 	zhdr = get_z3fold_header(handle);
11769a001fc1SVitaly Wool 	page = virt_to_page(zhdr);
11775b6807deSVitaly Wool 	page_claimed = test_and_set_bit(PAGE_CLAIMED, &page->private);
11789a001fc1SVitaly Wool 
11799a001fc1SVitaly Wool 	if (test_bit(PAGE_HEADLESS, &page->private)) {
1180ca0246bbSVitaly Wool 		/* if a headless page is under reclaim, just leave.
1181ca0246bbSVitaly Wool 		 * NB: we use test_and_set_bit for a reason: if the bit
1182ca0246bbSVitaly Wool 		 * has not been set before, we release this page
1183ca0246bbSVitaly Wool 		 * immediately so we don't care about its value any more.
1184ca0246bbSVitaly Wool 		 */
11855b6807deSVitaly Wool 		if (!page_claimed) {
1186ca0246bbSVitaly Wool 			spin_lock(&pool->lock);
1187ca0246bbSVitaly Wool 			list_del(&page->lru);
1188ca0246bbSVitaly Wool 			spin_unlock(&pool->lock);
11894a3ac931SVitaly Wool 			put_z3fold_header(zhdr);
11901f862989SVitaly Wool 			free_z3fold_page(page, true);
1191ca0246bbSVitaly Wool 			atomic64_dec(&pool->pages_nr);
1192ca0246bbSVitaly Wool 		}
1193ca0246bbSVitaly Wool 		return;
1194ca0246bbSVitaly Wool 	}
1195ca0246bbSVitaly Wool 
1196ca0246bbSVitaly Wool 	/* Non-headless case */
119743afc194SVitaly Wool 	bud = handle_to_buddy(handle);
11989a001fc1SVitaly Wool 
11999a001fc1SVitaly Wool 	switch (bud) {
12009a001fc1SVitaly Wool 	case FIRST:
12019a001fc1SVitaly Wool 		zhdr->first_chunks = 0;
12029a001fc1SVitaly Wool 		break;
12039a001fc1SVitaly Wool 	case MIDDLE:
12049a001fc1SVitaly Wool 		zhdr->middle_chunks = 0;
12059a001fc1SVitaly Wool 		break;
12069a001fc1SVitaly Wool 	case LAST:
12079a001fc1SVitaly Wool 		zhdr->last_chunks = 0;
12089a001fc1SVitaly Wool 		break;
12099a001fc1SVitaly Wool 	default:
12109a001fc1SVitaly Wool 		pr_err("%s: unknown bud %d\n", __func__, bud);
12119a001fc1SVitaly Wool 		WARN_ON(1);
12124a3ac931SVitaly Wool 		put_z3fold_header(zhdr);
12139a001fc1SVitaly Wool 		return;
12149a001fc1SVitaly Wool 	}
12159a001fc1SVitaly Wool 
12164a3ac931SVitaly Wool 	if (!page_claimed)
1217fc548865SVitaly Wool 		free_handle(handle, zhdr);
12185e36c25bSMiaohe Lin 	if (kref_put(&zhdr->refcount, release_z3fold_page_locked_list))
1219d30561c5SVitaly Wool 		return;
12205b6807deSVitaly Wool 	if (page_claimed) {
12215b6807deSVitaly Wool 		/* the page has not been claimed by us */
1222ed0e5dcaSMiaohe Lin 		put_z3fold_header(zhdr);
12236098d7e1SVitaly Wool 		return;
12246098d7e1SVitaly Wool 	}
1225dcf5aedbSVitaly Wool 	if (test_and_set_bit(NEEDS_COMPACTING, &page->private)) {
12264a3ac931SVitaly Wool 		put_z3fold_header(zhdr);
12275b6807deSVitaly Wool 		clear_bit(PAGE_CLAIMED, &page->private);
1228d30561c5SVitaly Wool 		return;
1229d30561c5SVitaly Wool 	}
1230d30561c5SVitaly Wool 	if (zhdr->cpu < 0 || !cpu_online(zhdr->cpu)) {
1231d30561c5SVitaly Wool 		zhdr->cpu = -1;
12325d03a661SVitaly Wool 		kref_get(&zhdr->refcount);
12335b6807deSVitaly Wool 		clear_bit(PAGE_CLAIMED, &page->private);
12344a3ac931SVitaly Wool 		do_compact_page(zhdr, true);
1235d30561c5SVitaly Wool 		return;
1236d30561c5SVitaly Wool 	}
12375d03a661SVitaly Wool 	kref_get(&zhdr->refcount);
12385b6807deSVitaly Wool 	clear_bit(PAGE_CLAIMED, &page->private);
12394a3ac931SVitaly Wool 	queue_work_on(zhdr->cpu, pool->compact_wq, &zhdr->work);
12404a3ac931SVitaly Wool 	put_z3fold_header(zhdr);
12419a001fc1SVitaly Wool }
12429a001fc1SVitaly Wool 
12439a001fc1SVitaly Wool /**
12449a001fc1SVitaly Wool  * z3fold_reclaim_page() - evicts allocations from a pool page and frees it
12459a001fc1SVitaly Wool  * @pool:	pool from which a page will attempt to be evicted
1246f144c390SMike Rapoport  * @retries:	number of pages on the LRU list for which eviction will
12479a001fc1SVitaly Wool  *		be attempted before failing
12489a001fc1SVitaly Wool  *
12499a001fc1SVitaly Wool  * z3fold reclaim is different from normal system reclaim in that it is done
12509a001fc1SVitaly Wool  * from the bottom, up. This is because only the bottom layer, z3fold, has
12519a001fc1SVitaly Wool  * information on how the allocations are organized within each z3fold page.
12529a001fc1SVitaly Wool  * This has the potential to create interesting locking situations between
12539a001fc1SVitaly Wool  * z3fold and the user, however.
12549a001fc1SVitaly Wool  *
12559a001fc1SVitaly Wool  * To avoid these, this is how z3fold_reclaim_page() should be called:
1256f144c390SMike Rapoport  *
12579a001fc1SVitaly Wool  * The user detects a page should be reclaimed and calls z3fold_reclaim_page().
12589a001fc1SVitaly Wool  * z3fold_reclaim_page() will remove a z3fold page from the pool LRU list and
12599a001fc1SVitaly Wool  * call the user-defined eviction handler with the pool and handle as
12609a001fc1SVitaly Wool  * arguments.
12619a001fc1SVitaly Wool  *
12629a001fc1SVitaly Wool  * If the handle can not be evicted, the eviction handler should return
12639a001fc1SVitaly Wool  * non-zero. z3fold_reclaim_page() will add the z3fold page back to the
12649a001fc1SVitaly Wool  * appropriate list and try the next z3fold page on the LRU up to
12659a001fc1SVitaly Wool  * a user defined number of retries.
12669a001fc1SVitaly Wool  *
12679a001fc1SVitaly Wool  * If the handle is successfully evicted, the eviction handler should
12689a001fc1SVitaly Wool  * return 0 _and_ should have called z3fold_free() on the handle. z3fold_free()
12699a001fc1SVitaly Wool  * contains logic to delay freeing the page if the page is under reclaim,
12709a001fc1SVitaly Wool  * as indicated by the setting of the PG_reclaim flag on the underlying page.
12719a001fc1SVitaly Wool  *
12729a001fc1SVitaly Wool  * If all buddies in the z3fold page are successfully evicted, then the
12739a001fc1SVitaly Wool  * z3fold page can be freed.
12749a001fc1SVitaly Wool  *
12759a001fc1SVitaly Wool  * Returns: 0 if page is successfully freed, otherwise -EINVAL if there are
12769a001fc1SVitaly Wool  * no pages to evict or an eviction handler is not registered, -EAGAIN if
12779a001fc1SVitaly Wool  * the retry limit was hit.
12789a001fc1SVitaly Wool  */
12799a001fc1SVitaly Wool static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
12809a001fc1SVitaly Wool {
12814a3ac931SVitaly Wool 	int i, ret = -1;
1282d30561c5SVitaly Wool 	struct z3fold_header *zhdr = NULL;
1283d30561c5SVitaly Wool 	struct page *page = NULL;
1284d30561c5SVitaly Wool 	struct list_head *pos;
12859a001fc1SVitaly Wool 	unsigned long first_handle = 0, middle_handle = 0, last_handle = 0;
1286dcf5aedbSVitaly Wool 	struct z3fold_buddy_slots slots __attribute__((aligned(SLOTS_ALIGN)));
1287dcf5aedbSVitaly Wool 
1288dcf5aedbSVitaly Wool 	rwlock_init(&slots.lock);
1289dcf5aedbSVitaly Wool 	slots.pool = (unsigned long)pool | (1 << HANDLES_NOFREE);
12909a001fc1SVitaly Wool 
12919a001fc1SVitaly Wool 	spin_lock(&pool->lock);
12922f1e5e4dSVitaly Wool 	if (!pool->ops || !pool->ops->evict || retries == 0) {
12939a001fc1SVitaly Wool 		spin_unlock(&pool->lock);
12949a001fc1SVitaly Wool 		return -EINVAL;
12959a001fc1SVitaly Wool 	}
12969a001fc1SVitaly Wool 	for (i = 0; i < retries; i++) {
12972f1e5e4dSVitaly Wool 		if (list_empty(&pool->lru)) {
12982f1e5e4dSVitaly Wool 			spin_unlock(&pool->lock);
12992f1e5e4dSVitaly Wool 			return -EINVAL;
13002f1e5e4dSVitaly Wool 		}
1301d30561c5SVitaly Wool 		list_for_each_prev(pos, &pool->lru) {
1302d30561c5SVitaly Wool 			page = list_entry(pos, struct page, lru);
1303ca0246bbSVitaly Wool 
13043f9d2b57SVitaly Wool 			zhdr = page_address(page);
13056d679578SThomas Hebb 			if (test_bit(PAGE_HEADLESS, &page->private)) {
13066d679578SThomas Hebb 				/*
13076d679578SThomas Hebb 				 * For non-headless pages, we wait to do this
13086d679578SThomas Hebb 				 * until we have the page lock to avoid racing
13096d679578SThomas Hebb 				 * with __z3fold_alloc(). Headless pages don't
13106d679578SThomas Hebb 				 * have a lock (and __z3fold_alloc() will never
13116d679578SThomas Hebb 				 * see them), but we still need to test and set
13126d679578SThomas Hebb 				 * PAGE_CLAIMED to avoid racing with
13136d679578SThomas Hebb 				 * z3fold_free(), so just do it now before
13146d679578SThomas Hebb 				 * leaving the loop.
13156d679578SThomas Hebb 				 */
13166d679578SThomas Hebb 				if (test_and_set_bit(PAGE_CLAIMED, &page->private))
13176d679578SThomas Hebb 					continue;
13186d679578SThomas Hebb 
1319ca0246bbSVitaly Wool 				break;
13206d679578SThomas Hebb 			}
1321ca0246bbSVitaly Wool 
1322dcf5aedbSVitaly Wool 			if (kref_get_unless_zero(&zhdr->refcount) == 0) {
1323dcf5aedbSVitaly Wool 				zhdr = NULL;
1324dcf5aedbSVitaly Wool 				break;
1325dcf5aedbSVitaly Wool 			}
1326ca0246bbSVitaly Wool 			if (!z3fold_page_trylock(zhdr)) {
13275e36c25bSMiaohe Lin 				kref_put(&zhdr->refcount, release_z3fold_page);
1328ca0246bbSVitaly Wool 				zhdr = NULL;
1329d30561c5SVitaly Wool 				continue; /* can't evict at this point */
1330ca0246bbSVitaly Wool 			}
1331dcf5aedbSVitaly Wool 
1332dcf5aedbSVitaly Wool 			/* test_and_set_bit is of course atomic, but we still
1333dcf5aedbSVitaly Wool 			 * need to do it under page lock, otherwise checking
1334dcf5aedbSVitaly Wool 			 * that bit in __z3fold_alloc wouldn't make sense
1335dcf5aedbSVitaly Wool 			 */
1336dcf5aedbSVitaly Wool 			if (zhdr->foreign_handles ||
1337dcf5aedbSVitaly Wool 			    test_and_set_bit(PAGE_CLAIMED, &page->private)) {
13385e36c25bSMiaohe Lin 				if (!kref_put(&zhdr->refcount,
133928473d91SMiaohe Lin 						release_z3fold_page_locked))
13404a3ac931SVitaly Wool 					z3fold_page_unlock(zhdr);
13414a3ac931SVitaly Wool 				zhdr = NULL;
13424a3ac931SVitaly Wool 				continue; /* can't evict such page */
13434a3ac931SVitaly Wool 			}
1344d30561c5SVitaly Wool 			list_del_init(&zhdr->buddy);
1345d30561c5SVitaly Wool 			zhdr->cpu = -1;
13466098d7e1SVitaly Wool 			break;
1347d30561c5SVitaly Wool 		}
1348d30561c5SVitaly Wool 
1349ca0246bbSVitaly Wool 		if (!zhdr)
1350ca0246bbSVitaly Wool 			break;
1351ca0246bbSVitaly Wool 
1352d30561c5SVitaly Wool 		list_del_init(&page->lru);
13532f1e5e4dSVitaly Wool 		spin_unlock(&pool->lock);
1354d30561c5SVitaly Wool 
1355d30561c5SVitaly Wool 		if (!test_bit(PAGE_HEADLESS, &page->private)) {
13569a001fc1SVitaly Wool 			/*
13573f9d2b57SVitaly Wool 			 * We need encode the handles before unlocking, and
13583f9d2b57SVitaly Wool 			 * use our local slots structure because z3fold_free
13593f9d2b57SVitaly Wool 			 * can zero out zhdr->slots and we can't do much
13603f9d2b57SVitaly Wool 			 * about that
13619a001fc1SVitaly Wool 			 */
13629a001fc1SVitaly Wool 			first_handle = 0;
13639a001fc1SVitaly Wool 			last_handle = 0;
13649a001fc1SVitaly Wool 			middle_handle = 0;
1365dcf5aedbSVitaly Wool 			memset(slots.slot, 0, sizeof(slots.slot));
13669a001fc1SVitaly Wool 			if (zhdr->first_chunks)
1367dcf5aedbSVitaly Wool 				first_handle = __encode_handle(zhdr, &slots,
1368dcf5aedbSVitaly Wool 								FIRST);
13699a001fc1SVitaly Wool 			if (zhdr->middle_chunks)
1370dcf5aedbSVitaly Wool 				middle_handle = __encode_handle(zhdr, &slots,
1371dcf5aedbSVitaly Wool 								MIDDLE);
13729a001fc1SVitaly Wool 			if (zhdr->last_chunks)
1373dcf5aedbSVitaly Wool 				last_handle = __encode_handle(zhdr, &slots,
1374dcf5aedbSVitaly Wool 								LAST);
1375d30561c5SVitaly Wool 			/*
1376d30561c5SVitaly Wool 			 * it's safe to unlock here because we hold a
1377d30561c5SVitaly Wool 			 * reference to this page
1378d30561c5SVitaly Wool 			 */
13792f1e5e4dSVitaly Wool 			z3fold_page_unlock(zhdr);
13809a001fc1SVitaly Wool 		} else {
13814a3ac931SVitaly Wool 			first_handle = encode_handle(zhdr, HEADLESS);
13829a001fc1SVitaly Wool 			last_handle = middle_handle = 0;
13832f1e5e4dSVitaly Wool 		}
13849a001fc1SVitaly Wool 		/* Issue the eviction callback(s) */
13859a001fc1SVitaly Wool 		if (middle_handle) {
13869a001fc1SVitaly Wool 			ret = pool->ops->evict(pool, middle_handle);
13879a001fc1SVitaly Wool 			if (ret)
13889a001fc1SVitaly Wool 				goto next;
13899a001fc1SVitaly Wool 		}
13909a001fc1SVitaly Wool 		if (first_handle) {
13919a001fc1SVitaly Wool 			ret = pool->ops->evict(pool, first_handle);
13929a001fc1SVitaly Wool 			if (ret)
13939a001fc1SVitaly Wool 				goto next;
13949a001fc1SVitaly Wool 		}
13959a001fc1SVitaly Wool 		if (last_handle) {
13969a001fc1SVitaly Wool 			ret = pool->ops->evict(pool, last_handle);
13979a001fc1SVitaly Wool 			if (ret)
13989a001fc1SVitaly Wool 				goto next;
13999a001fc1SVitaly Wool 		}
14009a001fc1SVitaly Wool next:
14015a27aa82SVitaly Wool 		if (test_bit(PAGE_HEADLESS, &page->private)) {
14025a27aa82SVitaly Wool 			if (ret == 0) {
14031f862989SVitaly Wool 				free_z3fold_page(page, true);
1404ca0246bbSVitaly Wool 				atomic64_dec(&pool->pages_nr);
14059a001fc1SVitaly Wool 				return 0;
14065a27aa82SVitaly Wool 			}
14076098d7e1SVitaly Wool 			spin_lock(&pool->lock);
14086098d7e1SVitaly Wool 			list_add(&page->lru, &pool->lru);
1409d5567c9dSVitaly Wool 			spin_unlock(&pool->lock);
14103f9d2b57SVitaly Wool 			clear_bit(PAGE_CLAIMED, &page->private);
14116098d7e1SVitaly Wool 		} else {
1412dcf5aedbSVitaly Wool 			struct z3fold_buddy_slots *slots = zhdr->slots;
14136098d7e1SVitaly Wool 			z3fold_page_lock(zhdr);
14146098d7e1SVitaly Wool 			if (kref_put(&zhdr->refcount,
14156098d7e1SVitaly Wool 					release_z3fold_page_locked)) {
1416dcf5aedbSVitaly Wool 				kmem_cache_free(pool->c_handle, slots);
14175a27aa82SVitaly Wool 				return 0;
14185a27aa82SVitaly Wool 			}
14195a27aa82SVitaly Wool 			/*
14206098d7e1SVitaly Wool 			 * if we are here, the page is still not completely
14216098d7e1SVitaly Wool 			 * free. Take the global pool lock then to be able
14226098d7e1SVitaly Wool 			 * to add it back to the lru list
14235a27aa82SVitaly Wool 			 */
14246098d7e1SVitaly Wool 			spin_lock(&pool->lock);
14259a001fc1SVitaly Wool 			list_add(&page->lru, &pool->lru);
14266098d7e1SVitaly Wool 			spin_unlock(&pool->lock);
14276098d7e1SVitaly Wool 			z3fold_page_unlock(zhdr);
14283f9d2b57SVitaly Wool 			clear_bit(PAGE_CLAIMED, &page->private);
14296098d7e1SVitaly Wool 		}
14306098d7e1SVitaly Wool 
14316098d7e1SVitaly Wool 		/* We started off locked to we need to lock the pool back */
14326098d7e1SVitaly Wool 		spin_lock(&pool->lock);
14339a001fc1SVitaly Wool 	}
14349a001fc1SVitaly Wool 	spin_unlock(&pool->lock);
14359a001fc1SVitaly Wool 	return -EAGAIN;
14369a001fc1SVitaly Wool }
14379a001fc1SVitaly Wool 
14389a001fc1SVitaly Wool /**
14399a001fc1SVitaly Wool  * z3fold_map() - maps the allocation associated with the given handle
14409a001fc1SVitaly Wool  * @pool:	pool in which the allocation resides
14419a001fc1SVitaly Wool  * @handle:	handle associated with the allocation to be mapped
14429a001fc1SVitaly Wool  *
14439a001fc1SVitaly Wool  * Extracts the buddy number from handle and constructs the pointer to the
14449a001fc1SVitaly Wool  * correct starting chunk within the page.
14459a001fc1SVitaly Wool  *
14469a001fc1SVitaly Wool  * Returns: a pointer to the mapped allocation
14479a001fc1SVitaly Wool  */
14489a001fc1SVitaly Wool static void *z3fold_map(struct z3fold_pool *pool, unsigned long handle)
14499a001fc1SVitaly Wool {
14509a001fc1SVitaly Wool 	struct z3fold_header *zhdr;
14519a001fc1SVitaly Wool 	struct page *page;
14529a001fc1SVitaly Wool 	void *addr;
14539a001fc1SVitaly Wool 	enum buddy buddy;
14549a001fc1SVitaly Wool 
14554a3ac931SVitaly Wool 	zhdr = get_z3fold_header(handle);
14569a001fc1SVitaly Wool 	addr = zhdr;
14579a001fc1SVitaly Wool 	page = virt_to_page(zhdr);
14589a001fc1SVitaly Wool 
14599a001fc1SVitaly Wool 	if (test_bit(PAGE_HEADLESS, &page->private))
14609a001fc1SVitaly Wool 		goto out;
14619a001fc1SVitaly Wool 
14629a001fc1SVitaly Wool 	buddy = handle_to_buddy(handle);
14639a001fc1SVitaly Wool 	switch (buddy) {
14649a001fc1SVitaly Wool 	case FIRST:
14659a001fc1SVitaly Wool 		addr += ZHDR_SIZE_ALIGNED;
14669a001fc1SVitaly Wool 		break;
14679a001fc1SVitaly Wool 	case MIDDLE:
14689a001fc1SVitaly Wool 		addr += zhdr->start_middle << CHUNK_SHIFT;
14699a001fc1SVitaly Wool 		set_bit(MIDDLE_CHUNK_MAPPED, &page->private);
14709a001fc1SVitaly Wool 		break;
14719a001fc1SVitaly Wool 	case LAST:
1472ca0246bbSVitaly Wool 		addr += PAGE_SIZE - (handle_to_chunks(handle) << CHUNK_SHIFT);
14739a001fc1SVitaly Wool 		break;
14749a001fc1SVitaly Wool 	default:
14759a001fc1SVitaly Wool 		pr_err("unknown buddy id %d\n", buddy);
14769a001fc1SVitaly Wool 		WARN_ON(1);
14779a001fc1SVitaly Wool 		addr = NULL;
14789a001fc1SVitaly Wool 		break;
14799a001fc1SVitaly Wool 	}
14802f1e5e4dSVitaly Wool 
14811f862989SVitaly Wool 	if (addr)
14821f862989SVitaly Wool 		zhdr->mapped_count++;
14839a001fc1SVitaly Wool out:
14844a3ac931SVitaly Wool 	put_z3fold_header(zhdr);
14859a001fc1SVitaly Wool 	return addr;
14869a001fc1SVitaly Wool }
14879a001fc1SVitaly Wool 
14889a001fc1SVitaly Wool /**
14899a001fc1SVitaly Wool  * z3fold_unmap() - unmaps the allocation associated with the given handle
14909a001fc1SVitaly Wool  * @pool:	pool in which the allocation resides
14919a001fc1SVitaly Wool  * @handle:	handle associated with the allocation to be unmapped
14929a001fc1SVitaly Wool  */
14939a001fc1SVitaly Wool static void z3fold_unmap(struct z3fold_pool *pool, unsigned long handle)
14949a001fc1SVitaly Wool {
14959a001fc1SVitaly Wool 	struct z3fold_header *zhdr;
14969a001fc1SVitaly Wool 	struct page *page;
14979a001fc1SVitaly Wool 	enum buddy buddy;
14989a001fc1SVitaly Wool 
14994a3ac931SVitaly Wool 	zhdr = get_z3fold_header(handle);
15009a001fc1SVitaly Wool 	page = virt_to_page(zhdr);
15019a001fc1SVitaly Wool 
15022f1e5e4dSVitaly Wool 	if (test_bit(PAGE_HEADLESS, &page->private))
15039a001fc1SVitaly Wool 		return;
15049a001fc1SVitaly Wool 
15059a001fc1SVitaly Wool 	buddy = handle_to_buddy(handle);
15069a001fc1SVitaly Wool 	if (buddy == MIDDLE)
15079a001fc1SVitaly Wool 		clear_bit(MIDDLE_CHUNK_MAPPED, &page->private);
15081f862989SVitaly Wool 	zhdr->mapped_count--;
15094a3ac931SVitaly Wool 	put_z3fold_header(zhdr);
15109a001fc1SVitaly Wool }
15119a001fc1SVitaly Wool 
15129a001fc1SVitaly Wool /**
15139a001fc1SVitaly Wool  * z3fold_get_pool_size() - gets the z3fold pool size in pages
15149a001fc1SVitaly Wool  * @pool:	pool whose size is being queried
15159a001fc1SVitaly Wool  *
151612d59ae6SVitaly Wool  * Returns: size in pages of the given pool.
15179a001fc1SVitaly Wool  */
15189a001fc1SVitaly Wool static u64 z3fold_get_pool_size(struct z3fold_pool *pool)
15199a001fc1SVitaly Wool {
152012d59ae6SVitaly Wool 	return atomic64_read(&pool->pages_nr);
15219a001fc1SVitaly Wool }
15229a001fc1SVitaly Wool 
15231f862989SVitaly Wool static bool z3fold_page_isolate(struct page *page, isolate_mode_t mode)
15241f862989SVitaly Wool {
15251f862989SVitaly Wool 	struct z3fold_header *zhdr;
15261f862989SVitaly Wool 	struct z3fold_pool *pool;
15271f862989SVitaly Wool 
15281f862989SVitaly Wool 	VM_BUG_ON_PAGE(!PageMovable(page), page);
15291f862989SVitaly Wool 	VM_BUG_ON_PAGE(PageIsolated(page), page);
15301f862989SVitaly Wool 
1531dcf5aedbSVitaly Wool 	if (test_bit(PAGE_HEADLESS, &page->private))
15321f862989SVitaly Wool 		return false;
15331f862989SVitaly Wool 
15341f862989SVitaly Wool 	zhdr = page_address(page);
15351f862989SVitaly Wool 	z3fold_page_lock(zhdr);
15361f862989SVitaly Wool 	if (test_bit(NEEDS_COMPACTING, &page->private) ||
15371f862989SVitaly Wool 	    test_bit(PAGE_STALE, &page->private))
15381f862989SVitaly Wool 		goto out;
15391f862989SVitaly Wool 
15404a3ac931SVitaly Wool 	if (zhdr->mapped_count != 0 || zhdr->foreign_handles != 0)
15414a3ac931SVitaly Wool 		goto out;
15421f862989SVitaly Wool 
1543dcf5aedbSVitaly Wool 	if (test_and_set_bit(PAGE_CLAIMED, &page->private))
1544dcf5aedbSVitaly Wool 		goto out;
15454a3ac931SVitaly Wool 	pool = zhdr_to_pool(zhdr);
15464a3ac931SVitaly Wool 	spin_lock(&pool->lock);
15471f862989SVitaly Wool 	if (!list_empty(&zhdr->buddy))
15481f862989SVitaly Wool 		list_del_init(&zhdr->buddy);
15491f862989SVitaly Wool 	if (!list_empty(&page->lru))
15504a3ac931SVitaly Wool 		list_del_init(&page->lru);
15511f862989SVitaly Wool 	spin_unlock(&pool->lock);
15524a3ac931SVitaly Wool 
15534a3ac931SVitaly Wool 	kref_get(&zhdr->refcount);
15541f862989SVitaly Wool 	z3fold_page_unlock(zhdr);
15551f862989SVitaly Wool 	return true;
15564a3ac931SVitaly Wool 
15571f862989SVitaly Wool out:
15581f862989SVitaly Wool 	z3fold_page_unlock(zhdr);
15591f862989SVitaly Wool 	return false;
15601f862989SVitaly Wool }
15611f862989SVitaly Wool 
15621f862989SVitaly Wool static int z3fold_page_migrate(struct address_space *mapping, struct page *newpage,
15631f862989SVitaly Wool 			       struct page *page, enum migrate_mode mode)
15641f862989SVitaly Wool {
15651f862989SVitaly Wool 	struct z3fold_header *zhdr, *new_zhdr;
15661f862989SVitaly Wool 	struct z3fold_pool *pool;
15671f862989SVitaly Wool 	struct address_space *new_mapping;
15681f862989SVitaly Wool 
15691f862989SVitaly Wool 	VM_BUG_ON_PAGE(!PageMovable(page), page);
15701f862989SVitaly Wool 	VM_BUG_ON_PAGE(!PageIsolated(page), page);
1571dcf5aedbSVitaly Wool 	VM_BUG_ON_PAGE(!test_bit(PAGE_CLAIMED, &page->private), page);
1572810481a2SHenry Burns 	VM_BUG_ON_PAGE(!PageLocked(newpage), newpage);
15731f862989SVitaly Wool 
15741f862989SVitaly Wool 	zhdr = page_address(page);
15751f862989SVitaly Wool 	pool = zhdr_to_pool(zhdr);
15761f862989SVitaly Wool 
1577dcf5aedbSVitaly Wool 	if (!z3fold_page_trylock(zhdr))
15781f862989SVitaly Wool 		return -EAGAIN;
15794a3ac931SVitaly Wool 	if (zhdr->mapped_count != 0 || zhdr->foreign_handles != 0) {
15801f862989SVitaly Wool 		z3fold_page_unlock(zhdr);
1581dcf5aedbSVitaly Wool 		clear_bit(PAGE_CLAIMED, &page->private);
15821f862989SVitaly Wool 		return -EBUSY;
15831f862989SVitaly Wool 	}
1584c92d2f38SHenry Burns 	if (work_pending(&zhdr->work)) {
1585c92d2f38SHenry Burns 		z3fold_page_unlock(zhdr);
1586c92d2f38SHenry Burns 		return -EAGAIN;
1587c92d2f38SHenry Burns 	}
15881f862989SVitaly Wool 	new_zhdr = page_address(newpage);
15891f862989SVitaly Wool 	memcpy(new_zhdr, zhdr, PAGE_SIZE);
15901f862989SVitaly Wool 	newpage->private = page->private;
15911f862989SVitaly Wool 	page->private = 0;
15921f862989SVitaly Wool 	z3fold_page_unlock(zhdr);
15931f862989SVitaly Wool 	spin_lock_init(&new_zhdr->page_lock);
1594c92d2f38SHenry Burns 	INIT_WORK(&new_zhdr->work, compact_page_work);
1595c92d2f38SHenry Burns 	/*
1596c92d2f38SHenry Burns 	 * z3fold_page_isolate() ensures that new_zhdr->buddy is empty,
1597c92d2f38SHenry Burns 	 * so we only have to reinitialize it.
1598c92d2f38SHenry Burns 	 */
1599c92d2f38SHenry Burns 	INIT_LIST_HEAD(&new_zhdr->buddy);
16001f862989SVitaly Wool 	new_mapping = page_mapping(page);
16011f862989SVitaly Wool 	__ClearPageMovable(page);
16021f862989SVitaly Wool 
16031f862989SVitaly Wool 	get_page(newpage);
16041f862989SVitaly Wool 	z3fold_page_lock(new_zhdr);
16051f862989SVitaly Wool 	if (new_zhdr->first_chunks)
16061f862989SVitaly Wool 		encode_handle(new_zhdr, FIRST);
16071f862989SVitaly Wool 	if (new_zhdr->last_chunks)
16081f862989SVitaly Wool 		encode_handle(new_zhdr, LAST);
16091f862989SVitaly Wool 	if (new_zhdr->middle_chunks)
16101f862989SVitaly Wool 		encode_handle(new_zhdr, MIDDLE);
16111f862989SVitaly Wool 	set_bit(NEEDS_COMPACTING, &newpage->private);
16121f862989SVitaly Wool 	new_zhdr->cpu = smp_processor_id();
16131f862989SVitaly Wool 	spin_lock(&pool->lock);
16141f862989SVitaly Wool 	list_add(&newpage->lru, &pool->lru);
16151f862989SVitaly Wool 	spin_unlock(&pool->lock);
16161f862989SVitaly Wool 	__SetPageMovable(newpage, new_mapping);
16171f862989SVitaly Wool 	z3fold_page_unlock(new_zhdr);
16181f862989SVitaly Wool 
16191f862989SVitaly Wool 	queue_work_on(new_zhdr->cpu, pool->compact_wq, &new_zhdr->work);
16201f862989SVitaly Wool 
1621dcf5aedbSVitaly Wool 	clear_bit(PAGE_CLAIMED, &page->private);
16221f862989SVitaly Wool 	put_page(page);
16231f862989SVitaly Wool 	return 0;
16241f862989SVitaly Wool }
16251f862989SVitaly Wool 
16261f862989SVitaly Wool static void z3fold_page_putback(struct page *page)
16271f862989SVitaly Wool {
16281f862989SVitaly Wool 	struct z3fold_header *zhdr;
16291f862989SVitaly Wool 	struct z3fold_pool *pool;
16301f862989SVitaly Wool 
16311f862989SVitaly Wool 	zhdr = page_address(page);
16321f862989SVitaly Wool 	pool = zhdr_to_pool(zhdr);
16331f862989SVitaly Wool 
16341f862989SVitaly Wool 	z3fold_page_lock(zhdr);
16351f862989SVitaly Wool 	if (!list_empty(&zhdr->buddy))
16361f862989SVitaly Wool 		list_del_init(&zhdr->buddy);
16371f862989SVitaly Wool 	INIT_LIST_HEAD(&page->lru);
16385e36c25bSMiaohe Lin 	if (kref_put(&zhdr->refcount, release_z3fold_page_locked))
16391f862989SVitaly Wool 		return;
16401f862989SVitaly Wool 	spin_lock(&pool->lock);
16411f862989SVitaly Wool 	list_add(&page->lru, &pool->lru);
16421f862989SVitaly Wool 	spin_unlock(&pool->lock);
1643dcf5aedbSVitaly Wool 	clear_bit(PAGE_CLAIMED, &page->private);
16441f862989SVitaly Wool 	z3fold_page_unlock(zhdr);
16451f862989SVitaly Wool }
16461f862989SVitaly Wool 
16471f862989SVitaly Wool static const struct address_space_operations z3fold_aops = {
16481f862989SVitaly Wool 	.isolate_page = z3fold_page_isolate,
16491f862989SVitaly Wool 	.migratepage = z3fold_page_migrate,
16501f862989SVitaly Wool 	.putback_page = z3fold_page_putback,
16511f862989SVitaly Wool };
16521f862989SVitaly Wool 
16539a001fc1SVitaly Wool /*****************
16549a001fc1SVitaly Wool  * zpool
16559a001fc1SVitaly Wool  ****************/
16569a001fc1SVitaly Wool 
16579a001fc1SVitaly Wool static int z3fold_zpool_evict(struct z3fold_pool *pool, unsigned long handle)
16589a001fc1SVitaly Wool {
16599a001fc1SVitaly Wool 	if (pool->zpool && pool->zpool_ops && pool->zpool_ops->evict)
16609a001fc1SVitaly Wool 		return pool->zpool_ops->evict(pool->zpool, handle);
16619a001fc1SVitaly Wool 	else
16629a001fc1SVitaly Wool 		return -ENOENT;
16639a001fc1SVitaly Wool }
16649a001fc1SVitaly Wool 
16659a001fc1SVitaly Wool static const struct z3fold_ops z3fold_zpool_ops = {
16669a001fc1SVitaly Wool 	.evict =	z3fold_zpool_evict
16679a001fc1SVitaly Wool };
16689a001fc1SVitaly Wool 
16699a001fc1SVitaly Wool static void *z3fold_zpool_create(const char *name, gfp_t gfp,
16709a001fc1SVitaly Wool 			       const struct zpool_ops *zpool_ops,
16719a001fc1SVitaly Wool 			       struct zpool *zpool)
16729a001fc1SVitaly Wool {
16739a001fc1SVitaly Wool 	struct z3fold_pool *pool;
16749a001fc1SVitaly Wool 
1675d30561c5SVitaly Wool 	pool = z3fold_create_pool(name, gfp,
1676d30561c5SVitaly Wool 				zpool_ops ? &z3fold_zpool_ops : NULL);
16779a001fc1SVitaly Wool 	if (pool) {
16789a001fc1SVitaly Wool 		pool->zpool = zpool;
16799a001fc1SVitaly Wool 		pool->zpool_ops = zpool_ops;
16809a001fc1SVitaly Wool 	}
16819a001fc1SVitaly Wool 	return pool;
16829a001fc1SVitaly Wool }
16839a001fc1SVitaly Wool 
16849a001fc1SVitaly Wool static void z3fold_zpool_destroy(void *pool)
16859a001fc1SVitaly Wool {
16869a001fc1SVitaly Wool 	z3fold_destroy_pool(pool);
16879a001fc1SVitaly Wool }
16889a001fc1SVitaly Wool 
16899a001fc1SVitaly Wool static int z3fold_zpool_malloc(void *pool, size_t size, gfp_t gfp,
16909a001fc1SVitaly Wool 			unsigned long *handle)
16919a001fc1SVitaly Wool {
16929a001fc1SVitaly Wool 	return z3fold_alloc(pool, size, gfp, handle);
16939a001fc1SVitaly Wool }
16949a001fc1SVitaly Wool static void z3fold_zpool_free(void *pool, unsigned long handle)
16959a001fc1SVitaly Wool {
16969a001fc1SVitaly Wool 	z3fold_free(pool, handle);
16979a001fc1SVitaly Wool }
16989a001fc1SVitaly Wool 
16999a001fc1SVitaly Wool static int z3fold_zpool_shrink(void *pool, unsigned int pages,
17009a001fc1SVitaly Wool 			unsigned int *reclaimed)
17019a001fc1SVitaly Wool {
17029a001fc1SVitaly Wool 	unsigned int total = 0;
17039a001fc1SVitaly Wool 	int ret = -EINVAL;
17049a001fc1SVitaly Wool 
17059a001fc1SVitaly Wool 	while (total < pages) {
17069a001fc1SVitaly Wool 		ret = z3fold_reclaim_page(pool, 8);
17079a001fc1SVitaly Wool 		if (ret < 0)
17089a001fc1SVitaly Wool 			break;
17099a001fc1SVitaly Wool 		total++;
17109a001fc1SVitaly Wool 	}
17119a001fc1SVitaly Wool 
17129a001fc1SVitaly Wool 	if (reclaimed)
17139a001fc1SVitaly Wool 		*reclaimed = total;
17149a001fc1SVitaly Wool 
17159a001fc1SVitaly Wool 	return ret;
17169a001fc1SVitaly Wool }
17179a001fc1SVitaly Wool 
17189a001fc1SVitaly Wool static void *z3fold_zpool_map(void *pool, unsigned long handle,
17199a001fc1SVitaly Wool 			enum zpool_mapmode mm)
17209a001fc1SVitaly Wool {
17219a001fc1SVitaly Wool 	return z3fold_map(pool, handle);
17229a001fc1SVitaly Wool }
17239a001fc1SVitaly Wool static void z3fold_zpool_unmap(void *pool, unsigned long handle)
17249a001fc1SVitaly Wool {
17259a001fc1SVitaly Wool 	z3fold_unmap(pool, handle);
17269a001fc1SVitaly Wool }
17279a001fc1SVitaly Wool 
17289a001fc1SVitaly Wool static u64 z3fold_zpool_total_size(void *pool)
17299a001fc1SVitaly Wool {
17309a001fc1SVitaly Wool 	return z3fold_get_pool_size(pool) * PAGE_SIZE;
17319a001fc1SVitaly Wool }
17329a001fc1SVitaly Wool 
17339a001fc1SVitaly Wool static struct zpool_driver z3fold_zpool_driver = {
17349a001fc1SVitaly Wool 	.type =		"z3fold",
1735e818e820STian Tao 	.sleep_mapped = true,
17369a001fc1SVitaly Wool 	.owner =	THIS_MODULE,
17379a001fc1SVitaly Wool 	.create =	z3fold_zpool_create,
17389a001fc1SVitaly Wool 	.destroy =	z3fold_zpool_destroy,
17399a001fc1SVitaly Wool 	.malloc =	z3fold_zpool_malloc,
17409a001fc1SVitaly Wool 	.free =		z3fold_zpool_free,
17419a001fc1SVitaly Wool 	.shrink =	z3fold_zpool_shrink,
17429a001fc1SVitaly Wool 	.map =		z3fold_zpool_map,
17439a001fc1SVitaly Wool 	.unmap =	z3fold_zpool_unmap,
17449a001fc1SVitaly Wool 	.total_size =	z3fold_zpool_total_size,
17459a001fc1SVitaly Wool };
17469a001fc1SVitaly Wool 
17479a001fc1SVitaly Wool MODULE_ALIAS("zpool-z3fold");
17489a001fc1SVitaly Wool 
17499a001fc1SVitaly Wool static int __init init_z3fold(void)
17509a001fc1SVitaly Wool {
17511f862989SVitaly Wool 	int ret;
17521f862989SVitaly Wool 
1753014284a0SMiaohe Lin 	/*
1754014284a0SMiaohe Lin 	 * Make sure the z3fold header is not larger than the page size and
1755014284a0SMiaohe Lin 	 * there has remaining spaces for its buddy.
1756014284a0SMiaohe Lin 	 */
1757014284a0SMiaohe Lin 	BUILD_BUG_ON(ZHDR_SIZE_ALIGNED > PAGE_SIZE - CHUNK_SIZE);
17581f862989SVitaly Wool 	ret = z3fold_mount();
17591f862989SVitaly Wool 	if (ret)
17601f862989SVitaly Wool 		return ret;
17611f862989SVitaly Wool 
17629a001fc1SVitaly Wool 	zpool_register_driver(&z3fold_zpool_driver);
17639a001fc1SVitaly Wool 
17649a001fc1SVitaly Wool 	return 0;
17659a001fc1SVitaly Wool }
17669a001fc1SVitaly Wool 
17679a001fc1SVitaly Wool static void __exit exit_z3fold(void)
17689a001fc1SVitaly Wool {
17691f862989SVitaly Wool 	z3fold_unmount();
17709a001fc1SVitaly Wool 	zpool_unregister_driver(&z3fold_zpool_driver);
17719a001fc1SVitaly Wool }
17729a001fc1SVitaly Wool 
17739a001fc1SVitaly Wool module_init(init_z3fold);
17749a001fc1SVitaly Wool module_exit(exit_z3fold);
17759a001fc1SVitaly Wool 
17769a001fc1SVitaly Wool MODULE_LICENSE("GPL");
17779a001fc1SVitaly Wool MODULE_AUTHOR("Vitaly Wool <vitalywool@gmail.com>");
17789a001fc1SVitaly Wool MODULE_DESCRIPTION("3-Fold Allocator for Compressed Pages");
1779