xref: /linux/mm/z3fold.c (revision 943fb61dd66f475c25b1ef5dddb647070f2e89a1)
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 */
184*943fb61dSMiaohe Lin 	PAGE_MIGRATED, /* page is migrated and soon to be released */
1859a001fc1SVitaly Wool };
1869a001fc1SVitaly Wool 
1874a3ac931SVitaly Wool /*
188dcf5aedbSVitaly Wool  * handle flags, go under HANDLE_FLAG_MASK
189dcf5aedbSVitaly Wool  */
190dcf5aedbSVitaly Wool enum z3fold_handle_flags {
191dcf5aedbSVitaly Wool 	HANDLES_NOFREE = 0,
192dcf5aedbSVitaly Wool };
193dcf5aedbSVitaly Wool 
194dcf5aedbSVitaly Wool /*
1954a3ac931SVitaly Wool  * Forward declarations
1964a3ac931SVitaly Wool  */
1974a3ac931SVitaly Wool static struct z3fold_header *__z3fold_alloc(struct z3fold_pool *, size_t, bool);
1984a3ac931SVitaly Wool static void compact_page_work(struct work_struct *w);
1994a3ac931SVitaly Wool 
2009a001fc1SVitaly Wool /*****************
2019a001fc1SVitaly Wool  * Helpers
2029a001fc1SVitaly Wool *****************/
2039a001fc1SVitaly Wool 
2049a001fc1SVitaly Wool /* Converts an allocation size in bytes to size in z3fold chunks */
2059a001fc1SVitaly Wool static int size_to_chunks(size_t size)
2069a001fc1SVitaly Wool {
2079a001fc1SVitaly Wool 	return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
2089a001fc1SVitaly Wool }
2099a001fc1SVitaly Wool 
2109a001fc1SVitaly Wool #define for_each_unbuddied_list(_iter, _begin) \
2119a001fc1SVitaly Wool 	for ((_iter) = (_begin); (_iter) < NCHUNKS; (_iter)++)
2129a001fc1SVitaly Wool 
213bb9f6f63SVitaly Wool static inline struct z3fold_buddy_slots *alloc_slots(struct z3fold_pool *pool,
214bb9f6f63SVitaly Wool 							gfp_t gfp)
2157c2b8baaSVitaly Wool {
216f4bad643SMiaohe Lin 	struct z3fold_buddy_slots *slots = kmem_cache_zalloc(pool->c_handle,
217f4bad643SMiaohe Lin 							     gfp);
2187c2b8baaSVitaly Wool 
2197c2b8baaSVitaly Wool 	if (slots) {
220af4798a5SQian Cai 		/* It will be freed separately in free_handle(). */
221af4798a5SQian Cai 		kmemleak_not_leak(slots);
2227c2b8baaSVitaly Wool 		slots->pool = (unsigned long)pool;
2234a3ac931SVitaly Wool 		rwlock_init(&slots->lock);
2247c2b8baaSVitaly Wool 	}
2257c2b8baaSVitaly Wool 
2267c2b8baaSVitaly Wool 	return slots;
2277c2b8baaSVitaly Wool }
2287c2b8baaSVitaly Wool 
2297c2b8baaSVitaly Wool static inline struct z3fold_pool *slots_to_pool(struct z3fold_buddy_slots *s)
2307c2b8baaSVitaly Wool {
2317c2b8baaSVitaly Wool 	return (struct z3fold_pool *)(s->pool & ~HANDLE_FLAG_MASK);
2327c2b8baaSVitaly Wool }
2337c2b8baaSVitaly Wool 
2347c2b8baaSVitaly Wool static inline struct z3fold_buddy_slots *handle_to_slots(unsigned long handle)
2357c2b8baaSVitaly Wool {
2367c2b8baaSVitaly Wool 	return (struct z3fold_buddy_slots *)(handle & ~(SLOTS_ALIGN - 1));
2377c2b8baaSVitaly Wool }
2387c2b8baaSVitaly Wool 
2394a3ac931SVitaly Wool /* Lock a z3fold page */
2404a3ac931SVitaly Wool static inline void z3fold_page_lock(struct z3fold_header *zhdr)
2414a3ac931SVitaly Wool {
2424a3ac931SVitaly Wool 	spin_lock(&zhdr->page_lock);
2434a3ac931SVitaly Wool }
2444a3ac931SVitaly Wool 
2454a3ac931SVitaly Wool /* Try to lock a z3fold page */
2464a3ac931SVitaly Wool static inline int z3fold_page_trylock(struct z3fold_header *zhdr)
2474a3ac931SVitaly Wool {
2484a3ac931SVitaly Wool 	return spin_trylock(&zhdr->page_lock);
2494a3ac931SVitaly Wool }
2504a3ac931SVitaly Wool 
2514a3ac931SVitaly Wool /* Unlock a z3fold page */
2524a3ac931SVitaly Wool static inline void z3fold_page_unlock(struct z3fold_header *zhdr)
2534a3ac931SVitaly Wool {
2544a3ac931SVitaly Wool 	spin_unlock(&zhdr->page_lock);
2554a3ac931SVitaly Wool }
2564a3ac931SVitaly Wool 
257767cc6c5SMiaohe Lin /* return locked z3fold page if it's not headless */
258767cc6c5SMiaohe Lin static inline struct z3fold_header *get_z3fold_header(unsigned long handle)
2594a3ac931SVitaly Wool {
2604a3ac931SVitaly Wool 	struct z3fold_buddy_slots *slots;
2614a3ac931SVitaly Wool 	struct z3fold_header *zhdr;
2624a3ac931SVitaly Wool 	int locked = 0;
2634a3ac931SVitaly Wool 
2644a3ac931SVitaly Wool 	if (!(handle & (1 << PAGE_HEADLESS))) {
2654a3ac931SVitaly Wool 		slots = handle_to_slots(handle);
2664a3ac931SVitaly Wool 		do {
2674a3ac931SVitaly Wool 			unsigned long addr;
2684a3ac931SVitaly Wool 
2694a3ac931SVitaly Wool 			read_lock(&slots->lock);
2704a3ac931SVitaly Wool 			addr = *(unsigned long *)handle;
2714a3ac931SVitaly Wool 			zhdr = (struct z3fold_header *)(addr & PAGE_MASK);
2724a3ac931SVitaly Wool 			locked = z3fold_page_trylock(zhdr);
2734a3ac931SVitaly Wool 			read_unlock(&slots->lock);
274*943fb61dSMiaohe Lin 			if (locked) {
275*943fb61dSMiaohe Lin 				struct page *page = virt_to_page(zhdr);
276*943fb61dSMiaohe Lin 
277*943fb61dSMiaohe Lin 				if (!test_bit(PAGE_MIGRATED, &page->private))
2784a3ac931SVitaly Wool 					break;
279*943fb61dSMiaohe Lin 				z3fold_page_unlock(zhdr);
280*943fb61dSMiaohe Lin 			}
2814a3ac931SVitaly Wool 			cpu_relax();
282767cc6c5SMiaohe Lin 		} while (true);
2834a3ac931SVitaly Wool 	} else {
2844a3ac931SVitaly Wool 		zhdr = (struct z3fold_header *)(handle & PAGE_MASK);
2854a3ac931SVitaly Wool 	}
2864a3ac931SVitaly Wool 
2874a3ac931SVitaly Wool 	return zhdr;
2884a3ac931SVitaly Wool }
2894a3ac931SVitaly Wool 
2904a3ac931SVitaly Wool static inline void put_z3fold_header(struct z3fold_header *zhdr)
2914a3ac931SVitaly Wool {
2924a3ac931SVitaly Wool 	struct page *page = virt_to_page(zhdr);
2934a3ac931SVitaly Wool 
2944a3ac931SVitaly Wool 	if (!test_bit(PAGE_HEADLESS, &page->private))
2954a3ac931SVitaly Wool 		z3fold_page_unlock(zhdr);
2964a3ac931SVitaly Wool }
2974a3ac931SVitaly Wool 
298fc548865SVitaly Wool static inline void free_handle(unsigned long handle, struct z3fold_header *zhdr)
2997c2b8baaSVitaly Wool {
3007c2b8baaSVitaly Wool 	struct z3fold_buddy_slots *slots;
3017c2b8baaSVitaly Wool 	int i;
3027c2b8baaSVitaly Wool 	bool is_free;
3037c2b8baaSVitaly Wool 
3044a3ac931SVitaly Wool 	if (WARN_ON(*(unsigned long *)handle == 0))
3054a3ac931SVitaly Wool 		return;
3064a3ac931SVitaly Wool 
3077c2b8baaSVitaly Wool 	slots = handle_to_slots(handle);
3084a3ac931SVitaly Wool 	write_lock(&slots->lock);
3094a3ac931SVitaly Wool 	*(unsigned long *)handle = 0;
310dcf5aedbSVitaly Wool 
311dcf5aedbSVitaly Wool 	if (test_bit(HANDLES_NOFREE, &slots->pool)) {
312dcf5aedbSVitaly Wool 		write_unlock(&slots->lock);
313dcf5aedbSVitaly Wool 		return; /* simple case, nothing else to do */
314dcf5aedbSVitaly Wool 	}
315dcf5aedbSVitaly Wool 
316fc548865SVitaly Wool 	if (zhdr->slots != slots)
3174a3ac931SVitaly Wool 		zhdr->foreign_handles--;
318fc548865SVitaly Wool 
3197c2b8baaSVitaly Wool 	is_free = true;
3207c2b8baaSVitaly Wool 	for (i = 0; i <= BUDDY_MASK; i++) {
3217c2b8baaSVitaly Wool 		if (slots->slot[i]) {
3227c2b8baaSVitaly Wool 			is_free = false;
3237c2b8baaSVitaly Wool 			break;
3247c2b8baaSVitaly Wool 		}
3257c2b8baaSVitaly Wool 	}
326d8f117abSUladzislau Rezki 	write_unlock(&slots->lock);
3277c2b8baaSVitaly Wool 
3287c2b8baaSVitaly Wool 	if (is_free) {
3297c2b8baaSVitaly Wool 		struct z3fold_pool *pool = slots_to_pool(slots);
3307c2b8baaSVitaly Wool 
331fc548865SVitaly Wool 		if (zhdr->slots == slots)
332fc548865SVitaly Wool 			zhdr->slots = NULL;
3337c2b8baaSVitaly Wool 		kmem_cache_free(pool->c_handle, slots);
3347c2b8baaSVitaly Wool 	}
3357c2b8baaSVitaly Wool }
3367c2b8baaSVitaly Wool 
337ea8157abSDavid Howells static int z3fold_init_fs_context(struct fs_context *fc)
3381f862989SVitaly Wool {
339ea8157abSDavid Howells 	return init_pseudo(fc, Z3FOLD_MAGIC) ? 0 : -ENOMEM;
3401f862989SVitaly Wool }
3411f862989SVitaly Wool 
3421f862989SVitaly Wool static struct file_system_type z3fold_fs = {
3431f862989SVitaly Wool 	.name		= "z3fold",
344ea8157abSDavid Howells 	.init_fs_context = z3fold_init_fs_context,
3451f862989SVitaly Wool 	.kill_sb	= kill_anon_super,
3461f862989SVitaly Wool };
3471f862989SVitaly Wool 
3481f862989SVitaly Wool static struct vfsmount *z3fold_mnt;
349dc3a1f30SMiaohe Lin static int __init z3fold_mount(void)
3501f862989SVitaly Wool {
3511f862989SVitaly Wool 	int ret = 0;
3521f862989SVitaly Wool 
3531f862989SVitaly Wool 	z3fold_mnt = kern_mount(&z3fold_fs);
3541f862989SVitaly Wool 	if (IS_ERR(z3fold_mnt))
3551f862989SVitaly Wool 		ret = PTR_ERR(z3fold_mnt);
3561f862989SVitaly Wool 
3571f862989SVitaly Wool 	return ret;
3581f862989SVitaly Wool }
3591f862989SVitaly Wool 
3601f862989SVitaly Wool static void z3fold_unmount(void)
3611f862989SVitaly Wool {
3621f862989SVitaly Wool 	kern_unmount(z3fold_mnt);
3631f862989SVitaly Wool }
3641f862989SVitaly Wool 
3651f862989SVitaly Wool static const struct address_space_operations z3fold_aops;
3661f862989SVitaly Wool static int z3fold_register_migration(struct z3fold_pool *pool)
3671f862989SVitaly Wool {
3681f862989SVitaly Wool 	pool->inode = alloc_anon_inode(z3fold_mnt->mnt_sb);
3691f862989SVitaly Wool 	if (IS_ERR(pool->inode)) {
3701f862989SVitaly Wool 		pool->inode = NULL;
3711f862989SVitaly Wool 		return 1;
3721f862989SVitaly Wool 	}
3731f862989SVitaly Wool 
3741f862989SVitaly Wool 	pool->inode->i_mapping->private_data = pool;
3751f862989SVitaly Wool 	pool->inode->i_mapping->a_ops = &z3fold_aops;
3761f862989SVitaly Wool 	return 0;
3771f862989SVitaly Wool }
3781f862989SVitaly Wool 
3791f862989SVitaly Wool static void z3fold_unregister_migration(struct z3fold_pool *pool)
3801f862989SVitaly Wool {
3811f862989SVitaly Wool 	if (pool->inode)
3821f862989SVitaly Wool 		iput(pool->inode);
3831f862989SVitaly Wool }
3841f862989SVitaly Wool 
3859a001fc1SVitaly Wool /* Initializes the z3fold header of a newly allocated z3fold page */
38663398413SVitaly Wool static struct z3fold_header *init_z3fold_page(struct page *page, bool headless,
387bb9f6f63SVitaly Wool 					struct z3fold_pool *pool, gfp_t gfp)
3889a001fc1SVitaly Wool {
3899a001fc1SVitaly Wool 	struct z3fold_header *zhdr = page_address(page);
39063398413SVitaly Wool 	struct z3fold_buddy_slots *slots;
3919a001fc1SVitaly Wool 
3929a001fc1SVitaly Wool 	INIT_LIST_HEAD(&page->lru);
3939a001fc1SVitaly Wool 	clear_bit(PAGE_HEADLESS, &page->private);
3949a001fc1SVitaly Wool 	clear_bit(MIDDLE_CHUNK_MAPPED, &page->private);
395d30561c5SVitaly Wool 	clear_bit(NEEDS_COMPACTING, &page->private);
396d30561c5SVitaly Wool 	clear_bit(PAGE_STALE, &page->private);
397ca0246bbSVitaly Wool 	clear_bit(PAGE_CLAIMED, &page->private);
398*943fb61dSMiaohe Lin 	clear_bit(PAGE_MIGRATED, &page->private);
39963398413SVitaly Wool 	if (headless)
40063398413SVitaly Wool 		return zhdr;
40163398413SVitaly Wool 
40263398413SVitaly Wool 	slots = alloc_slots(pool, gfp);
40363398413SVitaly Wool 	if (!slots)
40463398413SVitaly Wool 		return NULL;
4059a001fc1SVitaly Wool 
406c457cd96SMiaohe Lin 	memset(zhdr, 0, sizeof(*zhdr));
4072f1e5e4dSVitaly Wool 	spin_lock_init(&zhdr->page_lock);
4085a27aa82SVitaly Wool 	kref_init(&zhdr->refcount);
409d30561c5SVitaly Wool 	zhdr->cpu = -1;
4107c2b8baaSVitaly Wool 	zhdr->slots = slots;
411bb9a374dSVitaly Wool 	zhdr->pool = pool;
4129a001fc1SVitaly Wool 	INIT_LIST_HEAD(&zhdr->buddy);
413d30561c5SVitaly Wool 	INIT_WORK(&zhdr->work, compact_page_work);
4149a001fc1SVitaly Wool 	return zhdr;
4159a001fc1SVitaly Wool }
4169a001fc1SVitaly Wool 
4179a001fc1SVitaly Wool /* Resets the struct page fields and frees the page */
4181f862989SVitaly Wool static void free_z3fold_page(struct page *page, bool headless)
4199a001fc1SVitaly Wool {
4201f862989SVitaly Wool 	if (!headless) {
4211f862989SVitaly Wool 		lock_page(page);
4221f862989SVitaly Wool 		__ClearPageMovable(page);
4231f862989SVitaly Wool 		unlock_page(page);
4241f862989SVitaly Wool 	}
4255a27aa82SVitaly Wool 	__free_page(page);
4265a27aa82SVitaly Wool }
4275a27aa82SVitaly Wool 
4287c2b8baaSVitaly Wool /* Helper function to build the index */
4297c2b8baaSVitaly Wool static inline int __idx(struct z3fold_header *zhdr, enum buddy bud)
4307c2b8baaSVitaly Wool {
4317c2b8baaSVitaly Wool 	return (bud + zhdr->first_num) & BUDDY_MASK;
4327c2b8baaSVitaly Wool }
4337c2b8baaSVitaly Wool 
4349a001fc1SVitaly Wool /*
4359a001fc1SVitaly Wool  * Encodes the handle of a particular buddy within a z3fold page
4369a001fc1SVitaly Wool  * Pool lock should be held as this function accesses first_num
4379a001fc1SVitaly Wool  */
4383f9d2b57SVitaly Wool static unsigned long __encode_handle(struct z3fold_header *zhdr,
4393f9d2b57SVitaly Wool 				struct z3fold_buddy_slots *slots,
4403f9d2b57SVitaly Wool 				enum buddy bud)
4419a001fc1SVitaly Wool {
4427c2b8baaSVitaly Wool 	unsigned long h = (unsigned long)zhdr;
4437c2b8baaSVitaly Wool 	int idx = 0;
4449a001fc1SVitaly Wool 
4457c2b8baaSVitaly Wool 	/*
4467c2b8baaSVitaly Wool 	 * For a headless page, its handle is its pointer with the extra
4477c2b8baaSVitaly Wool 	 * PAGE_HEADLESS bit set
4487c2b8baaSVitaly Wool 	 */
4497c2b8baaSVitaly Wool 	if (bud == HEADLESS)
4507c2b8baaSVitaly Wool 		return h | (1 << PAGE_HEADLESS);
4517c2b8baaSVitaly Wool 
4527c2b8baaSVitaly Wool 	/* otherwise, return pointer to encoded handle */
4537c2b8baaSVitaly Wool 	idx = __idx(zhdr, bud);
4547c2b8baaSVitaly Wool 	h += idx;
455ca0246bbSVitaly Wool 	if (bud == LAST)
4567c2b8baaSVitaly Wool 		h |= (zhdr->last_chunks << BUDDY_SHIFT);
4577c2b8baaSVitaly Wool 
4584a3ac931SVitaly Wool 	write_lock(&slots->lock);
4597c2b8baaSVitaly Wool 	slots->slot[idx] = h;
4604a3ac931SVitaly Wool 	write_unlock(&slots->lock);
4617c2b8baaSVitaly Wool 	return (unsigned long)&slots->slot[idx];
4629a001fc1SVitaly Wool }
4639a001fc1SVitaly Wool 
4643f9d2b57SVitaly Wool static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud)
4653f9d2b57SVitaly Wool {
4663f9d2b57SVitaly Wool 	return __encode_handle(zhdr, zhdr->slots, bud);
4673f9d2b57SVitaly Wool }
4683f9d2b57SVitaly Wool 
469ca0246bbSVitaly Wool /* only for LAST bud, returns zero otherwise */
470ca0246bbSVitaly Wool static unsigned short handle_to_chunks(unsigned long handle)
471ca0246bbSVitaly Wool {
4724a3ac931SVitaly Wool 	struct z3fold_buddy_slots *slots = handle_to_slots(handle);
4734a3ac931SVitaly Wool 	unsigned long addr;
4747c2b8baaSVitaly Wool 
4754a3ac931SVitaly Wool 	read_lock(&slots->lock);
4764a3ac931SVitaly Wool 	addr = *(unsigned long *)handle;
4774a3ac931SVitaly Wool 	read_unlock(&slots->lock);
4787c2b8baaSVitaly Wool 	return (addr & ~PAGE_MASK) >> BUDDY_SHIFT;
479ca0246bbSVitaly Wool }
480ca0246bbSVitaly Wool 
481f201ebd8Szhong jiang /*
482f201ebd8Szhong jiang  * (handle & BUDDY_MASK) < zhdr->first_num is possible in encode_handle
483f201ebd8Szhong jiang  *  but that doesn't matter. because the masking will result in the
484f201ebd8Szhong jiang  *  correct buddy number.
485f201ebd8Szhong jiang  */
4869a001fc1SVitaly Wool static enum buddy handle_to_buddy(unsigned long handle)
4879a001fc1SVitaly Wool {
4887c2b8baaSVitaly Wool 	struct z3fold_header *zhdr;
4894a3ac931SVitaly Wool 	struct z3fold_buddy_slots *slots = handle_to_slots(handle);
4907c2b8baaSVitaly Wool 	unsigned long addr;
4917c2b8baaSVitaly Wool 
4924a3ac931SVitaly Wool 	read_lock(&slots->lock);
4937c2b8baaSVitaly Wool 	WARN_ON(handle & (1 << PAGE_HEADLESS));
4947c2b8baaSVitaly Wool 	addr = *(unsigned long *)handle;
4954a3ac931SVitaly Wool 	read_unlock(&slots->lock);
4967c2b8baaSVitaly Wool 	zhdr = (struct z3fold_header *)(addr & PAGE_MASK);
4977c2b8baaSVitaly Wool 	return (addr - zhdr->first_num) & BUDDY_MASK;
4989a001fc1SVitaly Wool }
4999a001fc1SVitaly Wool 
5009050cce1SVitaly Wool static inline struct z3fold_pool *zhdr_to_pool(struct z3fold_header *zhdr)
5019050cce1SVitaly Wool {
502bb9a374dSVitaly Wool 	return zhdr->pool;
5039050cce1SVitaly Wool }
5049050cce1SVitaly Wool 
505d30561c5SVitaly Wool static void __release_z3fold_page(struct z3fold_header *zhdr, bool locked)
506d30561c5SVitaly Wool {
507d30561c5SVitaly Wool 	struct page *page = virt_to_page(zhdr);
5089050cce1SVitaly Wool 	struct z3fold_pool *pool = zhdr_to_pool(zhdr);
509d30561c5SVitaly Wool 
510d30561c5SVitaly Wool 	WARN_ON(!list_empty(&zhdr->buddy));
511d30561c5SVitaly Wool 	set_bit(PAGE_STALE, &page->private);
51235529357SVitaly Wool 	clear_bit(NEEDS_COMPACTING, &page->private);
513d30561c5SVitaly Wool 	spin_lock(&pool->lock);
514d30561c5SVitaly Wool 	if (!list_empty(&page->lru))
5151f862989SVitaly Wool 		list_del_init(&page->lru);
516d30561c5SVitaly Wool 	spin_unlock(&pool->lock);
5174a3ac931SVitaly Wool 
518d30561c5SVitaly Wool 	if (locked)
519d30561c5SVitaly Wool 		z3fold_page_unlock(zhdr);
5204a3ac931SVitaly Wool 
521d30561c5SVitaly Wool 	spin_lock(&pool->stale_lock);
522d30561c5SVitaly Wool 	list_add(&zhdr->buddy, &pool->stale);
523d30561c5SVitaly Wool 	queue_work(pool->release_wq, &pool->work);
524d30561c5SVitaly Wool 	spin_unlock(&pool->stale_lock);
5255e36c25bSMiaohe Lin 
5265e36c25bSMiaohe Lin 	atomic64_dec(&pool->pages_nr);
527d30561c5SVitaly Wool }
528d30561c5SVitaly Wool 
529d30561c5SVitaly Wool static void release_z3fold_page_locked(struct kref *ref)
530d30561c5SVitaly Wool {
531d30561c5SVitaly Wool 	struct z3fold_header *zhdr = container_of(ref, struct z3fold_header,
532d30561c5SVitaly Wool 						refcount);
533d30561c5SVitaly Wool 	WARN_ON(z3fold_page_trylock(zhdr));
534d30561c5SVitaly Wool 	__release_z3fold_page(zhdr, true);
535d30561c5SVitaly Wool }
536d30561c5SVitaly Wool 
537d30561c5SVitaly Wool static void release_z3fold_page_locked_list(struct kref *ref)
538d30561c5SVitaly Wool {
539d30561c5SVitaly Wool 	struct z3fold_header *zhdr = container_of(ref, struct z3fold_header,
540d30561c5SVitaly Wool 					       refcount);
5419050cce1SVitaly Wool 	struct z3fold_pool *pool = zhdr_to_pool(zhdr);
5424a3ac931SVitaly Wool 
5439050cce1SVitaly Wool 	spin_lock(&pool->lock);
544d30561c5SVitaly Wool 	list_del_init(&zhdr->buddy);
5459050cce1SVitaly Wool 	spin_unlock(&pool->lock);
546d30561c5SVitaly Wool 
547d30561c5SVitaly Wool 	WARN_ON(z3fold_page_trylock(zhdr));
548d30561c5SVitaly Wool 	__release_z3fold_page(zhdr, true);
549d30561c5SVitaly Wool }
550d30561c5SVitaly Wool 
551d30561c5SVitaly Wool static void free_pages_work(struct work_struct *w)
552d30561c5SVitaly Wool {
553d30561c5SVitaly Wool 	struct z3fold_pool *pool = container_of(w, struct z3fold_pool, work);
554d30561c5SVitaly Wool 
555d30561c5SVitaly Wool 	spin_lock(&pool->stale_lock);
556d30561c5SVitaly Wool 	while (!list_empty(&pool->stale)) {
557d30561c5SVitaly Wool 		struct z3fold_header *zhdr = list_first_entry(&pool->stale,
558d30561c5SVitaly Wool 						struct z3fold_header, buddy);
559d30561c5SVitaly Wool 		struct page *page = virt_to_page(zhdr);
560d30561c5SVitaly Wool 
561d30561c5SVitaly Wool 		list_del(&zhdr->buddy);
562d30561c5SVitaly Wool 		if (WARN_ON(!test_bit(PAGE_STALE, &page->private)))
563d30561c5SVitaly Wool 			continue;
564d30561c5SVitaly Wool 		spin_unlock(&pool->stale_lock);
565d30561c5SVitaly Wool 		cancel_work_sync(&zhdr->work);
5661f862989SVitaly Wool 		free_z3fold_page(page, false);
567d30561c5SVitaly Wool 		cond_resched();
568d30561c5SVitaly Wool 		spin_lock(&pool->stale_lock);
569d30561c5SVitaly Wool 	}
570d30561c5SVitaly Wool 	spin_unlock(&pool->stale_lock);
571d30561c5SVitaly Wool }
572d30561c5SVitaly Wool 
5739a001fc1SVitaly Wool /*
5749a001fc1SVitaly Wool  * Returns the number of free chunks in a z3fold page.
5759a001fc1SVitaly Wool  * NB: can't be used with HEADLESS pages.
5769a001fc1SVitaly Wool  */
5779a001fc1SVitaly Wool static int num_free_chunks(struct z3fold_header *zhdr)
5789a001fc1SVitaly Wool {
5799a001fc1SVitaly Wool 	int nfree;
5809a001fc1SVitaly Wool 	/*
5819a001fc1SVitaly Wool 	 * If there is a middle object, pick up the bigger free space
5829a001fc1SVitaly Wool 	 * either before or after it. Otherwise just subtract the number
5839a001fc1SVitaly Wool 	 * of chunks occupied by the first and the last objects.
5849a001fc1SVitaly Wool 	 */
5859a001fc1SVitaly Wool 	if (zhdr->middle_chunks != 0) {
5869a001fc1SVitaly Wool 		int nfree_before = zhdr->first_chunks ?
587ede93213SVitaly Wool 			0 : zhdr->start_middle - ZHDR_CHUNKS;
5889a001fc1SVitaly Wool 		int nfree_after = zhdr->last_chunks ?
589ede93213SVitaly Wool 			0 : TOTAL_CHUNKS -
590ede93213SVitaly Wool 				(zhdr->start_middle + zhdr->middle_chunks);
5919a001fc1SVitaly Wool 		nfree = max(nfree_before, nfree_after);
5929a001fc1SVitaly Wool 	} else
5939a001fc1SVitaly Wool 		nfree = NCHUNKS - zhdr->first_chunks - zhdr->last_chunks;
5949a001fc1SVitaly Wool 	return nfree;
5959a001fc1SVitaly Wool }
5969a001fc1SVitaly Wool 
5979050cce1SVitaly Wool /* Add to the appropriate unbuddied list */
5989050cce1SVitaly Wool static inline void add_to_unbuddied(struct z3fold_pool *pool,
5999050cce1SVitaly Wool 				struct z3fold_header *zhdr)
6009050cce1SVitaly Wool {
6019050cce1SVitaly Wool 	if (zhdr->first_chunks == 0 || zhdr->last_chunks == 0 ||
6029050cce1SVitaly Wool 			zhdr->middle_chunks == 0) {
603135f97fdSVitaly Wool 		struct list_head *unbuddied;
6049050cce1SVitaly Wool 		int freechunks = num_free_chunks(zhdr);
605135f97fdSVitaly Wool 
606135f97fdSVitaly Wool 		migrate_disable();
607135f97fdSVitaly Wool 		unbuddied = this_cpu_ptr(pool->unbuddied);
6089050cce1SVitaly Wool 		spin_lock(&pool->lock);
6099050cce1SVitaly Wool 		list_add(&zhdr->buddy, &unbuddied[freechunks]);
6109050cce1SVitaly Wool 		spin_unlock(&pool->lock);
6119050cce1SVitaly Wool 		zhdr->cpu = smp_processor_id();
612135f97fdSVitaly Wool 		migrate_enable();
6139050cce1SVitaly Wool 	}
6149050cce1SVitaly Wool }
6159050cce1SVitaly Wool 
616dcf5aedbSVitaly Wool static inline enum buddy get_free_buddy(struct z3fold_header *zhdr, int chunks)
617dcf5aedbSVitaly Wool {
618dcf5aedbSVitaly Wool 	enum buddy bud = HEADLESS;
619dcf5aedbSVitaly Wool 
620dcf5aedbSVitaly Wool 	if (zhdr->middle_chunks) {
621dcf5aedbSVitaly Wool 		if (!zhdr->first_chunks &&
622dcf5aedbSVitaly Wool 		    chunks <= zhdr->start_middle - ZHDR_CHUNKS)
623dcf5aedbSVitaly Wool 			bud = FIRST;
624dcf5aedbSVitaly Wool 		else if (!zhdr->last_chunks)
625dcf5aedbSVitaly Wool 			bud = LAST;
626dcf5aedbSVitaly Wool 	} else {
627dcf5aedbSVitaly Wool 		if (!zhdr->first_chunks)
628dcf5aedbSVitaly Wool 			bud = FIRST;
629dcf5aedbSVitaly Wool 		else if (!zhdr->last_chunks)
630dcf5aedbSVitaly Wool 			bud = LAST;
631dcf5aedbSVitaly Wool 		else
632dcf5aedbSVitaly Wool 			bud = MIDDLE;
633dcf5aedbSVitaly Wool 	}
634dcf5aedbSVitaly Wool 
635dcf5aedbSVitaly Wool 	return bud;
636dcf5aedbSVitaly Wool }
637dcf5aedbSVitaly Wool 
638ede93213SVitaly Wool static inline void *mchunk_memmove(struct z3fold_header *zhdr,
639ede93213SVitaly Wool 				unsigned short dst_chunk)
640ede93213SVitaly Wool {
641ede93213SVitaly Wool 	void *beg = zhdr;
642ede93213SVitaly Wool 	return memmove(beg + (dst_chunk << CHUNK_SHIFT),
643ede93213SVitaly Wool 		       beg + (zhdr->start_middle << CHUNK_SHIFT),
644ede93213SVitaly Wool 		       zhdr->middle_chunks << CHUNK_SHIFT);
645ede93213SVitaly Wool }
646ede93213SVitaly Wool 
6474a3ac931SVitaly Wool static inline bool buddy_single(struct z3fold_header *zhdr)
6484a3ac931SVitaly Wool {
6494a3ac931SVitaly Wool 	return !((zhdr->first_chunks && zhdr->middle_chunks) ||
6504a3ac931SVitaly Wool 			(zhdr->first_chunks && zhdr->last_chunks) ||
6514a3ac931SVitaly Wool 			(zhdr->middle_chunks && zhdr->last_chunks));
6524a3ac931SVitaly Wool }
6534a3ac931SVitaly Wool 
6544a3ac931SVitaly Wool static struct z3fold_header *compact_single_buddy(struct z3fold_header *zhdr)
6554a3ac931SVitaly Wool {
6564a3ac931SVitaly Wool 	struct z3fold_pool *pool = zhdr_to_pool(zhdr);
6574a3ac931SVitaly Wool 	void *p = zhdr;
6584a3ac931SVitaly Wool 	unsigned long old_handle = 0;
6594a3ac931SVitaly Wool 	size_t sz = 0;
6604a3ac931SVitaly Wool 	struct z3fold_header *new_zhdr = NULL;
6614a3ac931SVitaly Wool 	int first_idx = __idx(zhdr, FIRST);
6624a3ac931SVitaly Wool 	int middle_idx = __idx(zhdr, MIDDLE);
6634a3ac931SVitaly Wool 	int last_idx = __idx(zhdr, LAST);
6644a3ac931SVitaly Wool 	unsigned short *moved_chunks = NULL;
6654a3ac931SVitaly Wool 
6664a3ac931SVitaly Wool 	/*
6674a3ac931SVitaly Wool 	 * No need to protect slots here -- all the slots are "local" and
6684a3ac931SVitaly Wool 	 * the page lock is already taken
6694a3ac931SVitaly Wool 	 */
6704a3ac931SVitaly Wool 	if (zhdr->first_chunks && zhdr->slots->slot[first_idx]) {
6714a3ac931SVitaly Wool 		p += ZHDR_SIZE_ALIGNED;
6724a3ac931SVitaly Wool 		sz = zhdr->first_chunks << CHUNK_SHIFT;
6734a3ac931SVitaly Wool 		old_handle = (unsigned long)&zhdr->slots->slot[first_idx];
6744a3ac931SVitaly Wool 		moved_chunks = &zhdr->first_chunks;
6754a3ac931SVitaly Wool 	} else if (zhdr->middle_chunks && zhdr->slots->slot[middle_idx]) {
6764a3ac931SVitaly Wool 		p += zhdr->start_middle << CHUNK_SHIFT;
6774a3ac931SVitaly Wool 		sz = zhdr->middle_chunks << CHUNK_SHIFT;
6784a3ac931SVitaly Wool 		old_handle = (unsigned long)&zhdr->slots->slot[middle_idx];
6794a3ac931SVitaly Wool 		moved_chunks = &zhdr->middle_chunks;
6804a3ac931SVitaly Wool 	} else if (zhdr->last_chunks && zhdr->slots->slot[last_idx]) {
6814a3ac931SVitaly Wool 		p += PAGE_SIZE - (zhdr->last_chunks << CHUNK_SHIFT);
6824a3ac931SVitaly Wool 		sz = zhdr->last_chunks << CHUNK_SHIFT;
6834a3ac931SVitaly Wool 		old_handle = (unsigned long)&zhdr->slots->slot[last_idx];
6844a3ac931SVitaly Wool 		moved_chunks = &zhdr->last_chunks;
6854a3ac931SVitaly Wool 	}
6864a3ac931SVitaly Wool 
6874a3ac931SVitaly Wool 	if (sz > 0) {
6884a3ac931SVitaly Wool 		enum buddy new_bud = HEADLESS;
6894a3ac931SVitaly Wool 		short chunks = size_to_chunks(sz);
6904a3ac931SVitaly Wool 		void *q;
6914a3ac931SVitaly Wool 
6924a3ac931SVitaly Wool 		new_zhdr = __z3fold_alloc(pool, sz, false);
6934a3ac931SVitaly Wool 		if (!new_zhdr)
6944a3ac931SVitaly Wool 			return NULL;
6954a3ac931SVitaly Wool 
6964a3ac931SVitaly Wool 		if (WARN_ON(new_zhdr == zhdr))
6974a3ac931SVitaly Wool 			goto out_fail;
6984a3ac931SVitaly Wool 
699dcf5aedbSVitaly Wool 		new_bud = get_free_buddy(new_zhdr, chunks);
7004a3ac931SVitaly Wool 		q = new_zhdr;
7014a3ac931SVitaly Wool 		switch (new_bud) {
7024a3ac931SVitaly Wool 		case FIRST:
7034a3ac931SVitaly Wool 			new_zhdr->first_chunks = chunks;
7044a3ac931SVitaly Wool 			q += ZHDR_SIZE_ALIGNED;
7054a3ac931SVitaly Wool 			break;
7064a3ac931SVitaly Wool 		case MIDDLE:
7074a3ac931SVitaly Wool 			new_zhdr->middle_chunks = chunks;
7084a3ac931SVitaly Wool 			new_zhdr->start_middle =
7094a3ac931SVitaly Wool 				new_zhdr->first_chunks + ZHDR_CHUNKS;
7104a3ac931SVitaly Wool 			q += new_zhdr->start_middle << CHUNK_SHIFT;
7114a3ac931SVitaly Wool 			break;
7124a3ac931SVitaly Wool 		case LAST:
7134a3ac931SVitaly Wool 			new_zhdr->last_chunks = chunks;
7144a3ac931SVitaly Wool 			q += PAGE_SIZE - (new_zhdr->last_chunks << CHUNK_SHIFT);
7154a3ac931SVitaly Wool 			break;
7164a3ac931SVitaly Wool 		default:
7174a3ac931SVitaly Wool 			goto out_fail;
7184a3ac931SVitaly Wool 		}
7194a3ac931SVitaly Wool 		new_zhdr->foreign_handles++;
7204a3ac931SVitaly Wool 		memcpy(q, p, sz);
7214a3ac931SVitaly Wool 		write_lock(&zhdr->slots->lock);
7224a3ac931SVitaly Wool 		*(unsigned long *)old_handle = (unsigned long)new_zhdr +
7234a3ac931SVitaly Wool 			__idx(new_zhdr, new_bud);
7244a3ac931SVitaly Wool 		if (new_bud == LAST)
7254a3ac931SVitaly Wool 			*(unsigned long *)old_handle |=
7264a3ac931SVitaly Wool 					(new_zhdr->last_chunks << BUDDY_SHIFT);
7274a3ac931SVitaly Wool 		write_unlock(&zhdr->slots->lock);
7284a3ac931SVitaly Wool 		add_to_unbuddied(pool, new_zhdr);
7294a3ac931SVitaly Wool 		z3fold_page_unlock(new_zhdr);
7304a3ac931SVitaly Wool 
7314a3ac931SVitaly Wool 		*moved_chunks = 0;
7324a3ac931SVitaly Wool 	}
7334a3ac931SVitaly Wool 
7344a3ac931SVitaly Wool 	return new_zhdr;
7354a3ac931SVitaly Wool 
7364a3ac931SVitaly Wool out_fail:
7375e36c25bSMiaohe Lin 	if (new_zhdr && !kref_put(&new_zhdr->refcount, release_z3fold_page_locked)) {
7384a3ac931SVitaly Wool 		add_to_unbuddied(pool, new_zhdr);
7394a3ac931SVitaly Wool 		z3fold_page_unlock(new_zhdr);
7404a3ac931SVitaly Wool 	}
7414a3ac931SVitaly Wool 	return NULL;
7424a3ac931SVitaly Wool 
7434a3ac931SVitaly Wool }
7444a3ac931SVitaly Wool 
7451b096e5aSVitaly Wool #define BIG_CHUNK_GAP	3
7469a001fc1SVitaly Wool /* Has to be called with lock held */
7479a001fc1SVitaly Wool static int z3fold_compact_page(struct z3fold_header *zhdr)
7489a001fc1SVitaly Wool {
7499a001fc1SVitaly Wool 	struct page *page = virt_to_page(zhdr);
7509a001fc1SVitaly Wool 
751ede93213SVitaly Wool 	if (test_bit(MIDDLE_CHUNK_MAPPED, &page->private))
752ede93213SVitaly Wool 		return 0; /* can't move middle chunk, it's used */
7539a001fc1SVitaly Wool 
7541f862989SVitaly Wool 	if (unlikely(PageIsolated(page)))
7551f862989SVitaly Wool 		return 0;
7561f862989SVitaly Wool 
757ede93213SVitaly Wool 	if (zhdr->middle_chunks == 0)
758ede93213SVitaly Wool 		return 0; /* nothing to compact */
759ede93213SVitaly Wool 
760ede93213SVitaly Wool 	if (zhdr->first_chunks == 0 && zhdr->last_chunks == 0) {
761ede93213SVitaly Wool 		/* move to the beginning */
762ede93213SVitaly Wool 		mchunk_memmove(zhdr, ZHDR_CHUNKS);
7639a001fc1SVitaly Wool 		zhdr->first_chunks = zhdr->middle_chunks;
7649a001fc1SVitaly Wool 		zhdr->middle_chunks = 0;
7659a001fc1SVitaly Wool 		zhdr->start_middle = 0;
7669a001fc1SVitaly Wool 		zhdr->first_num++;
767ede93213SVitaly Wool 		return 1;
7689a001fc1SVitaly Wool 	}
7699a001fc1SVitaly Wool 
7701b096e5aSVitaly Wool 	/*
7711b096e5aSVitaly Wool 	 * moving data is expensive, so let's only do that if
7721b096e5aSVitaly Wool 	 * there's substantial gain (at least BIG_CHUNK_GAP chunks)
7731b096e5aSVitaly Wool 	 */
7741b096e5aSVitaly Wool 	if (zhdr->first_chunks != 0 && zhdr->last_chunks == 0 &&
7751b096e5aSVitaly Wool 	    zhdr->start_middle - (zhdr->first_chunks + ZHDR_CHUNKS) >=
7761b096e5aSVitaly Wool 			BIG_CHUNK_GAP) {
7771b096e5aSVitaly Wool 		mchunk_memmove(zhdr, zhdr->first_chunks + ZHDR_CHUNKS);
7781b096e5aSVitaly Wool 		zhdr->start_middle = zhdr->first_chunks + ZHDR_CHUNKS;
7791b096e5aSVitaly Wool 		return 1;
7801b096e5aSVitaly Wool 	} else if (zhdr->last_chunks != 0 && zhdr->first_chunks == 0 &&
7811b096e5aSVitaly Wool 		   TOTAL_CHUNKS - (zhdr->last_chunks + zhdr->start_middle
7821b096e5aSVitaly Wool 					+ zhdr->middle_chunks) >=
7831b096e5aSVitaly Wool 			BIG_CHUNK_GAP) {
7841b096e5aSVitaly Wool 		unsigned short new_start = TOTAL_CHUNKS - zhdr->last_chunks -
7851b096e5aSVitaly Wool 			zhdr->middle_chunks;
7861b096e5aSVitaly Wool 		mchunk_memmove(zhdr, new_start);
7871b096e5aSVitaly Wool 		zhdr->start_middle = new_start;
7881b096e5aSVitaly Wool 		return 1;
7891b096e5aSVitaly Wool 	}
7901b096e5aSVitaly Wool 
7911b096e5aSVitaly Wool 	return 0;
7921b096e5aSVitaly Wool }
7931b096e5aSVitaly Wool 
794d30561c5SVitaly Wool static void do_compact_page(struct z3fold_header *zhdr, bool locked)
795d30561c5SVitaly Wool {
7969050cce1SVitaly Wool 	struct z3fold_pool *pool = zhdr_to_pool(zhdr);
797d30561c5SVitaly Wool 	struct page *page;
798d30561c5SVitaly Wool 
799d30561c5SVitaly Wool 	page = virt_to_page(zhdr);
800d30561c5SVitaly Wool 	if (locked)
801d30561c5SVitaly Wool 		WARN_ON(z3fold_page_trylock(zhdr));
802d30561c5SVitaly Wool 	else
803d30561c5SVitaly Wool 		z3fold_page_lock(zhdr);
8045d03a661SVitaly Wool 	if (WARN_ON(!test_and_clear_bit(NEEDS_COMPACTING, &page->private))) {
805d30561c5SVitaly Wool 		z3fold_page_unlock(zhdr);
806d30561c5SVitaly Wool 		return;
807d30561c5SVitaly Wool 	}
808d30561c5SVitaly Wool 	spin_lock(&pool->lock);
809d30561c5SVitaly Wool 	list_del_init(&zhdr->buddy);
810d30561c5SVitaly Wool 	spin_unlock(&pool->lock);
811d30561c5SVitaly Wool 
8125e36c25bSMiaohe Lin 	if (kref_put(&zhdr->refcount, release_z3fold_page_locked))
8135d03a661SVitaly Wool 		return;
8145d03a661SVitaly Wool 
815dcf5aedbSVitaly Wool 	if (test_bit(PAGE_STALE, &page->private) ||
816dcf5aedbSVitaly Wool 	    test_and_set_bit(PAGE_CLAIMED, &page->private)) {
8171f862989SVitaly Wool 		z3fold_page_unlock(zhdr);
8181f862989SVitaly Wool 		return;
8191f862989SVitaly Wool 	}
8201f862989SVitaly Wool 
8214a3ac931SVitaly Wool 	if (!zhdr->foreign_handles && buddy_single(zhdr) &&
8224a3ac931SVitaly Wool 	    zhdr->mapped_count == 0 && compact_single_buddy(zhdr)) {
8235e36c25bSMiaohe Lin 		if (!kref_put(&zhdr->refcount, release_z3fold_page_locked)) {
824dcf5aedbSVitaly Wool 			clear_bit(PAGE_CLAIMED, &page->private);
8254a3ac931SVitaly Wool 			z3fold_page_unlock(zhdr);
826dcf5aedbSVitaly Wool 		}
8274a3ac931SVitaly Wool 		return;
8284a3ac931SVitaly Wool 	}
8294a3ac931SVitaly Wool 
830d30561c5SVitaly Wool 	z3fold_compact_page(zhdr);
8319050cce1SVitaly Wool 	add_to_unbuddied(pool, zhdr);
832dcf5aedbSVitaly Wool 	clear_bit(PAGE_CLAIMED, &page->private);
833d30561c5SVitaly Wool 	z3fold_page_unlock(zhdr);
834d30561c5SVitaly Wool }
835d30561c5SVitaly Wool 
836d30561c5SVitaly Wool static void compact_page_work(struct work_struct *w)
837d30561c5SVitaly Wool {
838d30561c5SVitaly Wool 	struct z3fold_header *zhdr = container_of(w, struct z3fold_header,
839d30561c5SVitaly Wool 						work);
840d30561c5SVitaly Wool 
841d30561c5SVitaly Wool 	do_compact_page(zhdr, false);
842d30561c5SVitaly Wool }
843d30561c5SVitaly Wool 
8449050cce1SVitaly Wool /* returns _locked_ z3fold page header or NULL */
8459050cce1SVitaly Wool static inline struct z3fold_header *__z3fold_alloc(struct z3fold_pool *pool,
8469050cce1SVitaly Wool 						size_t size, bool can_sleep)
8479050cce1SVitaly Wool {
8489050cce1SVitaly Wool 	struct z3fold_header *zhdr = NULL;
8499050cce1SVitaly Wool 	struct page *page;
8509050cce1SVitaly Wool 	struct list_head *unbuddied;
8519050cce1SVitaly Wool 	int chunks = size_to_chunks(size), i;
8529050cce1SVitaly Wool 
8539050cce1SVitaly Wool lookup:
854135f97fdSVitaly Wool 	migrate_disable();
8559050cce1SVitaly Wool 	/* First, try to find an unbuddied z3fold page. */
856135f97fdSVitaly Wool 	unbuddied = this_cpu_ptr(pool->unbuddied);
8579050cce1SVitaly Wool 	for_each_unbuddied_list(i, chunks) {
8589050cce1SVitaly Wool 		struct list_head *l = &unbuddied[i];
8599050cce1SVitaly Wool 
8609050cce1SVitaly Wool 		zhdr = list_first_entry_or_null(READ_ONCE(l),
8619050cce1SVitaly Wool 					struct z3fold_header, buddy);
8629050cce1SVitaly Wool 
8639050cce1SVitaly Wool 		if (!zhdr)
8649050cce1SVitaly Wool 			continue;
8659050cce1SVitaly Wool 
8669050cce1SVitaly Wool 		/* Re-check under lock. */
8679050cce1SVitaly Wool 		spin_lock(&pool->lock);
8689050cce1SVitaly Wool 		if (unlikely(zhdr != list_first_entry(READ_ONCE(l),
8699050cce1SVitaly Wool 						struct z3fold_header, buddy)) ||
8709050cce1SVitaly Wool 		    !z3fold_page_trylock(zhdr)) {
8719050cce1SVitaly Wool 			spin_unlock(&pool->lock);
8729050cce1SVitaly Wool 			zhdr = NULL;
873135f97fdSVitaly Wool 			migrate_enable();
8749050cce1SVitaly Wool 			if (can_sleep)
8759050cce1SVitaly Wool 				cond_resched();
8769050cce1SVitaly Wool 			goto lookup;
8779050cce1SVitaly Wool 		}
8789050cce1SVitaly Wool 		list_del_init(&zhdr->buddy);
8799050cce1SVitaly Wool 		zhdr->cpu = -1;
8809050cce1SVitaly Wool 		spin_unlock(&pool->lock);
8819050cce1SVitaly Wool 
8829050cce1SVitaly Wool 		page = virt_to_page(zhdr);
8834a3ac931SVitaly Wool 		if (test_bit(NEEDS_COMPACTING, &page->private) ||
8844a3ac931SVitaly Wool 		    test_bit(PAGE_CLAIMED, &page->private)) {
8859050cce1SVitaly Wool 			z3fold_page_unlock(zhdr);
8869050cce1SVitaly Wool 			zhdr = NULL;
887135f97fdSVitaly Wool 			migrate_enable();
8889050cce1SVitaly Wool 			if (can_sleep)
8899050cce1SVitaly Wool 				cond_resched();
8909050cce1SVitaly Wool 			goto lookup;
8919050cce1SVitaly Wool 		}
8929050cce1SVitaly Wool 
8939050cce1SVitaly Wool 		/*
8949050cce1SVitaly Wool 		 * this page could not be removed from its unbuddied
8959050cce1SVitaly Wool 		 * list while pool lock was held, and then we've taken
8969050cce1SVitaly Wool 		 * page lock so kref_put could not be called before
8979050cce1SVitaly Wool 		 * we got here, so it's safe to just call kref_get()
8989050cce1SVitaly Wool 		 */
8999050cce1SVitaly Wool 		kref_get(&zhdr->refcount);
9009050cce1SVitaly Wool 		break;
9019050cce1SVitaly Wool 	}
902135f97fdSVitaly Wool 	migrate_enable();
9039050cce1SVitaly Wool 
904351618b2SVitaly Wool 	if (!zhdr) {
905351618b2SVitaly Wool 		int cpu;
906351618b2SVitaly Wool 
907351618b2SVitaly Wool 		/* look for _exact_ match on other cpus' lists */
908351618b2SVitaly Wool 		for_each_online_cpu(cpu) {
909351618b2SVitaly Wool 			struct list_head *l;
910351618b2SVitaly Wool 
911351618b2SVitaly Wool 			unbuddied = per_cpu_ptr(pool->unbuddied, cpu);
912351618b2SVitaly Wool 			spin_lock(&pool->lock);
913351618b2SVitaly Wool 			l = &unbuddied[chunks];
914351618b2SVitaly Wool 
915351618b2SVitaly Wool 			zhdr = list_first_entry_or_null(READ_ONCE(l),
916351618b2SVitaly Wool 						struct z3fold_header, buddy);
917351618b2SVitaly Wool 
918351618b2SVitaly Wool 			if (!zhdr || !z3fold_page_trylock(zhdr)) {
919351618b2SVitaly Wool 				spin_unlock(&pool->lock);
920351618b2SVitaly Wool 				zhdr = NULL;
921351618b2SVitaly Wool 				continue;
922351618b2SVitaly Wool 			}
923351618b2SVitaly Wool 			list_del_init(&zhdr->buddy);
924351618b2SVitaly Wool 			zhdr->cpu = -1;
925351618b2SVitaly Wool 			spin_unlock(&pool->lock);
926351618b2SVitaly Wool 
927351618b2SVitaly Wool 			page = virt_to_page(zhdr);
9284a3ac931SVitaly Wool 			if (test_bit(NEEDS_COMPACTING, &page->private) ||
9294a3ac931SVitaly Wool 			    test_bit(PAGE_CLAIMED, &page->private)) {
930351618b2SVitaly Wool 				z3fold_page_unlock(zhdr);
931351618b2SVitaly Wool 				zhdr = NULL;
932351618b2SVitaly Wool 				if (can_sleep)
933351618b2SVitaly Wool 					cond_resched();
934351618b2SVitaly Wool 				continue;
935351618b2SVitaly Wool 			}
936351618b2SVitaly Wool 			kref_get(&zhdr->refcount);
937351618b2SVitaly Wool 			break;
938351618b2SVitaly Wool 		}
939351618b2SVitaly Wool 	}
940351618b2SVitaly Wool 
9417c61c35bSMiaohe Lin 	if (zhdr && !zhdr->slots) {
9424c6bdb36SMiaohe Lin 		zhdr->slots = alloc_slots(pool, GFP_ATOMIC);
9437c61c35bSMiaohe Lin 		if (!zhdr->slots)
9447c61c35bSMiaohe Lin 			goto out_fail;
9457c61c35bSMiaohe Lin 	}
9469050cce1SVitaly Wool 	return zhdr;
9477c61c35bSMiaohe Lin 
9487c61c35bSMiaohe Lin out_fail:
9497c61c35bSMiaohe Lin 	if (!kref_put(&zhdr->refcount, release_z3fold_page_locked)) {
9507c61c35bSMiaohe Lin 		add_to_unbuddied(pool, zhdr);
9517c61c35bSMiaohe Lin 		z3fold_page_unlock(zhdr);
9527c61c35bSMiaohe Lin 	}
9537c61c35bSMiaohe Lin 	return NULL;
9549050cce1SVitaly Wool }
955d30561c5SVitaly Wool 
956d30561c5SVitaly Wool /*
957d30561c5SVitaly Wool  * API Functions
958d30561c5SVitaly Wool  */
959d30561c5SVitaly Wool 
960d30561c5SVitaly Wool /**
961d30561c5SVitaly Wool  * z3fold_create_pool() - create a new z3fold pool
962d30561c5SVitaly Wool  * @name:	pool name
963d30561c5SVitaly Wool  * @gfp:	gfp flags when allocating the z3fold pool structure
964d30561c5SVitaly Wool  * @ops:	user-defined operations for the z3fold pool
965d30561c5SVitaly Wool  *
966d30561c5SVitaly Wool  * Return: pointer to the new z3fold pool or NULL if the metadata allocation
967d30561c5SVitaly Wool  * failed.
968d30561c5SVitaly Wool  */
969d30561c5SVitaly Wool static struct z3fold_pool *z3fold_create_pool(const char *name, gfp_t gfp,
970d30561c5SVitaly Wool 		const struct z3fold_ops *ops)
971d30561c5SVitaly Wool {
972d30561c5SVitaly Wool 	struct z3fold_pool *pool = NULL;
973d30561c5SVitaly Wool 	int i, cpu;
974d30561c5SVitaly Wool 
975d30561c5SVitaly Wool 	pool = kzalloc(sizeof(struct z3fold_pool), gfp);
976d30561c5SVitaly Wool 	if (!pool)
977d30561c5SVitaly Wool 		goto out;
9787c2b8baaSVitaly Wool 	pool->c_handle = kmem_cache_create("z3fold_handle",
9797c2b8baaSVitaly Wool 				sizeof(struct z3fold_buddy_slots),
9807c2b8baaSVitaly Wool 				SLOTS_ALIGN, 0, NULL);
9817c2b8baaSVitaly Wool 	if (!pool->c_handle)
9827c2b8baaSVitaly Wool 		goto out_c;
983d30561c5SVitaly Wool 	spin_lock_init(&pool->lock);
984d30561c5SVitaly Wool 	spin_lock_init(&pool->stale_lock);
985e891f60eSMiaohe Lin 	pool->unbuddied = __alloc_percpu(sizeof(struct list_head) * NCHUNKS,
986e891f60eSMiaohe Lin 					 __alignof__(struct list_head));
9871ec6995dSXidong Wang 	if (!pool->unbuddied)
9881ec6995dSXidong Wang 		goto out_pool;
989d30561c5SVitaly Wool 	for_each_possible_cpu(cpu) {
990d30561c5SVitaly Wool 		struct list_head *unbuddied =
991d30561c5SVitaly Wool 				per_cpu_ptr(pool->unbuddied, cpu);
992d30561c5SVitaly Wool 		for_each_unbuddied_list(i, 0)
993d30561c5SVitaly Wool 			INIT_LIST_HEAD(&unbuddied[i]);
994d30561c5SVitaly Wool 	}
995d30561c5SVitaly Wool 	INIT_LIST_HEAD(&pool->lru);
996d30561c5SVitaly Wool 	INIT_LIST_HEAD(&pool->stale);
997d30561c5SVitaly Wool 	atomic64_set(&pool->pages_nr, 0);
998d30561c5SVitaly Wool 	pool->name = name;
999d30561c5SVitaly Wool 	pool->compact_wq = create_singlethread_workqueue(pool->name);
1000d30561c5SVitaly Wool 	if (!pool->compact_wq)
10011ec6995dSXidong Wang 		goto out_unbuddied;
1002d30561c5SVitaly Wool 	pool->release_wq = create_singlethread_workqueue(pool->name);
1003d30561c5SVitaly Wool 	if (!pool->release_wq)
1004d30561c5SVitaly Wool 		goto out_wq;
10051f862989SVitaly Wool 	if (z3fold_register_migration(pool))
10061f862989SVitaly Wool 		goto out_rwq;
1007d30561c5SVitaly Wool 	INIT_WORK(&pool->work, free_pages_work);
1008d30561c5SVitaly Wool 	pool->ops = ops;
1009d30561c5SVitaly Wool 	return pool;
1010d30561c5SVitaly Wool 
10111f862989SVitaly Wool out_rwq:
10121f862989SVitaly Wool 	destroy_workqueue(pool->release_wq);
1013d30561c5SVitaly Wool out_wq:
1014d30561c5SVitaly Wool 	destroy_workqueue(pool->compact_wq);
10151ec6995dSXidong Wang out_unbuddied:
10161ec6995dSXidong Wang 	free_percpu(pool->unbuddied);
10171ec6995dSXidong Wang out_pool:
10187c2b8baaSVitaly Wool 	kmem_cache_destroy(pool->c_handle);
10197c2b8baaSVitaly Wool out_c:
1020d30561c5SVitaly Wool 	kfree(pool);
10211ec6995dSXidong Wang out:
1022d30561c5SVitaly Wool 	return NULL;
1023d30561c5SVitaly Wool }
1024d30561c5SVitaly Wool 
1025d30561c5SVitaly Wool /**
1026d30561c5SVitaly Wool  * z3fold_destroy_pool() - destroys an existing z3fold pool
1027d30561c5SVitaly Wool  * @pool:	the z3fold pool to be destroyed
1028d30561c5SVitaly Wool  *
1029d30561c5SVitaly Wool  * The pool should be emptied before this function is called.
1030d30561c5SVitaly Wool  */
1031d30561c5SVitaly Wool static void z3fold_destroy_pool(struct z3fold_pool *pool)
1032d30561c5SVitaly Wool {
10337c2b8baaSVitaly Wool 	kmem_cache_destroy(pool->c_handle);
10346051d3bdSHenry Burns 
10356051d3bdSHenry Burns 	/*
10366051d3bdSHenry Burns 	 * We need to destroy pool->compact_wq before pool->release_wq,
10376051d3bdSHenry Burns 	 * as any pending work on pool->compact_wq will call
10386051d3bdSHenry Burns 	 * queue_work(pool->release_wq, &pool->work).
1039b997052bSHenry Burns 	 *
1040b997052bSHenry Burns 	 * There are still outstanding pages until both workqueues are drained,
1041b997052bSHenry Burns 	 * so we cannot unregister migration until then.
10426051d3bdSHenry Burns 	 */
10436051d3bdSHenry Burns 
1044d30561c5SVitaly Wool 	destroy_workqueue(pool->compact_wq);
10456051d3bdSHenry Burns 	destroy_workqueue(pool->release_wq);
1046b997052bSHenry Burns 	z3fold_unregister_migration(pool);
1047dac0d1cfSMiaohe Lin 	free_percpu(pool->unbuddied);
1048d30561c5SVitaly Wool 	kfree(pool);
1049d30561c5SVitaly Wool }
1050d30561c5SVitaly Wool 
10519a001fc1SVitaly Wool /**
10529a001fc1SVitaly Wool  * z3fold_alloc() - allocates a region of a given size
10539a001fc1SVitaly Wool  * @pool:	z3fold pool from which to allocate
10549a001fc1SVitaly Wool  * @size:	size in bytes of the desired allocation
10559a001fc1SVitaly Wool  * @gfp:	gfp flags used if the pool needs to grow
10569a001fc1SVitaly Wool  * @handle:	handle of the new allocation
10579a001fc1SVitaly Wool  *
10589a001fc1SVitaly Wool  * This function will attempt to find a free region in the pool large enough to
10599a001fc1SVitaly Wool  * satisfy the allocation request.  A search of the unbuddied lists is
10609a001fc1SVitaly Wool  * performed first. If no suitable free region is found, then a new page is
10619a001fc1SVitaly Wool  * allocated and added to the pool to satisfy the request.
10629a001fc1SVitaly Wool  *
10639a001fc1SVitaly Wool  * Return: 0 if success and handle is set, otherwise -EINVAL if the size or
10649a001fc1SVitaly Wool  * gfp arguments are invalid or -ENOMEM if the pool was unable to allocate
10659a001fc1SVitaly Wool  * a new page.
10669a001fc1SVitaly Wool  */
10679a001fc1SVitaly Wool static int z3fold_alloc(struct z3fold_pool *pool, size_t size, gfp_t gfp,
10689a001fc1SVitaly Wool 			unsigned long *handle)
10699a001fc1SVitaly Wool {
10709050cce1SVitaly Wool 	int chunks = size_to_chunks(size);
10719a001fc1SVitaly Wool 	struct z3fold_header *zhdr = NULL;
1072d30561c5SVitaly Wool 	struct page *page = NULL;
10739a001fc1SVitaly Wool 	enum buddy bud;
10748a97ea54SMatthew Wilcox 	bool can_sleep = gfpflags_allow_blocking(gfp);
10759a001fc1SVitaly Wool 
1076f4bad643SMiaohe Lin 	if (!size || (gfp & __GFP_HIGHMEM))
10779a001fc1SVitaly Wool 		return -EINVAL;
10789a001fc1SVitaly Wool 
10799a001fc1SVitaly Wool 	if (size > PAGE_SIZE)
10809a001fc1SVitaly Wool 		return -ENOSPC;
10819a001fc1SVitaly Wool 
10829a001fc1SVitaly Wool 	if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE)
10839a001fc1SVitaly Wool 		bud = HEADLESS;
10849a001fc1SVitaly Wool 	else {
10859050cce1SVitaly Wool retry:
10869050cce1SVitaly Wool 		zhdr = __z3fold_alloc(pool, size, can_sleep);
1087d30561c5SVitaly Wool 		if (zhdr) {
1088dcf5aedbSVitaly Wool 			bud = get_free_buddy(zhdr, chunks);
1089dcf5aedbSVitaly Wool 			if (bud == HEADLESS) {
10905e36c25bSMiaohe Lin 				if (!kref_put(&zhdr->refcount,
1091d30561c5SVitaly Wool 					     release_z3fold_page_locked))
1092d30561c5SVitaly Wool 					z3fold_page_unlock(zhdr);
10939a001fc1SVitaly Wool 				pr_err("No free chunks in unbuddied\n");
10949a001fc1SVitaly Wool 				WARN_ON(1);
10959050cce1SVitaly Wool 				goto retry;
10969a001fc1SVitaly Wool 			}
10979050cce1SVitaly Wool 			page = virt_to_page(zhdr);
10989a001fc1SVitaly Wool 			goto found;
10999a001fc1SVitaly Wool 		}
11009a001fc1SVitaly Wool 		bud = FIRST;
11019a001fc1SVitaly Wool 	}
11029a001fc1SVitaly Wool 
11035c9bab59SVitaly Wool 	page = alloc_page(gfp);
11049a001fc1SVitaly Wool 	if (!page)
11059a001fc1SVitaly Wool 		return -ENOMEM;
11062f1e5e4dSVitaly Wool 
110763398413SVitaly Wool 	zhdr = init_z3fold_page(page, bud == HEADLESS, pool, gfp);
11089050cce1SVitaly Wool 	if (!zhdr) {
11099050cce1SVitaly Wool 		__free_page(page);
11109050cce1SVitaly Wool 		return -ENOMEM;
11119050cce1SVitaly Wool 	}
11129050cce1SVitaly Wool 	atomic64_inc(&pool->pages_nr);
11139a001fc1SVitaly Wool 
11149a001fc1SVitaly Wool 	if (bud == HEADLESS) {
11159a001fc1SVitaly Wool 		set_bit(PAGE_HEADLESS, &page->private);
11169a001fc1SVitaly Wool 		goto headless;
11179a001fc1SVitaly Wool 	}
1118810481a2SHenry Burns 	if (can_sleep) {
1119810481a2SHenry Burns 		lock_page(page);
11201f862989SVitaly Wool 		__SetPageMovable(page, pool->inode->i_mapping);
1121810481a2SHenry Burns 		unlock_page(page);
1122810481a2SHenry Burns 	} else {
11232c0f3514SMiaohe Lin 		WARN_ON(!trylock_page(page));
1124810481a2SHenry Burns 		__SetPageMovable(page, pool->inode->i_mapping);
1125810481a2SHenry Burns 		unlock_page(page);
1126810481a2SHenry Burns 	}
11272f1e5e4dSVitaly Wool 	z3fold_page_lock(zhdr);
11289a001fc1SVitaly Wool 
11299a001fc1SVitaly Wool found:
11309a001fc1SVitaly Wool 	if (bud == FIRST)
11319a001fc1SVitaly Wool 		zhdr->first_chunks = chunks;
11329a001fc1SVitaly Wool 	else if (bud == LAST)
11339a001fc1SVitaly Wool 		zhdr->last_chunks = chunks;
11349a001fc1SVitaly Wool 	else {
11359a001fc1SVitaly Wool 		zhdr->middle_chunks = chunks;
1136ede93213SVitaly Wool 		zhdr->start_middle = zhdr->first_chunks + ZHDR_CHUNKS;
11379a001fc1SVitaly Wool 	}
11389050cce1SVitaly Wool 	add_to_unbuddied(pool, zhdr);
11399a001fc1SVitaly Wool 
11409a001fc1SVitaly Wool headless:
1141d30561c5SVitaly Wool 	spin_lock(&pool->lock);
11429a001fc1SVitaly Wool 	/* Add/move z3fold page to beginning of LRU */
11439a001fc1SVitaly Wool 	if (!list_empty(&page->lru))
11449a001fc1SVitaly Wool 		list_del(&page->lru);
11459a001fc1SVitaly Wool 
11469a001fc1SVitaly Wool 	list_add(&page->lru, &pool->lru);
11479a001fc1SVitaly Wool 
11489a001fc1SVitaly Wool 	*handle = encode_handle(zhdr, bud);
11499a001fc1SVitaly Wool 	spin_unlock(&pool->lock);
11502f1e5e4dSVitaly Wool 	if (bud != HEADLESS)
11512f1e5e4dSVitaly Wool 		z3fold_page_unlock(zhdr);
11529a001fc1SVitaly Wool 
11539a001fc1SVitaly Wool 	return 0;
11549a001fc1SVitaly Wool }
11559a001fc1SVitaly Wool 
11569a001fc1SVitaly Wool /**
11579a001fc1SVitaly Wool  * z3fold_free() - frees the allocation associated with the given handle
11589a001fc1SVitaly Wool  * @pool:	pool in which the allocation resided
11599a001fc1SVitaly Wool  * @handle:	handle associated with the allocation returned by z3fold_alloc()
11609a001fc1SVitaly Wool  *
11619a001fc1SVitaly Wool  * In the case that the z3fold page in which the allocation resides is under
1162ed0e5dcaSMiaohe Lin  * reclaim, as indicated by the PAGE_CLAIMED flag being set, this function
1163ed0e5dcaSMiaohe Lin  * only sets the first|middle|last_chunks to 0.  The page is actually freed
1164ed0e5dcaSMiaohe Lin  * once all buddies are evicted (see z3fold_reclaim_page() below).
11659a001fc1SVitaly Wool  */
11669a001fc1SVitaly Wool static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
11679a001fc1SVitaly Wool {
11689a001fc1SVitaly Wool 	struct z3fold_header *zhdr;
11699a001fc1SVitaly Wool 	struct page *page;
11709a001fc1SVitaly Wool 	enum buddy bud;
11715b6807deSVitaly Wool 	bool page_claimed;
11729a001fc1SVitaly Wool 
11734a3ac931SVitaly Wool 	zhdr = get_z3fold_header(handle);
11749a001fc1SVitaly Wool 	page = virt_to_page(zhdr);
11755b6807deSVitaly Wool 	page_claimed = test_and_set_bit(PAGE_CLAIMED, &page->private);
11769a001fc1SVitaly Wool 
11779a001fc1SVitaly Wool 	if (test_bit(PAGE_HEADLESS, &page->private)) {
1178ca0246bbSVitaly Wool 		/* if a headless page is under reclaim, just leave.
1179ca0246bbSVitaly Wool 		 * NB: we use test_and_set_bit for a reason: if the bit
1180ca0246bbSVitaly Wool 		 * has not been set before, we release this page
1181ca0246bbSVitaly Wool 		 * immediately so we don't care about its value any more.
1182ca0246bbSVitaly Wool 		 */
11835b6807deSVitaly Wool 		if (!page_claimed) {
1184ca0246bbSVitaly Wool 			spin_lock(&pool->lock);
1185ca0246bbSVitaly Wool 			list_del(&page->lru);
1186ca0246bbSVitaly Wool 			spin_unlock(&pool->lock);
11874a3ac931SVitaly Wool 			put_z3fold_header(zhdr);
11881f862989SVitaly Wool 			free_z3fold_page(page, true);
1189ca0246bbSVitaly Wool 			atomic64_dec(&pool->pages_nr);
1190ca0246bbSVitaly Wool 		}
1191ca0246bbSVitaly Wool 		return;
1192ca0246bbSVitaly Wool 	}
1193ca0246bbSVitaly Wool 
1194ca0246bbSVitaly Wool 	/* Non-headless case */
119543afc194SVitaly Wool 	bud = handle_to_buddy(handle);
11969a001fc1SVitaly Wool 
11979a001fc1SVitaly Wool 	switch (bud) {
11989a001fc1SVitaly Wool 	case FIRST:
11999a001fc1SVitaly Wool 		zhdr->first_chunks = 0;
12009a001fc1SVitaly Wool 		break;
12019a001fc1SVitaly Wool 	case MIDDLE:
12029a001fc1SVitaly Wool 		zhdr->middle_chunks = 0;
12039a001fc1SVitaly Wool 		break;
12049a001fc1SVitaly Wool 	case LAST:
12059a001fc1SVitaly Wool 		zhdr->last_chunks = 0;
12069a001fc1SVitaly Wool 		break;
12079a001fc1SVitaly Wool 	default:
12089a001fc1SVitaly Wool 		pr_err("%s: unknown bud %d\n", __func__, bud);
12099a001fc1SVitaly Wool 		WARN_ON(1);
12104a3ac931SVitaly Wool 		put_z3fold_header(zhdr);
12119a001fc1SVitaly Wool 		return;
12129a001fc1SVitaly Wool 	}
12139a001fc1SVitaly Wool 
12144a3ac931SVitaly Wool 	if (!page_claimed)
1215fc548865SVitaly Wool 		free_handle(handle, zhdr);
12165e36c25bSMiaohe Lin 	if (kref_put(&zhdr->refcount, release_z3fold_page_locked_list))
1217d30561c5SVitaly Wool 		return;
12185b6807deSVitaly Wool 	if (page_claimed) {
12195b6807deSVitaly Wool 		/* the page has not been claimed by us */
1220ed0e5dcaSMiaohe Lin 		put_z3fold_header(zhdr);
12216098d7e1SVitaly Wool 		return;
12226098d7e1SVitaly Wool 	}
1223dcf5aedbSVitaly Wool 	if (test_and_set_bit(NEEDS_COMPACTING, &page->private)) {
12245b6807deSVitaly Wool 		clear_bit(PAGE_CLAIMED, &page->private);
12254a1c3839SMiaohe Lin 		put_z3fold_header(zhdr);
1226d30561c5SVitaly Wool 		return;
1227d30561c5SVitaly Wool 	}
1228d30561c5SVitaly Wool 	if (zhdr->cpu < 0 || !cpu_online(zhdr->cpu)) {
1229d30561c5SVitaly Wool 		zhdr->cpu = -1;
12305d03a661SVitaly Wool 		kref_get(&zhdr->refcount);
12315b6807deSVitaly Wool 		clear_bit(PAGE_CLAIMED, &page->private);
12324a3ac931SVitaly Wool 		do_compact_page(zhdr, true);
1233d30561c5SVitaly Wool 		return;
1234d30561c5SVitaly Wool 	}
12355d03a661SVitaly Wool 	kref_get(&zhdr->refcount);
12365b6807deSVitaly Wool 	clear_bit(PAGE_CLAIMED, &page->private);
12374a3ac931SVitaly Wool 	queue_work_on(zhdr->cpu, pool->compact_wq, &zhdr->work);
12384a3ac931SVitaly Wool 	put_z3fold_header(zhdr);
12399a001fc1SVitaly Wool }
12409a001fc1SVitaly Wool 
12419a001fc1SVitaly Wool /**
12429a001fc1SVitaly Wool  * z3fold_reclaim_page() - evicts allocations from a pool page and frees it
12439a001fc1SVitaly Wool  * @pool:	pool from which a page will attempt to be evicted
1244f144c390SMike Rapoport  * @retries:	number of pages on the LRU list for which eviction will
12459a001fc1SVitaly Wool  *		be attempted before failing
12469a001fc1SVitaly Wool  *
12479a001fc1SVitaly Wool  * z3fold reclaim is different from normal system reclaim in that it is done
12489a001fc1SVitaly Wool  * from the bottom, up. This is because only the bottom layer, z3fold, has
12499a001fc1SVitaly Wool  * information on how the allocations are organized within each z3fold page.
12509a001fc1SVitaly Wool  * This has the potential to create interesting locking situations between
12519a001fc1SVitaly Wool  * z3fold and the user, however.
12529a001fc1SVitaly Wool  *
12539a001fc1SVitaly Wool  * To avoid these, this is how z3fold_reclaim_page() should be called:
1254f144c390SMike Rapoport  *
12559a001fc1SVitaly Wool  * The user detects a page should be reclaimed and calls z3fold_reclaim_page().
12569a001fc1SVitaly Wool  * z3fold_reclaim_page() will remove a z3fold page from the pool LRU list and
12579a001fc1SVitaly Wool  * call the user-defined eviction handler with the pool and handle as
12589a001fc1SVitaly Wool  * arguments.
12599a001fc1SVitaly Wool  *
12609a001fc1SVitaly Wool  * If the handle can not be evicted, the eviction handler should return
12619a001fc1SVitaly Wool  * non-zero. z3fold_reclaim_page() will add the z3fold page back to the
12629a001fc1SVitaly Wool  * appropriate list and try the next z3fold page on the LRU up to
12639a001fc1SVitaly Wool  * a user defined number of retries.
12649a001fc1SVitaly Wool  *
12659a001fc1SVitaly Wool  * If the handle is successfully evicted, the eviction handler should
12669a001fc1SVitaly Wool  * return 0 _and_ should have called z3fold_free() on the handle. z3fold_free()
12679a001fc1SVitaly Wool  * contains logic to delay freeing the page if the page is under reclaim,
12689a001fc1SVitaly Wool  * as indicated by the setting of the PG_reclaim flag on the underlying page.
12699a001fc1SVitaly Wool  *
12709a001fc1SVitaly Wool  * If all buddies in the z3fold page are successfully evicted, then the
12719a001fc1SVitaly Wool  * z3fold page can be freed.
12729a001fc1SVitaly Wool  *
12739a001fc1SVitaly Wool  * Returns: 0 if page is successfully freed, otherwise -EINVAL if there are
12749a001fc1SVitaly Wool  * no pages to evict or an eviction handler is not registered, -EAGAIN if
12759a001fc1SVitaly Wool  * the retry limit was hit.
12769a001fc1SVitaly Wool  */
12779a001fc1SVitaly Wool static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
12789a001fc1SVitaly Wool {
12794a3ac931SVitaly Wool 	int i, ret = -1;
1280d30561c5SVitaly Wool 	struct z3fold_header *zhdr = NULL;
1281d30561c5SVitaly Wool 	struct page *page = NULL;
1282d30561c5SVitaly Wool 	struct list_head *pos;
12839a001fc1SVitaly Wool 	unsigned long first_handle = 0, middle_handle = 0, last_handle = 0;
1284dcf5aedbSVitaly Wool 	struct z3fold_buddy_slots slots __attribute__((aligned(SLOTS_ALIGN)));
1285dcf5aedbSVitaly Wool 
1286dcf5aedbSVitaly Wool 	rwlock_init(&slots.lock);
1287dcf5aedbSVitaly Wool 	slots.pool = (unsigned long)pool | (1 << HANDLES_NOFREE);
12889a001fc1SVitaly Wool 
12899a001fc1SVitaly Wool 	spin_lock(&pool->lock);
12902f1e5e4dSVitaly Wool 	if (!pool->ops || !pool->ops->evict || retries == 0) {
12919a001fc1SVitaly Wool 		spin_unlock(&pool->lock);
12929a001fc1SVitaly Wool 		return -EINVAL;
12939a001fc1SVitaly Wool 	}
12949a001fc1SVitaly Wool 	for (i = 0; i < retries; i++) {
12952f1e5e4dSVitaly Wool 		if (list_empty(&pool->lru)) {
12962f1e5e4dSVitaly Wool 			spin_unlock(&pool->lock);
12972f1e5e4dSVitaly Wool 			return -EINVAL;
12982f1e5e4dSVitaly Wool 		}
1299d30561c5SVitaly Wool 		list_for_each_prev(pos, &pool->lru) {
1300d30561c5SVitaly Wool 			page = list_entry(pos, struct page, lru);
1301ca0246bbSVitaly Wool 
13023f9d2b57SVitaly Wool 			zhdr = page_address(page);
13036d679578SThomas Hebb 			if (test_bit(PAGE_HEADLESS, &page->private)) {
13046d679578SThomas Hebb 				/*
13056d679578SThomas Hebb 				 * For non-headless pages, we wait to do this
13066d679578SThomas Hebb 				 * until we have the page lock to avoid racing
13076d679578SThomas Hebb 				 * with __z3fold_alloc(). Headless pages don't
13086d679578SThomas Hebb 				 * have a lock (and __z3fold_alloc() will never
13096d679578SThomas Hebb 				 * see them), but we still need to test and set
13106d679578SThomas Hebb 				 * PAGE_CLAIMED to avoid racing with
13116d679578SThomas Hebb 				 * z3fold_free(), so just do it now before
13126d679578SThomas Hebb 				 * leaving the loop.
13136d679578SThomas Hebb 				 */
13146d679578SThomas Hebb 				if (test_and_set_bit(PAGE_CLAIMED, &page->private))
13156d679578SThomas Hebb 					continue;
13166d679578SThomas Hebb 
1317ca0246bbSVitaly Wool 				break;
13186d679578SThomas Hebb 			}
1319ca0246bbSVitaly Wool 
1320ca0246bbSVitaly Wool 			if (!z3fold_page_trylock(zhdr)) {
1321ca0246bbSVitaly Wool 				zhdr = NULL;
1322d30561c5SVitaly Wool 				continue; /* can't evict at this point */
1323ca0246bbSVitaly Wool 			}
1324dcf5aedbSVitaly Wool 
1325dcf5aedbSVitaly Wool 			/* test_and_set_bit is of course atomic, but we still
1326dcf5aedbSVitaly Wool 			 * need to do it under page lock, otherwise checking
1327dcf5aedbSVitaly Wool 			 * that bit in __z3fold_alloc wouldn't make sense
1328dcf5aedbSVitaly Wool 			 */
1329dcf5aedbSVitaly Wool 			if (zhdr->foreign_handles ||
1330dcf5aedbSVitaly Wool 			    test_and_set_bit(PAGE_CLAIMED, &page->private)) {
13314a3ac931SVitaly Wool 				z3fold_page_unlock(zhdr);
13324a3ac931SVitaly Wool 				zhdr = NULL;
13334a3ac931SVitaly Wool 				continue; /* can't evict such page */
13344a3ac931SVitaly Wool 			}
1335d30561c5SVitaly Wool 			list_del_init(&zhdr->buddy);
1336d30561c5SVitaly Wool 			zhdr->cpu = -1;
133704094226SMiaohe Lin 			/* See comment in __z3fold_alloc. */
133804094226SMiaohe Lin 			kref_get(&zhdr->refcount);
13396098d7e1SVitaly Wool 			break;
1340d30561c5SVitaly Wool 		}
1341d30561c5SVitaly Wool 
1342ca0246bbSVitaly Wool 		if (!zhdr)
1343ca0246bbSVitaly Wool 			break;
1344ca0246bbSVitaly Wool 
1345d30561c5SVitaly Wool 		list_del_init(&page->lru);
13462f1e5e4dSVitaly Wool 		spin_unlock(&pool->lock);
1347d30561c5SVitaly Wool 
1348d30561c5SVitaly Wool 		if (!test_bit(PAGE_HEADLESS, &page->private)) {
13499a001fc1SVitaly Wool 			/*
13503f9d2b57SVitaly Wool 			 * We need encode the handles before unlocking, and
13513f9d2b57SVitaly Wool 			 * use our local slots structure because z3fold_free
13523f9d2b57SVitaly Wool 			 * can zero out zhdr->slots and we can't do much
13533f9d2b57SVitaly Wool 			 * about that
13549a001fc1SVitaly Wool 			 */
13559a001fc1SVitaly Wool 			first_handle = 0;
13569a001fc1SVitaly Wool 			last_handle = 0;
13579a001fc1SVitaly Wool 			middle_handle = 0;
1358dcf5aedbSVitaly Wool 			memset(slots.slot, 0, sizeof(slots.slot));
13599a001fc1SVitaly Wool 			if (zhdr->first_chunks)
1360dcf5aedbSVitaly Wool 				first_handle = __encode_handle(zhdr, &slots,
1361dcf5aedbSVitaly Wool 								FIRST);
13629a001fc1SVitaly Wool 			if (zhdr->middle_chunks)
1363dcf5aedbSVitaly Wool 				middle_handle = __encode_handle(zhdr, &slots,
1364dcf5aedbSVitaly Wool 								MIDDLE);
13659a001fc1SVitaly Wool 			if (zhdr->last_chunks)
1366dcf5aedbSVitaly Wool 				last_handle = __encode_handle(zhdr, &slots,
1367dcf5aedbSVitaly Wool 								LAST);
1368d30561c5SVitaly Wool 			/*
1369d30561c5SVitaly Wool 			 * it's safe to unlock here because we hold a
1370d30561c5SVitaly Wool 			 * reference to this page
1371d30561c5SVitaly Wool 			 */
13722f1e5e4dSVitaly Wool 			z3fold_page_unlock(zhdr);
13739a001fc1SVitaly Wool 		} else {
13744a3ac931SVitaly Wool 			first_handle = encode_handle(zhdr, HEADLESS);
13759a001fc1SVitaly Wool 			last_handle = middle_handle = 0;
13762f1e5e4dSVitaly Wool 		}
13779a001fc1SVitaly Wool 		/* Issue the eviction callback(s) */
13789a001fc1SVitaly Wool 		if (middle_handle) {
13799a001fc1SVitaly Wool 			ret = pool->ops->evict(pool, middle_handle);
13809a001fc1SVitaly Wool 			if (ret)
13819a001fc1SVitaly Wool 				goto next;
13829a001fc1SVitaly Wool 		}
13839a001fc1SVitaly Wool 		if (first_handle) {
13849a001fc1SVitaly Wool 			ret = pool->ops->evict(pool, first_handle);
13859a001fc1SVitaly Wool 			if (ret)
13869a001fc1SVitaly Wool 				goto next;
13879a001fc1SVitaly Wool 		}
13889a001fc1SVitaly Wool 		if (last_handle) {
13899a001fc1SVitaly Wool 			ret = pool->ops->evict(pool, last_handle);
13909a001fc1SVitaly Wool 			if (ret)
13919a001fc1SVitaly Wool 				goto next;
13929a001fc1SVitaly Wool 		}
13939a001fc1SVitaly Wool next:
13945a27aa82SVitaly Wool 		if (test_bit(PAGE_HEADLESS, &page->private)) {
13955a27aa82SVitaly Wool 			if (ret == 0) {
13961f862989SVitaly Wool 				free_z3fold_page(page, true);
1397ca0246bbSVitaly Wool 				atomic64_dec(&pool->pages_nr);
13989a001fc1SVitaly Wool 				return 0;
13995a27aa82SVitaly Wool 			}
14006098d7e1SVitaly Wool 			spin_lock(&pool->lock);
14016098d7e1SVitaly Wool 			list_add(&page->lru, &pool->lru);
1402d5567c9dSVitaly Wool 			spin_unlock(&pool->lock);
14033f9d2b57SVitaly Wool 			clear_bit(PAGE_CLAIMED, &page->private);
14046098d7e1SVitaly Wool 		} else {
1405dcf5aedbSVitaly Wool 			struct z3fold_buddy_slots *slots = zhdr->slots;
14066098d7e1SVitaly Wool 			z3fold_page_lock(zhdr);
14076098d7e1SVitaly Wool 			if (kref_put(&zhdr->refcount,
14086098d7e1SVitaly Wool 					release_z3fold_page_locked)) {
1409dcf5aedbSVitaly Wool 				kmem_cache_free(pool->c_handle, slots);
14105a27aa82SVitaly Wool 				return 0;
14115a27aa82SVitaly Wool 			}
14125a27aa82SVitaly Wool 			/*
14136098d7e1SVitaly Wool 			 * if we are here, the page is still not completely
14146098d7e1SVitaly Wool 			 * free. Take the global pool lock then to be able
14156098d7e1SVitaly Wool 			 * to add it back to the lru list
14165a27aa82SVitaly Wool 			 */
14176098d7e1SVitaly Wool 			spin_lock(&pool->lock);
14189a001fc1SVitaly Wool 			list_add(&page->lru, &pool->lru);
14196098d7e1SVitaly Wool 			spin_unlock(&pool->lock);
14206cf9a349SMiaohe Lin 			if (list_empty(&zhdr->buddy))
14216cf9a349SMiaohe Lin 				add_to_unbuddied(pool, zhdr);
14223f9d2b57SVitaly Wool 			clear_bit(PAGE_CLAIMED, &page->private);
14234a1c3839SMiaohe Lin 			z3fold_page_unlock(zhdr);
14246098d7e1SVitaly Wool 		}
14256098d7e1SVitaly Wool 
14266098d7e1SVitaly Wool 		/* We started off locked to we need to lock the pool back */
14276098d7e1SVitaly Wool 		spin_lock(&pool->lock);
14289a001fc1SVitaly Wool 	}
14299a001fc1SVitaly Wool 	spin_unlock(&pool->lock);
14309a001fc1SVitaly Wool 	return -EAGAIN;
14319a001fc1SVitaly Wool }
14329a001fc1SVitaly Wool 
14339a001fc1SVitaly Wool /**
14349a001fc1SVitaly Wool  * z3fold_map() - maps the allocation associated with the given handle
14359a001fc1SVitaly Wool  * @pool:	pool in which the allocation resides
14369a001fc1SVitaly Wool  * @handle:	handle associated with the allocation to be mapped
14379a001fc1SVitaly Wool  *
14389a001fc1SVitaly Wool  * Extracts the buddy number from handle and constructs the pointer to the
14399a001fc1SVitaly Wool  * correct starting chunk within the page.
14409a001fc1SVitaly Wool  *
14419a001fc1SVitaly Wool  * Returns: a pointer to the mapped allocation
14429a001fc1SVitaly Wool  */
14439a001fc1SVitaly Wool static void *z3fold_map(struct z3fold_pool *pool, unsigned long handle)
14449a001fc1SVitaly Wool {
14459a001fc1SVitaly Wool 	struct z3fold_header *zhdr;
14469a001fc1SVitaly Wool 	struct page *page;
14479a001fc1SVitaly Wool 	void *addr;
14489a001fc1SVitaly Wool 	enum buddy buddy;
14499a001fc1SVitaly Wool 
14504a3ac931SVitaly Wool 	zhdr = get_z3fold_header(handle);
14519a001fc1SVitaly Wool 	addr = zhdr;
14529a001fc1SVitaly Wool 	page = virt_to_page(zhdr);
14539a001fc1SVitaly Wool 
14549a001fc1SVitaly Wool 	if (test_bit(PAGE_HEADLESS, &page->private))
14559a001fc1SVitaly Wool 		goto out;
14569a001fc1SVitaly Wool 
14579a001fc1SVitaly Wool 	buddy = handle_to_buddy(handle);
14589a001fc1SVitaly Wool 	switch (buddy) {
14599a001fc1SVitaly Wool 	case FIRST:
14609a001fc1SVitaly Wool 		addr += ZHDR_SIZE_ALIGNED;
14619a001fc1SVitaly Wool 		break;
14629a001fc1SVitaly Wool 	case MIDDLE:
14639a001fc1SVitaly Wool 		addr += zhdr->start_middle << CHUNK_SHIFT;
14649a001fc1SVitaly Wool 		set_bit(MIDDLE_CHUNK_MAPPED, &page->private);
14659a001fc1SVitaly Wool 		break;
14669a001fc1SVitaly Wool 	case LAST:
1467ca0246bbSVitaly Wool 		addr += PAGE_SIZE - (handle_to_chunks(handle) << CHUNK_SHIFT);
14689a001fc1SVitaly Wool 		break;
14699a001fc1SVitaly Wool 	default:
14709a001fc1SVitaly Wool 		pr_err("unknown buddy id %d\n", buddy);
14719a001fc1SVitaly Wool 		WARN_ON(1);
14729a001fc1SVitaly Wool 		addr = NULL;
14739a001fc1SVitaly Wool 		break;
14749a001fc1SVitaly Wool 	}
14752f1e5e4dSVitaly Wool 
14761f862989SVitaly Wool 	if (addr)
14771f862989SVitaly Wool 		zhdr->mapped_count++;
14789a001fc1SVitaly Wool out:
14794a3ac931SVitaly Wool 	put_z3fold_header(zhdr);
14809a001fc1SVitaly Wool 	return addr;
14819a001fc1SVitaly Wool }
14829a001fc1SVitaly Wool 
14839a001fc1SVitaly Wool /**
14849a001fc1SVitaly Wool  * z3fold_unmap() - unmaps the allocation associated with the given handle
14859a001fc1SVitaly Wool  * @pool:	pool in which the allocation resides
14869a001fc1SVitaly Wool  * @handle:	handle associated with the allocation to be unmapped
14879a001fc1SVitaly Wool  */
14889a001fc1SVitaly Wool static void z3fold_unmap(struct z3fold_pool *pool, unsigned long handle)
14899a001fc1SVitaly Wool {
14909a001fc1SVitaly Wool 	struct z3fold_header *zhdr;
14919a001fc1SVitaly Wool 	struct page *page;
14929a001fc1SVitaly Wool 	enum buddy buddy;
14939a001fc1SVitaly Wool 
14944a3ac931SVitaly Wool 	zhdr = get_z3fold_header(handle);
14959a001fc1SVitaly Wool 	page = virt_to_page(zhdr);
14969a001fc1SVitaly Wool 
14972f1e5e4dSVitaly Wool 	if (test_bit(PAGE_HEADLESS, &page->private))
14989a001fc1SVitaly Wool 		return;
14999a001fc1SVitaly Wool 
15009a001fc1SVitaly Wool 	buddy = handle_to_buddy(handle);
15019a001fc1SVitaly Wool 	if (buddy == MIDDLE)
15029a001fc1SVitaly Wool 		clear_bit(MIDDLE_CHUNK_MAPPED, &page->private);
15031f862989SVitaly Wool 	zhdr->mapped_count--;
15044a3ac931SVitaly Wool 	put_z3fold_header(zhdr);
15059a001fc1SVitaly Wool }
15069a001fc1SVitaly Wool 
15079a001fc1SVitaly Wool /**
15089a001fc1SVitaly Wool  * z3fold_get_pool_size() - gets the z3fold pool size in pages
15099a001fc1SVitaly Wool  * @pool:	pool whose size is being queried
15109a001fc1SVitaly Wool  *
151112d59ae6SVitaly Wool  * Returns: size in pages of the given pool.
15129a001fc1SVitaly Wool  */
15139a001fc1SVitaly Wool static u64 z3fold_get_pool_size(struct z3fold_pool *pool)
15149a001fc1SVitaly Wool {
151512d59ae6SVitaly Wool 	return atomic64_read(&pool->pages_nr);
15169a001fc1SVitaly Wool }
15179a001fc1SVitaly Wool 
15181f862989SVitaly Wool static bool z3fold_page_isolate(struct page *page, isolate_mode_t mode)
15191f862989SVitaly Wool {
15201f862989SVitaly Wool 	struct z3fold_header *zhdr;
15211f862989SVitaly Wool 	struct z3fold_pool *pool;
15221f862989SVitaly Wool 
15231f862989SVitaly Wool 	VM_BUG_ON_PAGE(!PageMovable(page), page);
15241f862989SVitaly Wool 	VM_BUG_ON_PAGE(PageIsolated(page), page);
15251f862989SVitaly Wool 
1526dcf5aedbSVitaly Wool 	if (test_bit(PAGE_HEADLESS, &page->private))
15271f862989SVitaly Wool 		return false;
15281f862989SVitaly Wool 
15291f862989SVitaly Wool 	zhdr = page_address(page);
15301f862989SVitaly Wool 	z3fold_page_lock(zhdr);
15311f862989SVitaly Wool 	if (test_bit(NEEDS_COMPACTING, &page->private) ||
15321f862989SVitaly Wool 	    test_bit(PAGE_STALE, &page->private))
15331f862989SVitaly Wool 		goto out;
15341f862989SVitaly Wool 
15354a3ac931SVitaly Wool 	if (zhdr->mapped_count != 0 || zhdr->foreign_handles != 0)
15364a3ac931SVitaly Wool 		goto out;
15371f862989SVitaly Wool 
1538dcf5aedbSVitaly Wool 	if (test_and_set_bit(PAGE_CLAIMED, &page->private))
1539dcf5aedbSVitaly Wool 		goto out;
15404a3ac931SVitaly Wool 	pool = zhdr_to_pool(zhdr);
15414a3ac931SVitaly Wool 	spin_lock(&pool->lock);
15421f862989SVitaly Wool 	if (!list_empty(&zhdr->buddy))
15431f862989SVitaly Wool 		list_del_init(&zhdr->buddy);
15441f862989SVitaly Wool 	if (!list_empty(&page->lru))
15454a3ac931SVitaly Wool 		list_del_init(&page->lru);
15461f862989SVitaly Wool 	spin_unlock(&pool->lock);
15474a3ac931SVitaly Wool 
15484a3ac931SVitaly Wool 	kref_get(&zhdr->refcount);
15491f862989SVitaly Wool 	z3fold_page_unlock(zhdr);
15501f862989SVitaly Wool 	return true;
15514a3ac931SVitaly Wool 
15521f862989SVitaly Wool out:
15531f862989SVitaly Wool 	z3fold_page_unlock(zhdr);
15541f862989SVitaly Wool 	return false;
15551f862989SVitaly Wool }
15561f862989SVitaly Wool 
15571f862989SVitaly Wool static int z3fold_page_migrate(struct address_space *mapping, struct page *newpage,
15581f862989SVitaly Wool 			       struct page *page, enum migrate_mode mode)
15591f862989SVitaly Wool {
15601f862989SVitaly Wool 	struct z3fold_header *zhdr, *new_zhdr;
15611f862989SVitaly Wool 	struct z3fold_pool *pool;
15621f862989SVitaly Wool 	struct address_space *new_mapping;
15631f862989SVitaly Wool 
15641f862989SVitaly Wool 	VM_BUG_ON_PAGE(!PageMovable(page), page);
15651f862989SVitaly Wool 	VM_BUG_ON_PAGE(!PageIsolated(page), page);
1566dcf5aedbSVitaly Wool 	VM_BUG_ON_PAGE(!test_bit(PAGE_CLAIMED, &page->private), page);
1567810481a2SHenry Burns 	VM_BUG_ON_PAGE(!PageLocked(newpage), newpage);
15681f862989SVitaly Wool 
15691f862989SVitaly Wool 	zhdr = page_address(page);
15701f862989SVitaly Wool 	pool = zhdr_to_pool(zhdr);
15711f862989SVitaly Wool 
1572dcf5aedbSVitaly Wool 	if (!z3fold_page_trylock(zhdr))
15731f862989SVitaly Wool 		return -EAGAIN;
15744a3ac931SVitaly Wool 	if (zhdr->mapped_count != 0 || zhdr->foreign_handles != 0) {
1575dcf5aedbSVitaly Wool 		clear_bit(PAGE_CLAIMED, &page->private);
15764a1c3839SMiaohe Lin 		z3fold_page_unlock(zhdr);
15771f862989SVitaly Wool 		return -EBUSY;
15781f862989SVitaly Wool 	}
1579c92d2f38SHenry Burns 	if (work_pending(&zhdr->work)) {
1580c92d2f38SHenry Burns 		z3fold_page_unlock(zhdr);
1581c92d2f38SHenry Burns 		return -EAGAIN;
1582c92d2f38SHenry Burns 	}
15831f862989SVitaly Wool 	new_zhdr = page_address(newpage);
15841f862989SVitaly Wool 	memcpy(new_zhdr, zhdr, PAGE_SIZE);
15851f862989SVitaly Wool 	newpage->private = page->private;
1586*943fb61dSMiaohe Lin 	set_bit(PAGE_MIGRATED, &page->private);
15871f862989SVitaly Wool 	z3fold_page_unlock(zhdr);
15881f862989SVitaly Wool 	spin_lock_init(&new_zhdr->page_lock);
1589c92d2f38SHenry Burns 	INIT_WORK(&new_zhdr->work, compact_page_work);
1590c92d2f38SHenry Burns 	/*
1591c92d2f38SHenry Burns 	 * z3fold_page_isolate() ensures that new_zhdr->buddy is empty,
1592c92d2f38SHenry Burns 	 * so we only have to reinitialize it.
1593c92d2f38SHenry Burns 	 */
1594c92d2f38SHenry Burns 	INIT_LIST_HEAD(&new_zhdr->buddy);
15951f862989SVitaly Wool 	new_mapping = page_mapping(page);
15961f862989SVitaly Wool 	__ClearPageMovable(page);
15971f862989SVitaly Wool 
15981f862989SVitaly Wool 	get_page(newpage);
15991f862989SVitaly Wool 	z3fold_page_lock(new_zhdr);
16001f862989SVitaly Wool 	if (new_zhdr->first_chunks)
16011f862989SVitaly Wool 		encode_handle(new_zhdr, FIRST);
16021f862989SVitaly Wool 	if (new_zhdr->last_chunks)
16031f862989SVitaly Wool 		encode_handle(new_zhdr, LAST);
16041f862989SVitaly Wool 	if (new_zhdr->middle_chunks)
16051f862989SVitaly Wool 		encode_handle(new_zhdr, MIDDLE);
16061f862989SVitaly Wool 	set_bit(NEEDS_COMPACTING, &newpage->private);
16071f862989SVitaly Wool 	new_zhdr->cpu = smp_processor_id();
16081f862989SVitaly Wool 	spin_lock(&pool->lock);
16091f862989SVitaly Wool 	list_add(&newpage->lru, &pool->lru);
16101f862989SVitaly Wool 	spin_unlock(&pool->lock);
16111f862989SVitaly Wool 	__SetPageMovable(newpage, new_mapping);
16121f862989SVitaly Wool 	z3fold_page_unlock(new_zhdr);
16131f862989SVitaly Wool 
16141f862989SVitaly Wool 	queue_work_on(new_zhdr->cpu, pool->compact_wq, &new_zhdr->work);
16151f862989SVitaly Wool 
1616*943fb61dSMiaohe Lin 	/* PAGE_CLAIMED and PAGE_MIGRATED are cleared now. */
1617*943fb61dSMiaohe Lin 	page->private = 0;
16181f862989SVitaly Wool 	put_page(page);
16191f862989SVitaly Wool 	return 0;
16201f862989SVitaly Wool }
16211f862989SVitaly Wool 
16221f862989SVitaly Wool static void z3fold_page_putback(struct page *page)
16231f862989SVitaly Wool {
16241f862989SVitaly Wool 	struct z3fold_header *zhdr;
16251f862989SVitaly Wool 	struct z3fold_pool *pool;
16261f862989SVitaly Wool 
16271f862989SVitaly Wool 	zhdr = page_address(page);
16281f862989SVitaly Wool 	pool = zhdr_to_pool(zhdr);
16291f862989SVitaly Wool 
16301f862989SVitaly Wool 	z3fold_page_lock(zhdr);
16311f862989SVitaly Wool 	if (!list_empty(&zhdr->buddy))
16321f862989SVitaly Wool 		list_del_init(&zhdr->buddy);
16331f862989SVitaly Wool 	INIT_LIST_HEAD(&page->lru);
16345e36c25bSMiaohe Lin 	if (kref_put(&zhdr->refcount, release_z3fold_page_locked))
16351f862989SVitaly Wool 		return;
16361f862989SVitaly Wool 	spin_lock(&pool->lock);
16371f862989SVitaly Wool 	list_add(&page->lru, &pool->lru);
16381f862989SVitaly Wool 	spin_unlock(&pool->lock);
16396cf9a349SMiaohe Lin 	if (list_empty(&zhdr->buddy))
16406cf9a349SMiaohe Lin 		add_to_unbuddied(pool, zhdr);
1641dcf5aedbSVitaly Wool 	clear_bit(PAGE_CLAIMED, &page->private);
16421f862989SVitaly Wool 	z3fold_page_unlock(zhdr);
16431f862989SVitaly Wool }
16441f862989SVitaly Wool 
16451f862989SVitaly Wool static const struct address_space_operations z3fold_aops = {
16461f862989SVitaly Wool 	.isolate_page = z3fold_page_isolate,
16471f862989SVitaly Wool 	.migratepage = z3fold_page_migrate,
16481f862989SVitaly Wool 	.putback_page = z3fold_page_putback,
16491f862989SVitaly Wool };
16501f862989SVitaly Wool 
16519a001fc1SVitaly Wool /*****************
16529a001fc1SVitaly Wool  * zpool
16539a001fc1SVitaly Wool  ****************/
16549a001fc1SVitaly Wool 
16559a001fc1SVitaly Wool static int z3fold_zpool_evict(struct z3fold_pool *pool, unsigned long handle)
16569a001fc1SVitaly Wool {
16579a001fc1SVitaly Wool 	if (pool->zpool && pool->zpool_ops && pool->zpool_ops->evict)
16589a001fc1SVitaly Wool 		return pool->zpool_ops->evict(pool->zpool, handle);
16599a001fc1SVitaly Wool 	else
16609a001fc1SVitaly Wool 		return -ENOENT;
16619a001fc1SVitaly Wool }
16629a001fc1SVitaly Wool 
16639a001fc1SVitaly Wool static const struct z3fold_ops z3fold_zpool_ops = {
16649a001fc1SVitaly Wool 	.evict =	z3fold_zpool_evict
16659a001fc1SVitaly Wool };
16669a001fc1SVitaly Wool 
16679a001fc1SVitaly Wool static void *z3fold_zpool_create(const char *name, gfp_t gfp,
16689a001fc1SVitaly Wool 			       const struct zpool_ops *zpool_ops,
16699a001fc1SVitaly Wool 			       struct zpool *zpool)
16709a001fc1SVitaly Wool {
16719a001fc1SVitaly Wool 	struct z3fold_pool *pool;
16729a001fc1SVitaly Wool 
1673d30561c5SVitaly Wool 	pool = z3fold_create_pool(name, gfp,
1674d30561c5SVitaly Wool 				zpool_ops ? &z3fold_zpool_ops : NULL);
16759a001fc1SVitaly Wool 	if (pool) {
16769a001fc1SVitaly Wool 		pool->zpool = zpool;
16779a001fc1SVitaly Wool 		pool->zpool_ops = zpool_ops;
16789a001fc1SVitaly Wool 	}
16799a001fc1SVitaly Wool 	return pool;
16809a001fc1SVitaly Wool }
16819a001fc1SVitaly Wool 
16829a001fc1SVitaly Wool static void z3fold_zpool_destroy(void *pool)
16839a001fc1SVitaly Wool {
16849a001fc1SVitaly Wool 	z3fold_destroy_pool(pool);
16859a001fc1SVitaly Wool }
16869a001fc1SVitaly Wool 
16879a001fc1SVitaly Wool static int z3fold_zpool_malloc(void *pool, size_t size, gfp_t gfp,
16889a001fc1SVitaly Wool 			unsigned long *handle)
16899a001fc1SVitaly Wool {
16909a001fc1SVitaly Wool 	return z3fold_alloc(pool, size, gfp, handle);
16919a001fc1SVitaly Wool }
16929a001fc1SVitaly Wool static void z3fold_zpool_free(void *pool, unsigned long handle)
16939a001fc1SVitaly Wool {
16949a001fc1SVitaly Wool 	z3fold_free(pool, handle);
16959a001fc1SVitaly Wool }
16969a001fc1SVitaly Wool 
16979a001fc1SVitaly Wool static int z3fold_zpool_shrink(void *pool, unsigned int pages,
16989a001fc1SVitaly Wool 			unsigned int *reclaimed)
16999a001fc1SVitaly Wool {
17009a001fc1SVitaly Wool 	unsigned int total = 0;
17019a001fc1SVitaly Wool 	int ret = -EINVAL;
17029a001fc1SVitaly Wool 
17039a001fc1SVitaly Wool 	while (total < pages) {
17049a001fc1SVitaly Wool 		ret = z3fold_reclaim_page(pool, 8);
17059a001fc1SVitaly Wool 		if (ret < 0)
17069a001fc1SVitaly Wool 			break;
17079a001fc1SVitaly Wool 		total++;
17089a001fc1SVitaly Wool 	}
17099a001fc1SVitaly Wool 
17109a001fc1SVitaly Wool 	if (reclaimed)
17119a001fc1SVitaly Wool 		*reclaimed = total;
17129a001fc1SVitaly Wool 
17139a001fc1SVitaly Wool 	return ret;
17149a001fc1SVitaly Wool }
17159a001fc1SVitaly Wool 
17169a001fc1SVitaly Wool static void *z3fold_zpool_map(void *pool, unsigned long handle,
17179a001fc1SVitaly Wool 			enum zpool_mapmode mm)
17189a001fc1SVitaly Wool {
17199a001fc1SVitaly Wool 	return z3fold_map(pool, handle);
17209a001fc1SVitaly Wool }
17219a001fc1SVitaly Wool static void z3fold_zpool_unmap(void *pool, unsigned long handle)
17229a001fc1SVitaly Wool {
17239a001fc1SVitaly Wool 	z3fold_unmap(pool, handle);
17249a001fc1SVitaly Wool }
17259a001fc1SVitaly Wool 
17269a001fc1SVitaly Wool static u64 z3fold_zpool_total_size(void *pool)
17279a001fc1SVitaly Wool {
17289a001fc1SVitaly Wool 	return z3fold_get_pool_size(pool) * PAGE_SIZE;
17299a001fc1SVitaly Wool }
17309a001fc1SVitaly Wool 
17319a001fc1SVitaly Wool static struct zpool_driver z3fold_zpool_driver = {
17329a001fc1SVitaly Wool 	.type =		"z3fold",
1733e818e820STian Tao 	.sleep_mapped = true,
17349a001fc1SVitaly Wool 	.owner =	THIS_MODULE,
17359a001fc1SVitaly Wool 	.create =	z3fold_zpool_create,
17369a001fc1SVitaly Wool 	.destroy =	z3fold_zpool_destroy,
17379a001fc1SVitaly Wool 	.malloc =	z3fold_zpool_malloc,
17389a001fc1SVitaly Wool 	.free =		z3fold_zpool_free,
17399a001fc1SVitaly Wool 	.shrink =	z3fold_zpool_shrink,
17409a001fc1SVitaly Wool 	.map =		z3fold_zpool_map,
17419a001fc1SVitaly Wool 	.unmap =	z3fold_zpool_unmap,
17429a001fc1SVitaly Wool 	.total_size =	z3fold_zpool_total_size,
17439a001fc1SVitaly Wool };
17449a001fc1SVitaly Wool 
17459a001fc1SVitaly Wool MODULE_ALIAS("zpool-z3fold");
17469a001fc1SVitaly Wool 
17479a001fc1SVitaly Wool static int __init init_z3fold(void)
17489a001fc1SVitaly Wool {
17491f862989SVitaly Wool 	int ret;
17501f862989SVitaly Wool 
1751014284a0SMiaohe Lin 	/*
1752014284a0SMiaohe Lin 	 * Make sure the z3fold header is not larger than the page size and
1753014284a0SMiaohe Lin 	 * there has remaining spaces for its buddy.
1754014284a0SMiaohe Lin 	 */
1755014284a0SMiaohe Lin 	BUILD_BUG_ON(ZHDR_SIZE_ALIGNED > PAGE_SIZE - CHUNK_SIZE);
17561f862989SVitaly Wool 	ret = z3fold_mount();
17571f862989SVitaly Wool 	if (ret)
17581f862989SVitaly Wool 		return ret;
17591f862989SVitaly Wool 
17609a001fc1SVitaly Wool 	zpool_register_driver(&z3fold_zpool_driver);
17619a001fc1SVitaly Wool 
17629a001fc1SVitaly Wool 	return 0;
17639a001fc1SVitaly Wool }
17649a001fc1SVitaly Wool 
17659a001fc1SVitaly Wool static void __exit exit_z3fold(void)
17669a001fc1SVitaly Wool {
17671f862989SVitaly Wool 	z3fold_unmount();
17689a001fc1SVitaly Wool 	zpool_unregister_driver(&z3fold_zpool_driver);
17699a001fc1SVitaly Wool }
17709a001fc1SVitaly Wool 
17719a001fc1SVitaly Wool module_init(init_z3fold);
17729a001fc1SVitaly Wool module_exit(exit_z3fold);
17739a001fc1SVitaly Wool 
17749a001fc1SVitaly Wool MODULE_LICENSE("GPL");
17759a001fc1SVitaly Wool MODULE_AUTHOR("Vitaly Wool <vitalywool@gmail.com>");
17769a001fc1SVitaly Wool MODULE_DESCRIPTION("3-Fold Allocator for Compressed Pages");
1777