Blame view

mm/z3fold.c 46.8 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /*
   * z3fold.c
   *
   * Author: Vitaly Wool <vitaly.wool@konsulko.com>
   * Copyright (C) 2016, Sony Mobile Communications Inc.
   *
   * This implementation is based on zbud written by Seth Jennings.
   *
   * z3fold is an special purpose allocator for storing compressed pages. It
   * can store up to three compressed pages per page which improves the
   * compression ratio of zbud while retaining its main concepts (e. g. always
   * storing an integral number of objects per page) and simplicity.
   * It still has simple and deterministic reclaim properties that make it
   * preferable to a higher density approach (with no requirement on integral
   * number of object per page) when reclaim is used.
   *
   * As in zbud, pages are divided into "chunks".  The size of the chunks is
   * fixed at compile time and is determined by NCHUNKS_ORDER below.
   *
   * z3fold doesn't export any API and is meant to be used via zpool API.
   */
  
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  
  #include <linux/atomic.h>
d30561c56   Vitaly Wool   z3fold: use per-c...
27
  #include <linux/sched.h>
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
28
  #include <linux/cpumask.h>
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
29
30
31
  #include <linux/list.h>
  #include <linux/mm.h>
  #include <linux/module.h>
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
32
33
34
35
  #include <linux/page-flags.h>
  #include <linux/migrate.h>
  #include <linux/node.h>
  #include <linux/compaction.h>
d30561c56   Vitaly Wool   z3fold: use per-c...
36
  #include <linux/percpu.h>
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
37
  #include <linux/mount.h>
ea8157ab2   David Howells   zsfold: Convert z...
38
  #include <linux/pseudo_fs.h>
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
39
  #include <linux/fs.h>
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
40
  #include <linux/preempt.h>
d30561c56   Vitaly Wool   z3fold: use per-c...
41
  #include <linux/workqueue.h>
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
42
43
44
  #include <linux/slab.h>
  #include <linux/spinlock.h>
  #include <linux/zpool.h>
ea8157ab2   David Howells   zsfold: Convert z...
45
  #include <linux/magic.h>
af4798a5b   Qian Cai   mm/z3fold: silenc...
46
  #include <linux/kmemleak.h>
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
47

7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  /*
   * NCHUNKS_ORDER determines the internal allocation granularity, effectively
   * adjusting internal fragmentation.  It also determines the number of
   * freelists maintained in each pool. NCHUNKS_ORDER of 6 means that the
   * allocation granularity will be in chunks of size PAGE_SIZE/64. Some chunks
   * in the beginning of an allocated page are occupied by z3fold header, so
   * NCHUNKS will be calculated to 63 (or 62 in case CONFIG_DEBUG_SPINLOCK=y),
   * which shows the max number of free chunks in z3fold page, also there will
   * be 63, or 62, respectively, freelists per pool.
   */
  #define NCHUNKS_ORDER	6
  
  #define CHUNK_SHIFT	(PAGE_SHIFT - NCHUNKS_ORDER)
  #define CHUNK_SIZE	(1 << CHUNK_SHIFT)
  #define ZHDR_SIZE_ALIGNED round_up(sizeof(struct z3fold_header), CHUNK_SIZE)
  #define ZHDR_CHUNKS	(ZHDR_SIZE_ALIGNED >> CHUNK_SHIFT)
  #define TOTAL_CHUNKS	(PAGE_SIZE >> CHUNK_SHIFT)
  #define NCHUNKS		((PAGE_SIZE - ZHDR_SIZE_ALIGNED) >> CHUNK_SHIFT)
  
  #define BUDDY_MASK	(0x3)
  #define BUDDY_SHIFT	2
  #define SLOTS_ALIGN	(0x40)
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
70
71
72
  /*****************
   * Structures
  *****************/
ede93213a   Vitaly Wool   z3fold: fix heade...
73
74
75
76
77
78
79
80
81
82
  struct z3fold_pool;
  struct z3fold_ops {
  	int (*evict)(struct z3fold_pool *pool, unsigned long handle);
  };
  
  enum buddy {
  	HEADLESS = 0,
  	FIRST,
  	MIDDLE,
  	LAST,
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
83
84
85
86
87
88
89
90
91
  	BUDDIES_MAX = LAST
  };
  
  struct z3fold_buddy_slots {
  	/*
  	 * we are using BUDDY_MASK in handle_to_buddy etc. so there should
  	 * be enough slots to hold all possible variants
  	 */
  	unsigned long slot[BUDDY_MASK + 1];
b8b1d4e96   Vitaly Wool   z3fold: simplify ...
92
  	unsigned long pool; /* back link */
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
93
  	rwlock_t lock;
ede93213a   Vitaly Wool   z3fold: fix heade...
94
  };
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
95
  #define HANDLE_FLAG_MASK	(0x03)
ede93213a   Vitaly Wool   z3fold: fix heade...
96
97
  
  /*
d30561c56   Vitaly Wool   z3fold: use per-c...
98
   * struct z3fold_header - z3fold page metadata occupying first chunks of each
ede93213a   Vitaly Wool   z3fold: fix heade...
99
   *			z3fold page, except for HEADLESS pages
d30561c56   Vitaly Wool   z3fold: use per-c...
100
101
   * @buddy:		links the z3fold page into the relevant list in the
   *			pool
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
102
   * @page_lock:		per-page lock
d30561c56   Vitaly Wool   z3fold: use per-c...
103
104
   * @refcount:		reference count for the z3fold page
   * @work:		work_struct for page layout optimization
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
105
   * @slots:		pointer to the structure holding buddy slots
bb9a374df   Vitaly Wool   mm/z3fold: don't ...
106
   * @pool:		pointer to the containing pool
d30561c56   Vitaly Wool   z3fold: use per-c...
107
   * @cpu:		CPU which this page "belongs" to
ede93213a   Vitaly Wool   z3fold: fix heade...
108
109
110
111
   * @first_chunks:	the size of the first buddy in chunks, 0 if free
   * @middle_chunks:	the size of the middle buddy in chunks, 0 if free
   * @last_chunks:	the size of the last buddy in chunks, 0 if free
   * @first_num:		the starting number (for the first handle)
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
112
   * @mapped_count:	the number of objects currently mapped
ede93213a   Vitaly Wool   z3fold: fix heade...
113
114
115
   */
  struct z3fold_header {
  	struct list_head buddy;
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
116
  	spinlock_t page_lock;
5a27aa822   Vitaly Wool   z3fold: add kref ...
117
  	struct kref refcount;
d30561c56   Vitaly Wool   z3fold: use per-c...
118
  	struct work_struct work;
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
119
  	struct z3fold_buddy_slots *slots;
bb9a374df   Vitaly Wool   mm/z3fold: don't ...
120
  	struct z3fold_pool *pool;
d30561c56   Vitaly Wool   z3fold: use per-c...
121
  	short cpu;
ede93213a   Vitaly Wool   z3fold: fix heade...
122
123
124
125
126
  	unsigned short first_chunks;
  	unsigned short middle_chunks;
  	unsigned short last_chunks;
  	unsigned short start_middle;
  	unsigned short first_num:2;
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
127
  	unsigned short mapped_count:2;
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
128
  	unsigned short foreign_handles:2;
ede93213a   Vitaly Wool   z3fold: fix heade...
129
  };
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
130
131
  /**
   * struct z3fold_pool - stores metadata for each z3fold pool
d30561c56   Vitaly Wool   z3fold: use per-c...
132
133
134
135
136
137
   * @name:	pool name
   * @lock:	protects pool unbuddied/lru lists
   * @stale_lock:	protects pool stale page list
   * @unbuddied:	per-cpu array of lists tracking z3fold pages that contain 2-
   *		buddies; the list each z3fold page is added to depends on
   *		the size of its free region.
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
138
139
   * @lru:	list tracking the z3fold pages in LRU order by most recently
   *		added buddy.
d30561c56   Vitaly Wool   z3fold: use per-c...
140
   * @stale:	list of pages marked for freeing
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
141
   * @pages_nr:	number of z3fold pages in the pool.
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
142
   * @c_handle:	cache for z3fold_buddy_slots allocation
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
143
144
   * @ops:	pointer to a structure of user defined operations specified at
   *		pool creation time.
d30561c56   Vitaly Wool   z3fold: use per-c...
145
146
147
   * @compact_wq:	workqueue for page layout background optimization
   * @release_wq:	workqueue for safe page release
   * @work:	work_struct for safe page release
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
148
   * @inode:	inode for z3fold pseudo filesystem
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
149
150
151
152
153
   *
   * This structure is allocated at pool creation time and maintains metadata
   * pertaining to a particular z3fold pool.
   */
  struct z3fold_pool {
d30561c56   Vitaly Wool   z3fold: use per-c...
154
  	const char *name;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
155
  	spinlock_t lock;
d30561c56   Vitaly Wool   z3fold: use per-c...
156
157
  	spinlock_t stale_lock;
  	struct list_head *unbuddied;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
158
  	struct list_head lru;
d30561c56   Vitaly Wool   z3fold: use per-c...
159
  	struct list_head stale;
12d59ae67   Vitaly Wool   z3fold: make page...
160
  	atomic64_t pages_nr;
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
161
  	struct kmem_cache *c_handle;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
162
163
164
  	const struct z3fold_ops *ops;
  	struct zpool *zpool;
  	const struct zpool_ops *zpool_ops;
d30561c56   Vitaly Wool   z3fold: use per-c...
165
166
167
  	struct workqueue_struct *compact_wq;
  	struct workqueue_struct *release_wq;
  	struct work_struct work;
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
168
  	struct inode *inode;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
169
  };
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
170
171
172
173
  /*
   * Internal z3fold page flags
   */
  enum z3fold_page_flags {
5a27aa822   Vitaly Wool   z3fold: add kref ...
174
  	PAGE_HEADLESS = 0,
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
175
  	MIDDLE_CHUNK_MAPPED,
d30561c56   Vitaly Wool   z3fold: use per-c...
176
  	NEEDS_COMPACTING,
6098d7e13   Vitaly Wool   z3fold: fix recla...
177
  	PAGE_STALE,
ca0246bb9   Vitaly Wool   z3fold: fix possi...
178
  	PAGE_CLAIMED, /* by either reclaim or free */
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
179
  };
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
180
  /*
746d179b0   Vitaly Wool   z3fold: stricter ...
181
182
183
184
185
186
187
   * handle flags, go under HANDLE_FLAG_MASK
   */
  enum z3fold_handle_flags {
  	HANDLES_NOFREE = 0,
  };
  
  /*
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
188
189
190
191
   * Forward declarations
   */
  static struct z3fold_header *__z3fold_alloc(struct z3fold_pool *, size_t, bool);
  static void compact_page_work(struct work_struct *w);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
192
193
194
195
196
197
198
199
200
201
202
203
  /*****************
   * Helpers
  *****************/
  
  /* Converts an allocation size in bytes to size in z3fold chunks */
  static int size_to_chunks(size_t size)
  {
  	return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
  }
  
  #define for_each_unbuddied_list(_iter, _begin) \
  	for ((_iter) = (_begin); (_iter) < NCHUNKS; (_iter)++)
bb9f6f63f   Vitaly Wool   z3fold: fix shedu...
204
205
  static inline struct z3fold_buddy_slots *alloc_slots(struct z3fold_pool *pool,
  							gfp_t gfp)
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
206
  {
f1549cb5a   Henry Burns   mm/z3fold.c: allo...
207
  	struct z3fold_buddy_slots *slots;
f94afee99   Hui Su   mm/z3fold.c: use ...
208
  	slots = kmem_cache_zalloc(pool->c_handle,
f1549cb5a   Henry Burns   mm/z3fold.c: allo...
209
  				 (gfp & ~(__GFP_HIGHMEM | __GFP_MOVABLE)));
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
210
211
  
  	if (slots) {
af4798a5b   Qian Cai   mm/z3fold: silenc...
212
213
  		/* It will be freed separately in free_handle(). */
  		kmemleak_not_leak(slots);
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
214
  		slots->pool = (unsigned long)pool;
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
215
  		rwlock_init(&slots->lock);
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
216
217
218
219
220
221
222
223
224
225
226
227
228
229
  	}
  
  	return slots;
  }
  
  static inline struct z3fold_pool *slots_to_pool(struct z3fold_buddy_slots *s)
  {
  	return (struct z3fold_pool *)(s->pool & ~HANDLE_FLAG_MASK);
  }
  
  static inline struct z3fold_buddy_slots *handle_to_slots(unsigned long handle)
  {
  	return (struct z3fold_buddy_slots *)(handle & ~(SLOTS_ALIGN - 1));
  }
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
  /* Lock a z3fold page */
  static inline void z3fold_page_lock(struct z3fold_header *zhdr)
  {
  	spin_lock(&zhdr->page_lock);
  }
  
  /* Try to lock a z3fold page */
  static inline int z3fold_page_trylock(struct z3fold_header *zhdr)
  {
  	return spin_trylock(&zhdr->page_lock);
  }
  
  /* Unlock a z3fold page */
  static inline void z3fold_page_unlock(struct z3fold_header *zhdr)
  {
  	spin_unlock(&zhdr->page_lock);
  }
  
  
  static inline struct z3fold_header *__get_z3fold_header(unsigned long handle,
  							bool lock)
  {
  	struct z3fold_buddy_slots *slots;
  	struct z3fold_header *zhdr;
  	int locked = 0;
  
  	if (!(handle & (1 << PAGE_HEADLESS))) {
  		slots = handle_to_slots(handle);
  		do {
  			unsigned long addr;
  
  			read_lock(&slots->lock);
  			addr = *(unsigned long *)handle;
  			zhdr = (struct z3fold_header *)(addr & PAGE_MASK);
  			if (lock)
  				locked = z3fold_page_trylock(zhdr);
  			read_unlock(&slots->lock);
  			if (locked)
  				break;
  			cpu_relax();
  		} while (lock);
  	} else {
  		zhdr = (struct z3fold_header *)(handle & PAGE_MASK);
  	}
  
  	return zhdr;
  }
  
  /* Returns the z3fold page where a given handle is stored */
  static inline struct z3fold_header *handle_to_z3fold_header(unsigned long h)
  {
  	return __get_z3fold_header(h, false);
  }
  
  /* return locked z3fold page if it's not headless */
  static inline struct z3fold_header *get_z3fold_header(unsigned long h)
  {
  	return __get_z3fold_header(h, true);
  }
  
  static inline void put_z3fold_header(struct z3fold_header *zhdr)
  {
  	struct page *page = virt_to_page(zhdr);
  
  	if (!test_bit(PAGE_HEADLESS, &page->private))
  		z3fold_page_unlock(zhdr);
  }
b8b1d4e96   Vitaly Wool   z3fold: simplify ...
297
  static inline void free_handle(unsigned long handle, struct z3fold_header *zhdr)
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
298
299
300
301
302
303
304
  {
  	struct z3fold_buddy_slots *slots;
  	int i;
  	bool is_free;
  
  	if (handle & (1 << PAGE_HEADLESS))
  		return;
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
305
306
  	if (WARN_ON(*(unsigned long *)handle == 0))
  		return;
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
307
  	slots = handle_to_slots(handle);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
308
309
  	write_lock(&slots->lock);
  	*(unsigned long *)handle = 0;
746d179b0   Vitaly Wool   z3fold: stricter ...
310
311
312
313
314
  
  	if (test_bit(HANDLES_NOFREE, &slots->pool)) {
  		write_unlock(&slots->lock);
  		return; /* simple case, nothing else to do */
  	}
b8b1d4e96   Vitaly Wool   z3fold: simplify ...
315
316
  	if (zhdr->slots != slots)
  		zhdr->foreign_handles--;
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
317

7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
318
319
320
321
322
323
324
  	is_free = true;
  	for (i = 0; i <= BUDDY_MASK; i++) {
  		if (slots->slot[i]) {
  			is_free = false;
  			break;
  		}
  	}
d8f117abb   Uladzislau Rezki   z3fold: fix use-a...
325
  	write_unlock(&slots->lock);
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
326
327
328
  
  	if (is_free) {
  		struct z3fold_pool *pool = slots_to_pool(slots);
b8b1d4e96   Vitaly Wool   z3fold: simplify ...
329
330
  		if (zhdr->slots == slots)
  			zhdr->slots = NULL;
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
331
332
333
  		kmem_cache_free(pool->c_handle, slots);
  	}
  }
ea8157ab2   David Howells   zsfold: Convert z...
334
  static int z3fold_init_fs_context(struct fs_context *fc)
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
335
  {
ea8157ab2   David Howells   zsfold: Convert z...
336
  	return init_pseudo(fc, Z3FOLD_MAGIC) ? 0 : -ENOMEM;
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
337
338
339
340
  }
  
  static struct file_system_type z3fold_fs = {
  	.name		= "z3fold",
ea8157ab2   David Howells   zsfold: Convert z...
341
  	.init_fs_context = z3fold_init_fs_context,
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
  	.kill_sb	= kill_anon_super,
  };
  
  static struct vfsmount *z3fold_mnt;
  static int z3fold_mount(void)
  {
  	int ret = 0;
  
  	z3fold_mnt = kern_mount(&z3fold_fs);
  	if (IS_ERR(z3fold_mnt))
  		ret = PTR_ERR(z3fold_mnt);
  
  	return ret;
  }
  
  static void z3fold_unmount(void)
  {
  	kern_unmount(z3fold_mnt);
  }
  
  static const struct address_space_operations z3fold_aops;
  static int z3fold_register_migration(struct z3fold_pool *pool)
  {
  	pool->inode = alloc_anon_inode(z3fold_mnt->mnt_sb);
  	if (IS_ERR(pool->inode)) {
  		pool->inode = NULL;
  		return 1;
  	}
  
  	pool->inode->i_mapping->private_data = pool;
  	pool->inode->i_mapping->a_ops = &z3fold_aops;
  	return 0;
  }
  
  static void z3fold_unregister_migration(struct z3fold_pool *pool)
  {
  	if (pool->inode)
  		iput(pool->inode);
   }
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
381
  /* Initializes the z3fold header of a newly allocated z3fold page */
63398413c   Vitaly Wool   z3fold: fix memor...
382
  static struct z3fold_header *init_z3fold_page(struct page *page, bool headless,
bb9f6f63f   Vitaly Wool   z3fold: fix shedu...
383
  					struct z3fold_pool *pool, gfp_t gfp)
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
384
385
  {
  	struct z3fold_header *zhdr = page_address(page);
63398413c   Vitaly Wool   z3fold: fix memor...
386
  	struct z3fold_buddy_slots *slots;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
387
388
  
  	INIT_LIST_HEAD(&page->lru);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
389
390
  	clear_bit(PAGE_HEADLESS, &page->private);
  	clear_bit(MIDDLE_CHUNK_MAPPED, &page->private);
d30561c56   Vitaly Wool   z3fold: use per-c...
391
392
  	clear_bit(NEEDS_COMPACTING, &page->private);
  	clear_bit(PAGE_STALE, &page->private);
ca0246bb9   Vitaly Wool   z3fold: fix possi...
393
  	clear_bit(PAGE_CLAIMED, &page->private);
63398413c   Vitaly Wool   z3fold: fix memor...
394
395
396
397
398
399
  	if (headless)
  		return zhdr;
  
  	slots = alloc_slots(pool, gfp);
  	if (!slots)
  		return NULL;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
400

2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
401
  	spin_lock_init(&zhdr->page_lock);
5a27aa822   Vitaly Wool   z3fold: add kref ...
402
  	kref_init(&zhdr->refcount);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
403
404
405
406
407
  	zhdr->first_chunks = 0;
  	zhdr->middle_chunks = 0;
  	zhdr->last_chunks = 0;
  	zhdr->first_num = 0;
  	zhdr->start_middle = 0;
d30561c56   Vitaly Wool   z3fold: use per-c...
408
  	zhdr->cpu = -1;
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
409
  	zhdr->foreign_handles = 0;
d8f117abb   Uladzislau Rezki   z3fold: fix use-a...
410
  	zhdr->mapped_count = 0;
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
411
  	zhdr->slots = slots;
bb9a374df   Vitaly Wool   mm/z3fold: don't ...
412
  	zhdr->pool = pool;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
413
  	INIT_LIST_HEAD(&zhdr->buddy);
d30561c56   Vitaly Wool   z3fold: use per-c...
414
  	INIT_WORK(&zhdr->work, compact_page_work);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
415
416
417
418
  	return zhdr;
  }
  
  /* Resets the struct page fields and frees the page */
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
419
  static void free_z3fold_page(struct page *page, bool headless)
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
420
  {
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
421
422
423
424
425
426
  	if (!headless) {
  		lock_page(page);
  		__ClearPageMovable(page);
  		unlock_page(page);
  	}
  	ClearPagePrivate(page);
5a27aa822   Vitaly Wool   z3fold: add kref ...
427
428
  	__free_page(page);
  }
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
429
430
431
432
433
  /* Helper function to build the index */
  static inline int __idx(struct z3fold_header *zhdr, enum buddy bud)
  {
  	return (bud + zhdr->first_num) & BUDDY_MASK;
  }
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
434
435
436
437
  /*
   * Encodes the handle of a particular buddy within a z3fold page
   * Pool lock should be held as this function accesses first_num
   */
3f9d2b576   Vitaly Wool   z3fold: fix retry...
438
439
440
  static unsigned long __encode_handle(struct z3fold_header *zhdr,
  				struct z3fold_buddy_slots *slots,
  				enum buddy bud)
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
441
  {
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
442
443
  	unsigned long h = (unsigned long)zhdr;
  	int idx = 0;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
444

7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
445
446
447
448
449
450
451
452
453
454
455
456
  	/*
  	 * For a headless page, its handle is its pointer with the extra
  	 * PAGE_HEADLESS bit set
  	 */
  	if (bud == HEADLESS)
  		return h | (1 << PAGE_HEADLESS);
  
  	/* otherwise, return pointer to encoded handle */
  	idx = __idx(zhdr, bud);
  	h += idx;
  	if (bud == LAST)
  		h |= (zhdr->last_chunks << BUDDY_SHIFT);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
457
  	write_lock(&slots->lock);
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
458
  	slots->slot[idx] = h;
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
459
  	write_unlock(&slots->lock);
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
460
  	return (unsigned long)&slots->slot[idx];
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
461
  }
3f9d2b576   Vitaly Wool   z3fold: fix retry...
462
463
464
465
  static unsigned long encode_handle(struct z3fold_header *zhdr, enum buddy bud)
  {
  	return __encode_handle(zhdr, zhdr->slots, bud);
  }
ca0246bb9   Vitaly Wool   z3fold: fix possi...
466
467
468
  /* only for LAST bud, returns zero otherwise */
  static unsigned short handle_to_chunks(unsigned long handle)
  {
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
469
470
  	struct z3fold_buddy_slots *slots = handle_to_slots(handle);
  	unsigned long addr;
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
471

4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
472
473
474
  	read_lock(&slots->lock);
  	addr = *(unsigned long *)handle;
  	read_unlock(&slots->lock);
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
475
  	return (addr & ~PAGE_MASK) >> BUDDY_SHIFT;
ca0246bb9   Vitaly Wool   z3fold: fix possi...
476
  }
f201ebd87   zhong jiang   mm/z3fold.c: limi...
477
478
479
480
481
  /*
   * (handle & BUDDY_MASK) < zhdr->first_num is possible in encode_handle
   *  but that doesn't matter. because the masking will result in the
   *  correct buddy number.
   */
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
482
483
  static enum buddy handle_to_buddy(unsigned long handle)
  {
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
484
  	struct z3fold_header *zhdr;
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
485
  	struct z3fold_buddy_slots *slots = handle_to_slots(handle);
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
486
  	unsigned long addr;
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
487
  	read_lock(&slots->lock);
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
488
489
  	WARN_ON(handle & (1 << PAGE_HEADLESS));
  	addr = *(unsigned long *)handle;
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
490
  	read_unlock(&slots->lock);
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
491
492
  	zhdr = (struct z3fold_header *)(addr & PAGE_MASK);
  	return (addr - zhdr->first_num) & BUDDY_MASK;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
493
  }
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
494
495
  static inline struct z3fold_pool *zhdr_to_pool(struct z3fold_header *zhdr)
  {
bb9a374df   Vitaly Wool   mm/z3fold: don't ...
496
  	return zhdr->pool;
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
497
  }
d30561c56   Vitaly Wool   z3fold: use per-c...
498
499
500
  static void __release_z3fold_page(struct z3fold_header *zhdr, bool locked)
  {
  	struct page *page = virt_to_page(zhdr);
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
501
  	struct z3fold_pool *pool = zhdr_to_pool(zhdr);
d30561c56   Vitaly Wool   z3fold: use per-c...
502
503
504
  
  	WARN_ON(!list_empty(&zhdr->buddy));
  	set_bit(PAGE_STALE, &page->private);
355293574   Vitaly Wool   z3fold: fix stale...
505
  	clear_bit(NEEDS_COMPACTING, &page->private);
d30561c56   Vitaly Wool   z3fold: use per-c...
506
507
  	spin_lock(&pool->lock);
  	if (!list_empty(&page->lru))
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
508
  		list_del_init(&page->lru);
d30561c56   Vitaly Wool   z3fold: use per-c...
509
  	spin_unlock(&pool->lock);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
510

d30561c56   Vitaly Wool   z3fold: use per-c...
511
512
  	if (locked)
  		z3fold_page_unlock(zhdr);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
513

d30561c56   Vitaly Wool   z3fold: use per-c...
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
  	spin_lock(&pool->stale_lock);
  	list_add(&zhdr->buddy, &pool->stale);
  	queue_work(pool->release_wq, &pool->work);
  	spin_unlock(&pool->stale_lock);
  }
  
  static void __attribute__((__unused__))
  			release_z3fold_page(struct kref *ref)
  {
  	struct z3fold_header *zhdr = container_of(ref, struct z3fold_header,
  						refcount);
  	__release_z3fold_page(zhdr, false);
  }
  
  static void release_z3fold_page_locked(struct kref *ref)
  {
  	struct z3fold_header *zhdr = container_of(ref, struct z3fold_header,
  						refcount);
  	WARN_ON(z3fold_page_trylock(zhdr));
  	__release_z3fold_page(zhdr, true);
  }
  
  static void release_z3fold_page_locked_list(struct kref *ref)
  {
  	struct z3fold_header *zhdr = container_of(ref, struct z3fold_header,
  					       refcount);
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
540
  	struct z3fold_pool *pool = zhdr_to_pool(zhdr);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
541

9050cce10   Vitaly Wool   mm/z3fold.c: intr...
542
  	spin_lock(&pool->lock);
d30561c56   Vitaly Wool   z3fold: use per-c...
543
  	list_del_init(&zhdr->buddy);
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
544
  	spin_unlock(&pool->lock);
d30561c56   Vitaly Wool   z3fold: use per-c...
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
  
  	WARN_ON(z3fold_page_trylock(zhdr));
  	__release_z3fold_page(zhdr, true);
  }
  
  static void free_pages_work(struct work_struct *w)
  {
  	struct z3fold_pool *pool = container_of(w, struct z3fold_pool, work);
  
  	spin_lock(&pool->stale_lock);
  	while (!list_empty(&pool->stale)) {
  		struct z3fold_header *zhdr = list_first_entry(&pool->stale,
  						struct z3fold_header, buddy);
  		struct page *page = virt_to_page(zhdr);
  
  		list_del(&zhdr->buddy);
  		if (WARN_ON(!test_bit(PAGE_STALE, &page->private)))
  			continue;
d30561c56   Vitaly Wool   z3fold: use per-c...
563
564
  		spin_unlock(&pool->stale_lock);
  		cancel_work_sync(&zhdr->work);
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
565
  		free_z3fold_page(page, false);
d30561c56   Vitaly Wool   z3fold: use per-c...
566
567
568
569
570
  		cond_resched();
  		spin_lock(&pool->stale_lock);
  	}
  	spin_unlock(&pool->stale_lock);
  }
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
571
572
573
574
575
576
577
578
579
580
581
582
583
584
  /*
   * Returns the number of free chunks in a z3fold page.
   * NB: can't be used with HEADLESS pages.
   */
  static int num_free_chunks(struct z3fold_header *zhdr)
  {
  	int nfree;
  	/*
  	 * If there is a middle object, pick up the bigger free space
  	 * either before or after it. Otherwise just subtract the number
  	 * of chunks occupied by the first and the last objects.
  	 */
  	if (zhdr->middle_chunks != 0) {
  		int nfree_before = zhdr->first_chunks ?
ede93213a   Vitaly Wool   z3fold: fix heade...
585
  			0 : zhdr->start_middle - ZHDR_CHUNKS;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
586
  		int nfree_after = zhdr->last_chunks ?
ede93213a   Vitaly Wool   z3fold: fix heade...
587
588
  			0 : TOTAL_CHUNKS -
  				(zhdr->start_middle + zhdr->middle_chunks);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
589
590
591
592
593
  		nfree = max(nfree_before, nfree_after);
  	} else
  		nfree = NCHUNKS - zhdr->first_chunks - zhdr->last_chunks;
  	return nfree;
  }
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
  /* Add to the appropriate unbuddied list */
  static inline void add_to_unbuddied(struct z3fold_pool *pool,
  				struct z3fold_header *zhdr)
  {
  	if (zhdr->first_chunks == 0 || zhdr->last_chunks == 0 ||
  			zhdr->middle_chunks == 0) {
  		struct list_head *unbuddied = get_cpu_ptr(pool->unbuddied);
  
  		int freechunks = num_free_chunks(zhdr);
  		spin_lock(&pool->lock);
  		list_add(&zhdr->buddy, &unbuddied[freechunks]);
  		spin_unlock(&pool->lock);
  		zhdr->cpu = smp_processor_id();
  		put_cpu_ptr(pool->unbuddied);
  	}
  }
746d179b0   Vitaly Wool   z3fold: stricter ...
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
  static inline enum buddy get_free_buddy(struct z3fold_header *zhdr, int chunks)
  {
  	enum buddy bud = HEADLESS;
  
  	if (zhdr->middle_chunks) {
  		if (!zhdr->first_chunks &&
  		    chunks <= zhdr->start_middle - ZHDR_CHUNKS)
  			bud = FIRST;
  		else if (!zhdr->last_chunks)
  			bud = LAST;
  	} else {
  		if (!zhdr->first_chunks)
  			bud = FIRST;
  		else if (!zhdr->last_chunks)
  			bud = LAST;
  		else
  			bud = MIDDLE;
  	}
  
  	return bud;
  }
ede93213a   Vitaly Wool   z3fold: fix heade...
631
632
633
634
635
636
637
638
  static inline void *mchunk_memmove(struct z3fold_header *zhdr,
  				unsigned short dst_chunk)
  {
  	void *beg = zhdr;
  	return memmove(beg + (dst_chunk << CHUNK_SHIFT),
  		       beg + (zhdr->start_middle << CHUNK_SHIFT),
  		       zhdr->middle_chunks << CHUNK_SHIFT);
  }
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
  static inline bool buddy_single(struct z3fold_header *zhdr)
  {
  	return !((zhdr->first_chunks && zhdr->middle_chunks) ||
  			(zhdr->first_chunks && zhdr->last_chunks) ||
  			(zhdr->middle_chunks && zhdr->last_chunks));
  }
  
  static struct z3fold_header *compact_single_buddy(struct z3fold_header *zhdr)
  {
  	struct z3fold_pool *pool = zhdr_to_pool(zhdr);
  	void *p = zhdr;
  	unsigned long old_handle = 0;
  	size_t sz = 0;
  	struct z3fold_header *new_zhdr = NULL;
  	int first_idx = __idx(zhdr, FIRST);
  	int middle_idx = __idx(zhdr, MIDDLE);
  	int last_idx = __idx(zhdr, LAST);
  	unsigned short *moved_chunks = NULL;
  
  	/*
  	 * No need to protect slots here -- all the slots are "local" and
  	 * the page lock is already taken
  	 */
  	if (zhdr->first_chunks && zhdr->slots->slot[first_idx]) {
  		p += ZHDR_SIZE_ALIGNED;
  		sz = zhdr->first_chunks << CHUNK_SHIFT;
  		old_handle = (unsigned long)&zhdr->slots->slot[first_idx];
  		moved_chunks = &zhdr->first_chunks;
  	} else if (zhdr->middle_chunks && zhdr->slots->slot[middle_idx]) {
  		p += zhdr->start_middle << CHUNK_SHIFT;
  		sz = zhdr->middle_chunks << CHUNK_SHIFT;
  		old_handle = (unsigned long)&zhdr->slots->slot[middle_idx];
  		moved_chunks = &zhdr->middle_chunks;
  	} else if (zhdr->last_chunks && zhdr->slots->slot[last_idx]) {
  		p += PAGE_SIZE - (zhdr->last_chunks << CHUNK_SHIFT);
  		sz = zhdr->last_chunks << CHUNK_SHIFT;
  		old_handle = (unsigned long)&zhdr->slots->slot[last_idx];
  		moved_chunks = &zhdr->last_chunks;
  	}
  
  	if (sz > 0) {
  		enum buddy new_bud = HEADLESS;
  		short chunks = size_to_chunks(sz);
  		void *q;
  
  		new_zhdr = __z3fold_alloc(pool, sz, false);
  		if (!new_zhdr)
  			return NULL;
  
  		if (WARN_ON(new_zhdr == zhdr))
  			goto out_fail;
746d179b0   Vitaly Wool   z3fold: stricter ...
690
  		new_bud = get_free_buddy(new_zhdr, chunks);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
  		q = new_zhdr;
  		switch (new_bud) {
  		case FIRST:
  			new_zhdr->first_chunks = chunks;
  			q += ZHDR_SIZE_ALIGNED;
  			break;
  		case MIDDLE:
  			new_zhdr->middle_chunks = chunks;
  			new_zhdr->start_middle =
  				new_zhdr->first_chunks + ZHDR_CHUNKS;
  			q += new_zhdr->start_middle << CHUNK_SHIFT;
  			break;
  		case LAST:
  			new_zhdr->last_chunks = chunks;
  			q += PAGE_SIZE - (new_zhdr->last_chunks << CHUNK_SHIFT);
  			break;
  		default:
  			goto out_fail;
  		}
  		new_zhdr->foreign_handles++;
  		memcpy(q, p, sz);
  		write_lock(&zhdr->slots->lock);
  		*(unsigned long *)old_handle = (unsigned long)new_zhdr +
  			__idx(new_zhdr, new_bud);
  		if (new_bud == LAST)
  			*(unsigned long *)old_handle |=
  					(new_zhdr->last_chunks << BUDDY_SHIFT);
  		write_unlock(&zhdr->slots->lock);
  		add_to_unbuddied(pool, new_zhdr);
  		z3fold_page_unlock(new_zhdr);
  
  		*moved_chunks = 0;
  	}
  
  	return new_zhdr;
  
  out_fail:
  	if (new_zhdr) {
  		if (kref_put(&new_zhdr->refcount, release_z3fold_page_locked))
  			atomic64_dec(&pool->pages_nr);
  		else {
  			add_to_unbuddied(pool, new_zhdr);
  			z3fold_page_unlock(new_zhdr);
  		}
  	}
  	return NULL;
  
  }
1b096e5ae   Vitaly Wool   z3fold: extend co...
739
  #define BIG_CHUNK_GAP	3
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
740
741
742
743
  /* Has to be called with lock held */
  static int z3fold_compact_page(struct z3fold_header *zhdr)
  {
  	struct page *page = virt_to_page(zhdr);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
744

ede93213a   Vitaly Wool   z3fold: fix heade...
745
746
  	if (test_bit(MIDDLE_CHUNK_MAPPED, &page->private))
  		return 0; /* can't move middle chunk, it's used */
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
747

1f862989b   Vitaly Wool   mm/z3fold.c: supp...
748
749
  	if (unlikely(PageIsolated(page)))
  		return 0;
ede93213a   Vitaly Wool   z3fold: fix heade...
750
751
752
753
754
755
  	if (zhdr->middle_chunks == 0)
  		return 0; /* nothing to compact */
  
  	if (zhdr->first_chunks == 0 && zhdr->last_chunks == 0) {
  		/* move to the beginning */
  		mchunk_memmove(zhdr, ZHDR_CHUNKS);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
756
757
758
759
  		zhdr->first_chunks = zhdr->middle_chunks;
  		zhdr->middle_chunks = 0;
  		zhdr->start_middle = 0;
  		zhdr->first_num++;
1b096e5ae   Vitaly Wool   z3fold: extend co...
760
  		return 1;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
761
  	}
1b096e5ae   Vitaly Wool   z3fold: extend co...
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
  
  	/*
  	 * moving data is expensive, so let's only do that if
  	 * there's substantial gain (at least BIG_CHUNK_GAP chunks)
  	 */
  	if (zhdr->first_chunks != 0 && zhdr->last_chunks == 0 &&
  	    zhdr->start_middle - (zhdr->first_chunks + ZHDR_CHUNKS) >=
  			BIG_CHUNK_GAP) {
  		mchunk_memmove(zhdr, zhdr->first_chunks + ZHDR_CHUNKS);
  		zhdr->start_middle = zhdr->first_chunks + ZHDR_CHUNKS;
  		return 1;
  	} else if (zhdr->last_chunks != 0 && zhdr->first_chunks == 0 &&
  		   TOTAL_CHUNKS - (zhdr->last_chunks + zhdr->start_middle
  					+ zhdr->middle_chunks) >=
  			BIG_CHUNK_GAP) {
  		unsigned short new_start = TOTAL_CHUNKS - zhdr->last_chunks -
  			zhdr->middle_chunks;
  		mchunk_memmove(zhdr, new_start);
  		zhdr->start_middle = new_start;
  		return 1;
  	}
  
  	return 0;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
785
  }
d30561c56   Vitaly Wool   z3fold: use per-c...
786
787
  static void do_compact_page(struct z3fold_header *zhdr, bool locked)
  {
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
788
  	struct z3fold_pool *pool = zhdr_to_pool(zhdr);
d30561c56   Vitaly Wool   z3fold: use per-c...
789
  	struct page *page;
d30561c56   Vitaly Wool   z3fold: use per-c...
790
791
792
793
794
795
  
  	page = virt_to_page(zhdr);
  	if (locked)
  		WARN_ON(z3fold_page_trylock(zhdr));
  	else
  		z3fold_page_lock(zhdr);
5d03a6613   Vitaly Wool   mm/z3fold.c: use ...
796
  	if (WARN_ON(!test_and_clear_bit(NEEDS_COMPACTING, &page->private))) {
d30561c56   Vitaly Wool   z3fold: use per-c...
797
798
799
800
801
802
  		z3fold_page_unlock(zhdr);
  		return;
  	}
  	spin_lock(&pool->lock);
  	list_del_init(&zhdr->buddy);
  	spin_unlock(&pool->lock);
5d03a6613   Vitaly Wool   mm/z3fold.c: use ...
803
804
805
806
  	if (kref_put(&zhdr->refcount, release_z3fold_page_locked)) {
  		atomic64_dec(&pool->pages_nr);
  		return;
  	}
746d179b0   Vitaly Wool   z3fold: stricter ...
807
808
  	if (test_bit(PAGE_STALE, &page->private) ||
  	    test_and_set_bit(PAGE_CLAIMED, &page->private)) {
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
809
810
811
  		z3fold_page_unlock(zhdr);
  		return;
  	}
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
812
813
814
815
  	if (!zhdr->foreign_handles && buddy_single(zhdr) &&
  	    zhdr->mapped_count == 0 && compact_single_buddy(zhdr)) {
  		if (kref_put(&zhdr->refcount, release_z3fold_page_locked))
  			atomic64_dec(&pool->pages_nr);
746d179b0   Vitaly Wool   z3fold: stricter ...
816
817
  		else {
  			clear_bit(PAGE_CLAIMED, &page->private);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
818
  			z3fold_page_unlock(zhdr);
746d179b0   Vitaly Wool   z3fold: stricter ...
819
  		}
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
820
821
  		return;
  	}
d30561c56   Vitaly Wool   z3fold: use per-c...
822
  	z3fold_compact_page(zhdr);
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
823
  	add_to_unbuddied(pool, zhdr);
746d179b0   Vitaly Wool   z3fold: stricter ...
824
  	clear_bit(PAGE_CLAIMED, &page->private);
d30561c56   Vitaly Wool   z3fold: use per-c...
825
826
827
828
829
830
831
832
833
834
  	z3fold_page_unlock(zhdr);
  }
  
  static void compact_page_work(struct work_struct *w)
  {
  	struct z3fold_header *zhdr = container_of(w, struct z3fold_header,
  						work);
  
  	do_compact_page(zhdr, false);
  }
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
  /* returns _locked_ z3fold page header or NULL */
  static inline struct z3fold_header *__z3fold_alloc(struct z3fold_pool *pool,
  						size_t size, bool can_sleep)
  {
  	struct z3fold_header *zhdr = NULL;
  	struct page *page;
  	struct list_head *unbuddied;
  	int chunks = size_to_chunks(size), i;
  
  lookup:
  	/* First, try to find an unbuddied z3fold page. */
  	unbuddied = get_cpu_ptr(pool->unbuddied);
  	for_each_unbuddied_list(i, chunks) {
  		struct list_head *l = &unbuddied[i];
  
  		zhdr = list_first_entry_or_null(READ_ONCE(l),
  					struct z3fold_header, buddy);
  
  		if (!zhdr)
  			continue;
  
  		/* Re-check under lock. */
  		spin_lock(&pool->lock);
  		l = &unbuddied[i];
  		if (unlikely(zhdr != list_first_entry(READ_ONCE(l),
  						struct z3fold_header, buddy)) ||
  		    !z3fold_page_trylock(zhdr)) {
  			spin_unlock(&pool->lock);
  			zhdr = NULL;
  			put_cpu_ptr(pool->unbuddied);
  			if (can_sleep)
  				cond_resched();
  			goto lookup;
  		}
  		list_del_init(&zhdr->buddy);
  		zhdr->cpu = -1;
  		spin_unlock(&pool->lock);
  
  		page = virt_to_page(zhdr);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
874
875
  		if (test_bit(NEEDS_COMPACTING, &page->private) ||
  		    test_bit(PAGE_CLAIMED, &page->private)) {
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
  			z3fold_page_unlock(zhdr);
  			zhdr = NULL;
  			put_cpu_ptr(pool->unbuddied);
  			if (can_sleep)
  				cond_resched();
  			goto lookup;
  		}
  
  		/*
  		 * this page could not be removed from its unbuddied
  		 * list while pool lock was held, and then we've taken
  		 * page lock so kref_put could not be called before
  		 * we got here, so it's safe to just call kref_get()
  		 */
  		kref_get(&zhdr->refcount);
  		break;
  	}
  	put_cpu_ptr(pool->unbuddied);
351618b20   Vitaly Wool   mm/z3fold.c: impr...
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
  	if (!zhdr) {
  		int cpu;
  
  		/* look for _exact_ match on other cpus' lists */
  		for_each_online_cpu(cpu) {
  			struct list_head *l;
  
  			unbuddied = per_cpu_ptr(pool->unbuddied, cpu);
  			spin_lock(&pool->lock);
  			l = &unbuddied[chunks];
  
  			zhdr = list_first_entry_or_null(READ_ONCE(l),
  						struct z3fold_header, buddy);
  
  			if (!zhdr || !z3fold_page_trylock(zhdr)) {
  				spin_unlock(&pool->lock);
  				zhdr = NULL;
  				continue;
  			}
  			list_del_init(&zhdr->buddy);
  			zhdr->cpu = -1;
  			spin_unlock(&pool->lock);
  
  			page = virt_to_page(zhdr);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
918
919
  			if (test_bit(NEEDS_COMPACTING, &page->private) ||
  			    test_bit(PAGE_CLAIMED, &page->private)) {
351618b20   Vitaly Wool   mm/z3fold.c: impr...
920
921
922
923
924
925
926
927
928
929
  				z3fold_page_unlock(zhdr);
  				zhdr = NULL;
  				if (can_sleep)
  					cond_resched();
  				continue;
  			}
  			kref_get(&zhdr->refcount);
  			break;
  		}
  	}
b8b1d4e96   Vitaly Wool   z3fold: simplify ...
930
931
932
  	if (zhdr && !zhdr->slots)
  		zhdr->slots = alloc_slots(pool,
  					can_sleep ? GFP_NOIO : GFP_ATOMIC);
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
933
934
  	return zhdr;
  }
d30561c56   Vitaly Wool   z3fold: use per-c...
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
  
  /*
   * API Functions
   */
  
  /**
   * z3fold_create_pool() - create a new z3fold pool
   * @name:	pool name
   * @gfp:	gfp flags when allocating the z3fold pool structure
   * @ops:	user-defined operations for the z3fold pool
   *
   * Return: pointer to the new z3fold pool or NULL if the metadata allocation
   * failed.
   */
  static struct z3fold_pool *z3fold_create_pool(const char *name, gfp_t gfp,
  		const struct z3fold_ops *ops)
  {
  	struct z3fold_pool *pool = NULL;
  	int i, cpu;
  
  	pool = kzalloc(sizeof(struct z3fold_pool), gfp);
  	if (!pool)
  		goto out;
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
958
959
960
961
962
  	pool->c_handle = kmem_cache_create("z3fold_handle",
  				sizeof(struct z3fold_buddy_slots),
  				SLOTS_ALIGN, 0, NULL);
  	if (!pool->c_handle)
  		goto out_c;
d30561c56   Vitaly Wool   z3fold: use per-c...
963
964
965
  	spin_lock_init(&pool->lock);
  	spin_lock_init(&pool->stale_lock);
  	pool->unbuddied = __alloc_percpu(sizeof(struct list_head)*NCHUNKS, 2);
1ec6995d1   Xidong Wang   z3fold: fix memor...
966
967
  	if (!pool->unbuddied)
  		goto out_pool;
d30561c56   Vitaly Wool   z3fold: use per-c...
968
969
970
971
972
973
974
975
976
977
978
979
  	for_each_possible_cpu(cpu) {
  		struct list_head *unbuddied =
  				per_cpu_ptr(pool->unbuddied, cpu);
  		for_each_unbuddied_list(i, 0)
  			INIT_LIST_HEAD(&unbuddied[i]);
  	}
  	INIT_LIST_HEAD(&pool->lru);
  	INIT_LIST_HEAD(&pool->stale);
  	atomic64_set(&pool->pages_nr, 0);
  	pool->name = name;
  	pool->compact_wq = create_singlethread_workqueue(pool->name);
  	if (!pool->compact_wq)
1ec6995d1   Xidong Wang   z3fold: fix memor...
980
  		goto out_unbuddied;
d30561c56   Vitaly Wool   z3fold: use per-c...
981
982
983
  	pool->release_wq = create_singlethread_workqueue(pool->name);
  	if (!pool->release_wq)
  		goto out_wq;
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
984
985
  	if (z3fold_register_migration(pool))
  		goto out_rwq;
d30561c56   Vitaly Wool   z3fold: use per-c...
986
987
988
  	INIT_WORK(&pool->work, free_pages_work);
  	pool->ops = ops;
  	return pool;
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
989
990
  out_rwq:
  	destroy_workqueue(pool->release_wq);
d30561c56   Vitaly Wool   z3fold: use per-c...
991
992
  out_wq:
  	destroy_workqueue(pool->compact_wq);
1ec6995d1   Xidong Wang   z3fold: fix memor...
993
994
995
  out_unbuddied:
  	free_percpu(pool->unbuddied);
  out_pool:
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
996
997
  	kmem_cache_destroy(pool->c_handle);
  out_c:
d30561c56   Vitaly Wool   z3fold: use per-c...
998
  	kfree(pool);
1ec6995d1   Xidong Wang   z3fold: fix memor...
999
  out:
d30561c56   Vitaly Wool   z3fold: use per-c...
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
  	return NULL;
  }
  
  /**
   * z3fold_destroy_pool() - destroys an existing z3fold pool
   * @pool:	the z3fold pool to be destroyed
   *
   * The pool should be emptied before this function is called.
   */
  static void z3fold_destroy_pool(struct z3fold_pool *pool)
  {
7c2b8baa6   Vitaly Wool   mm/z3fold.c: add ...
1011
  	kmem_cache_destroy(pool->c_handle);
6051d3bd3   Henry Burns   mm/z3fold.c: fix ...
1012
1013
1014
1015
1016
  
  	/*
  	 * We need to destroy pool->compact_wq before pool->release_wq,
  	 * as any pending work on pool->compact_wq will call
  	 * queue_work(pool->release_wq, &pool->work).
b997052bc   Henry Burns   mm/z3fold.c: fix ...
1017
1018
1019
  	 *
  	 * There are still outstanding pages until both workqueues are drained,
  	 * so we cannot unregister migration until then.
6051d3bd3   Henry Burns   mm/z3fold.c: fix ...
1020
  	 */
d30561c56   Vitaly Wool   z3fold: use per-c...
1021
  	destroy_workqueue(pool->compact_wq);
6051d3bd3   Henry Burns   mm/z3fold.c: fix ...
1022
  	destroy_workqueue(pool->release_wq);
b997052bc   Henry Burns   mm/z3fold.c: fix ...
1023
  	z3fold_unregister_migration(pool);
d30561c56   Vitaly Wool   z3fold: use per-c...
1024
1025
  	kfree(pool);
  }
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
  /**
   * z3fold_alloc() - allocates a region of a given size
   * @pool:	z3fold pool from which to allocate
   * @size:	size in bytes of the desired allocation
   * @gfp:	gfp flags used if the pool needs to grow
   * @handle:	handle of the new allocation
   *
   * This function will attempt to find a free region in the pool large enough to
   * satisfy the allocation request.  A search of the unbuddied lists is
   * performed first. If no suitable free region is found, then a new page is
   * allocated and added to the pool to satisfy the request.
   *
   * gfp should not set __GFP_HIGHMEM as highmem pages cannot be used
   * as z3fold pool pages.
   *
   * Return: 0 if success and handle is set, otherwise -EINVAL if the size or
   * gfp arguments are invalid or -ENOMEM if the pool was unable to allocate
   * a new page.
   */
  static int z3fold_alloc(struct z3fold_pool *pool, size_t size, gfp_t gfp,
  			unsigned long *handle)
  {
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
1048
  	int chunks = size_to_chunks(size);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1049
  	struct z3fold_header *zhdr = NULL;
d30561c56   Vitaly Wool   z3fold: use per-c...
1050
  	struct page *page = NULL;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1051
  	enum buddy bud;
8a97ea546   Matthew Wilcox   mm/z3fold.c: use ...
1052
  	bool can_sleep = gfpflags_allow_blocking(gfp);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1053

f1549cb5a   Henry Burns   mm/z3fold.c: allo...
1054
  	if (!size)
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1055
1056
1057
1058
1059
1060
1061
1062
  		return -EINVAL;
  
  	if (size > PAGE_SIZE)
  		return -ENOSPC;
  
  	if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE)
  		bud = HEADLESS;
  	else {
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
1063
1064
  retry:
  		zhdr = __z3fold_alloc(pool, size, can_sleep);
d30561c56   Vitaly Wool   z3fold: use per-c...
1065
  		if (zhdr) {
746d179b0   Vitaly Wool   z3fold: stricter ...
1066
1067
  			bud = get_free_buddy(zhdr, chunks);
  			if (bud == HEADLESS) {
5a27aa822   Vitaly Wool   z3fold: add kref ...
1068
  				if (kref_put(&zhdr->refcount,
d30561c56   Vitaly Wool   z3fold: use per-c...
1069
  					     release_z3fold_page_locked))
5a27aa822   Vitaly Wool   z3fold: add kref ...
1070
  					atomic64_dec(&pool->pages_nr);
d30561c56   Vitaly Wool   z3fold: use per-c...
1071
1072
  				else
  					z3fold_page_unlock(zhdr);
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
1073
1074
1075
  				pr_err("No free chunks in unbuddied
  ");
  				WARN_ON(1);
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
1076
  				goto retry;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1077
  			}
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
1078
  			page = virt_to_page(zhdr);
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
1079
  			goto found;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1080
1081
  		}
  		bud = FIRST;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1082
  	}
5c9bab592   Vitaly Wool   z3fold: limit use...
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
  	page = NULL;
  	if (can_sleep) {
  		spin_lock(&pool->stale_lock);
  		zhdr = list_first_entry_or_null(&pool->stale,
  						struct z3fold_header, buddy);
  		/*
  		 * Before allocating a page, let's see if we can take one from
  		 * the stale pages list. cancel_work_sync() can sleep so we
  		 * limit this case to the contexts where we can sleep
  		 */
  		if (zhdr) {
  			list_del(&zhdr->buddy);
  			spin_unlock(&pool->stale_lock);
d30561c56   Vitaly Wool   z3fold: use per-c...
1096
  			cancel_work_sync(&zhdr->work);
5c9bab592   Vitaly Wool   z3fold: limit use...
1097
1098
1099
1100
  			page = virt_to_page(zhdr);
  		} else {
  			spin_unlock(&pool->stale_lock);
  		}
d30561c56   Vitaly Wool   z3fold: use per-c...
1101
  	}
5c9bab592   Vitaly Wool   z3fold: limit use...
1102
1103
  	if (!page)
  		page = alloc_page(gfp);
d30561c56   Vitaly Wool   z3fold: use per-c...
1104

9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1105
1106
  	if (!page)
  		return -ENOMEM;
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
1107

63398413c   Vitaly Wool   z3fold: fix memor...
1108
  	zhdr = init_z3fold_page(page, bud == HEADLESS, pool, gfp);
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
1109
1110
1111
1112
1113
  	if (!zhdr) {
  		__free_page(page);
  		return -ENOMEM;
  	}
  	atomic64_inc(&pool->pages_nr);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1114
1115
1116
1117
1118
  
  	if (bud == HEADLESS) {
  		set_bit(PAGE_HEADLESS, &page->private);
  		goto headless;
  	}
810481a24   Henry Burns   mm/z3fold.c: lock...
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
  	if (can_sleep) {
  		lock_page(page);
  		__SetPageMovable(page, pool->inode->i_mapping);
  		unlock_page(page);
  	} else {
  		if (trylock_page(page)) {
  			__SetPageMovable(page, pool->inode->i_mapping);
  			unlock_page(page);
  		}
  	}
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
1129
  	z3fold_page_lock(zhdr);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1130
1131
1132
1133
1134
1135
1136
1137
  
  found:
  	if (bud == FIRST)
  		zhdr->first_chunks = chunks;
  	else if (bud == LAST)
  		zhdr->last_chunks = chunks;
  	else {
  		zhdr->middle_chunks = chunks;
ede93213a   Vitaly Wool   z3fold: fix heade...
1138
  		zhdr->start_middle = zhdr->first_chunks + ZHDR_CHUNKS;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1139
  	}
9050cce10   Vitaly Wool   mm/z3fold.c: intr...
1140
  	add_to_unbuddied(pool, zhdr);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1141
1142
  
  headless:
d30561c56   Vitaly Wool   z3fold: use per-c...
1143
  	spin_lock(&pool->lock);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1144
1145
1146
1147
1148
1149
1150
1151
  	/* Add/move z3fold page to beginning of LRU */
  	if (!list_empty(&page->lru))
  		list_del(&page->lru);
  
  	list_add(&page->lru, &pool->lru);
  
  	*handle = encode_handle(zhdr, bud);
  	spin_unlock(&pool->lock);
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
1152
1153
  	if (bud != HEADLESS)
  		z3fold_page_unlock(zhdr);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
  
  	return 0;
  }
  
  /**
   * z3fold_free() - frees the allocation associated with the given handle
   * @pool:	pool in which the allocation resided
   * @handle:	handle associated with the allocation returned by z3fold_alloc()
   *
   * In the case that the z3fold page in which the allocation resides is under
   * reclaim, as indicated by the PG_reclaim flag being set, this function
   * only sets the first|last_chunks to 0.  The page is actually freed
   * once both buddies are evicted (see z3fold_reclaim_page() below).
   */
  static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
  {
  	struct z3fold_header *zhdr;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1171
1172
  	struct page *page;
  	enum buddy bud;
5b6807de1   Vitaly Wool   mm/z3fold.c: clai...
1173
  	bool page_claimed;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1174

4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1175
  	zhdr = get_z3fold_header(handle);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1176
  	page = virt_to_page(zhdr);
5b6807de1   Vitaly Wool   mm/z3fold.c: clai...
1177
  	page_claimed = test_and_set_bit(PAGE_CLAIMED, &page->private);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1178
1179
  
  	if (test_bit(PAGE_HEADLESS, &page->private)) {
ca0246bb9   Vitaly Wool   z3fold: fix possi...
1180
1181
1182
1183
1184
  		/* if a headless page is under reclaim, just leave.
  		 * NB: we use test_and_set_bit for a reason: if the bit
  		 * has not been set before, we release this page
  		 * immediately so we don't care about its value any more.
  		 */
5b6807de1   Vitaly Wool   mm/z3fold.c: clai...
1185
  		if (!page_claimed) {
ca0246bb9   Vitaly Wool   z3fold: fix possi...
1186
1187
1188
  			spin_lock(&pool->lock);
  			list_del(&page->lru);
  			spin_unlock(&pool->lock);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1189
  			put_z3fold_header(zhdr);
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1190
  			free_z3fold_page(page, true);
ca0246bb9   Vitaly Wool   z3fold: fix possi...
1191
  			atomic64_dec(&pool->pages_nr);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1192
  		}
ca0246bb9   Vitaly Wool   z3fold: fix possi...
1193
  		return;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1194
  	}
ca0246bb9   Vitaly Wool   z3fold: fix possi...
1195
  	/* Non-headless case */
ca0246bb9   Vitaly Wool   z3fold: fix possi...
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
  	bud = handle_to_buddy(handle);
  
  	switch (bud) {
  	case FIRST:
  		zhdr->first_chunks = 0;
  		break;
  	case MIDDLE:
  		zhdr->middle_chunks = 0;
  		break;
  	case LAST:
  		zhdr->last_chunks = 0;
  		break;
  	default:
  		pr_err("%s: unknown bud %d
  ", __func__, bud);
  		WARN_ON(1);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1212
  		put_z3fold_header(zhdr);
d30561c56   Vitaly Wool   z3fold: use per-c...
1213
1214
  		return;
  	}
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1215
  	if (!page_claimed)
b8b1d4e96   Vitaly Wool   z3fold: simplify ...
1216
  		free_handle(handle, zhdr);
d30561c56   Vitaly Wool   z3fold: use per-c...
1217
1218
1219
1220
  	if (kref_put(&zhdr->refcount, release_z3fold_page_locked_list)) {
  		atomic64_dec(&pool->pages_nr);
  		return;
  	}
5b6807de1   Vitaly Wool   mm/z3fold.c: clai...
1221
1222
  	if (page_claimed) {
  		/* the page has not been claimed by us */
6098d7e13   Vitaly Wool   z3fold: fix recla...
1223
1224
1225
  		z3fold_page_unlock(zhdr);
  		return;
  	}
746d179b0   Vitaly Wool   z3fold: stricter ...
1226
  	if (test_and_set_bit(NEEDS_COMPACTING, &page->private)) {
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1227
  		put_z3fold_header(zhdr);
5b6807de1   Vitaly Wool   mm/z3fold.c: clai...
1228
  		clear_bit(PAGE_CLAIMED, &page->private);
d30561c56   Vitaly Wool   z3fold: use per-c...
1229
1230
1231
  		return;
  	}
  	if (zhdr->cpu < 0 || !cpu_online(zhdr->cpu)) {
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
1232
  		spin_lock(&pool->lock);
d30561c56   Vitaly Wool   z3fold: use per-c...
1233
  		list_del_init(&zhdr->buddy);
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
1234
  		spin_unlock(&pool->lock);
d30561c56   Vitaly Wool   z3fold: use per-c...
1235
  		zhdr->cpu = -1;
5d03a6613   Vitaly Wool   mm/z3fold.c: use ...
1236
  		kref_get(&zhdr->refcount);
5b6807de1   Vitaly Wool   mm/z3fold.c: clai...
1237
  		clear_bit(PAGE_CLAIMED, &page->private);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1238
  		do_compact_page(zhdr, true);
d30561c56   Vitaly Wool   z3fold: use per-c...
1239
  		return;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1240
  	}
5d03a6613   Vitaly Wool   mm/z3fold.c: use ...
1241
  	kref_get(&zhdr->refcount);
5b6807de1   Vitaly Wool   mm/z3fold.c: clai...
1242
  	clear_bit(PAGE_CLAIMED, &page->private);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1243
1244
  	queue_work_on(zhdr->cpu, pool->compact_wq, &zhdr->work);
  	put_z3fold_header(zhdr);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1245
1246
1247
1248
1249
  }
  
  /**
   * z3fold_reclaim_page() - evicts allocations from a pool page and frees it
   * @pool:	pool from which a page will attempt to be evicted
f144c390f   Mike Rapoport   mm: docs: fix par...
1250
   * @retries:	number of pages on the LRU list for which eviction will
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1251
1252
1253
1254
1255
1256
1257
1258
1259
   *		be attempted before failing
   *
   * z3fold reclaim is different from normal system reclaim in that it is done
   * from the bottom, up. This is because only the bottom layer, z3fold, has
   * information on how the allocations are organized within each z3fold page.
   * This has the potential to create interesting locking situations between
   * z3fold and the user, however.
   *
   * To avoid these, this is how z3fold_reclaim_page() should be called:
f144c390f   Mike Rapoport   mm: docs: fix par...
1260
   *
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
   * The user detects a page should be reclaimed and calls z3fold_reclaim_page().
   * z3fold_reclaim_page() will remove a z3fold page from the pool LRU list and
   * call the user-defined eviction handler with the pool and handle as
   * arguments.
   *
   * If the handle can not be evicted, the eviction handler should return
   * non-zero. z3fold_reclaim_page() will add the z3fold page back to the
   * appropriate list and try the next z3fold page on the LRU up to
   * a user defined number of retries.
   *
   * If the handle is successfully evicted, the eviction handler should
   * return 0 _and_ should have called z3fold_free() on the handle. z3fold_free()
   * contains logic to delay freeing the page if the page is under reclaim,
   * as indicated by the setting of the PG_reclaim flag on the underlying page.
   *
   * If all buddies in the z3fold page are successfully evicted, then the
   * z3fold page can be freed.
   *
   * Returns: 0 if page is successfully freed, otherwise -EINVAL if there are
   * no pages to evict or an eviction handler is not registered, -EAGAIN if
   * the retry limit was hit.
   */
  static int z3fold_reclaim_page(struct z3fold_pool *pool, unsigned int retries)
  {
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1285
  	int i, ret = -1;
d30561c56   Vitaly Wool   z3fold: use per-c...
1286
1287
1288
  	struct z3fold_header *zhdr = NULL;
  	struct page *page = NULL;
  	struct list_head *pos;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1289
  	unsigned long first_handle = 0, middle_handle = 0, last_handle = 0;
746d179b0   Vitaly Wool   z3fold: stricter ...
1290
1291
1292
1293
  	struct z3fold_buddy_slots slots __attribute__((aligned(SLOTS_ALIGN)));
  
  	rwlock_init(&slots.lock);
  	slots.pool = (unsigned long)pool | (1 << HANDLES_NOFREE);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1294
1295
  
  	spin_lock(&pool->lock);
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
1296
  	if (!pool->ops || !pool->ops->evict || retries == 0) {
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1297
1298
1299
1300
  		spin_unlock(&pool->lock);
  		return -EINVAL;
  	}
  	for (i = 0; i < retries; i++) {
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
1301
1302
1303
1304
  		if (list_empty(&pool->lru)) {
  			spin_unlock(&pool->lock);
  			return -EINVAL;
  		}
d30561c56   Vitaly Wool   z3fold: use per-c...
1305
1306
  		list_for_each_prev(pos, &pool->lru) {
  			page = list_entry(pos, struct page, lru);
ca0246bb9   Vitaly Wool   z3fold: fix possi...
1307

3f9d2b576   Vitaly Wool   z3fold: fix retry...
1308
  			zhdr = page_address(page);
d30561c56   Vitaly Wool   z3fold: use per-c...
1309
  			if (test_bit(PAGE_HEADLESS, &page->private))
d30561c56   Vitaly Wool   z3fold: use per-c...
1310
  				break;
746d179b0   Vitaly Wool   z3fold: stricter ...
1311
1312
1313
1314
  			if (kref_get_unless_zero(&zhdr->refcount) == 0) {
  				zhdr = NULL;
  				break;
  			}
ca0246bb9   Vitaly Wool   z3fold: fix possi...
1315
  			if (!z3fold_page_trylock(zhdr)) {
746d179b0   Vitaly Wool   z3fold: stricter ...
1316
1317
1318
  				if (kref_put(&zhdr->refcount,
  						release_z3fold_page))
  					atomic64_dec(&pool->pages_nr);
ca0246bb9   Vitaly Wool   z3fold: fix possi...
1319
  				zhdr = NULL;
d30561c56   Vitaly Wool   z3fold: use per-c...
1320
  				continue; /* can't evict at this point */
ca0246bb9   Vitaly Wool   z3fold: fix possi...
1321
  			}
746d179b0   Vitaly Wool   z3fold: stricter ...
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
  
  			/* test_and_set_bit is of course atomic, but we still
  			 * need to do it under page lock, otherwise checking
  			 * that bit in __z3fold_alloc wouldn't make sense
  			 */
  			if (zhdr->foreign_handles ||
  			    test_and_set_bit(PAGE_CLAIMED, &page->private)) {
  				if (kref_put(&zhdr->refcount,
  						release_z3fold_page))
  					atomic64_dec(&pool->pages_nr);
  				else
  					z3fold_page_unlock(zhdr);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1334
1335
1336
  				zhdr = NULL;
  				continue; /* can't evict such page */
  			}
d30561c56   Vitaly Wool   z3fold: use per-c...
1337
1338
  			list_del_init(&zhdr->buddy);
  			zhdr->cpu = -1;
6098d7e13   Vitaly Wool   z3fold: fix recla...
1339
  			break;
d30561c56   Vitaly Wool   z3fold: use per-c...
1340
  		}
ca0246bb9   Vitaly Wool   z3fold: fix possi...
1341
1342
  		if (!zhdr)
  			break;
5a27aa822   Vitaly Wool   z3fold: add kref ...
1343
  		list_del_init(&page->lru);
d30561c56   Vitaly Wool   z3fold: use per-c...
1344
  		spin_unlock(&pool->lock);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1345

9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1346
  		if (!test_bit(PAGE_HEADLESS, &page->private)) {
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1347
  			/*
3f9d2b576   Vitaly Wool   z3fold: fix retry...
1348
1349
1350
1351
  			 * We need encode the handles before unlocking, and
  			 * use our local slots structure because z3fold_free
  			 * can zero out zhdr->slots and we can't do much
  			 * about that
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1352
1353
1354
1355
  			 */
  			first_handle = 0;
  			last_handle = 0;
  			middle_handle = 0;
746d179b0   Vitaly Wool   z3fold: stricter ...
1356
  			memset(slots.slot, 0, sizeof(slots.slot));
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1357
  			if (zhdr->first_chunks)
746d179b0   Vitaly Wool   z3fold: stricter ...
1358
1359
  				first_handle = __encode_handle(zhdr, &slots,
  								FIRST);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1360
  			if (zhdr->middle_chunks)
746d179b0   Vitaly Wool   z3fold: stricter ...
1361
1362
  				middle_handle = __encode_handle(zhdr, &slots,
  								MIDDLE);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1363
  			if (zhdr->last_chunks)
746d179b0   Vitaly Wool   z3fold: stricter ...
1364
1365
  				last_handle = __encode_handle(zhdr, &slots,
  								LAST);
d30561c56   Vitaly Wool   z3fold: use per-c...
1366
1367
1368
1369
  			/*
  			 * it's safe to unlock here because we hold a
  			 * reference to this page
  			 */
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
1370
  			z3fold_page_unlock(zhdr);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1371
  		} else {
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1372
  			first_handle = encode_handle(zhdr, HEADLESS);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1373
1374
  			last_handle = middle_handle = 0;
  		}
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
  		/* Issue the eviction callback(s) */
  		if (middle_handle) {
  			ret = pool->ops->evict(pool, middle_handle);
  			if (ret)
  				goto next;
  		}
  		if (first_handle) {
  			ret = pool->ops->evict(pool, first_handle);
  			if (ret)
  				goto next;
  		}
  		if (last_handle) {
  			ret = pool->ops->evict(pool, last_handle);
  			if (ret)
  				goto next;
  		}
  next:
5a27aa822   Vitaly Wool   z3fold: add kref ...
1392
1393
  		if (test_bit(PAGE_HEADLESS, &page->private)) {
  			if (ret == 0) {
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1394
  				free_z3fold_page(page, true);
ca0246bb9   Vitaly Wool   z3fold: fix possi...
1395
  				atomic64_dec(&pool->pages_nr);
5a27aa822   Vitaly Wool   z3fold: add kref ...
1396
  				return 0;
5a27aa822   Vitaly Wool   z3fold: add kref ...
1397
  			}
6098d7e13   Vitaly Wool   z3fold: fix recla...
1398
1399
1400
  			spin_lock(&pool->lock);
  			list_add(&page->lru, &pool->lru);
  			spin_unlock(&pool->lock);
3f9d2b576   Vitaly Wool   z3fold: fix retry...
1401
  			clear_bit(PAGE_CLAIMED, &page->private);
6098d7e13   Vitaly Wool   z3fold: fix recla...
1402
  		} else {
746d179b0   Vitaly Wool   z3fold: stricter ...
1403
  			struct z3fold_buddy_slots *slots = zhdr->slots;
6098d7e13   Vitaly Wool   z3fold: fix recla...
1404
  			z3fold_page_lock(zhdr);
6098d7e13   Vitaly Wool   z3fold: fix recla...
1405
1406
  			if (kref_put(&zhdr->refcount,
  					release_z3fold_page_locked)) {
746d179b0   Vitaly Wool   z3fold: stricter ...
1407
  				kmem_cache_free(pool->c_handle, slots);
6098d7e13   Vitaly Wool   z3fold: fix recla...
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
  				atomic64_dec(&pool->pages_nr);
  				return 0;
  			}
  			/*
  			 * if we are here, the page is still not completely
  			 * free. Take the global pool lock then to be able
  			 * to add it back to the lru list
  			 */
  			spin_lock(&pool->lock);
  			list_add(&page->lru, &pool->lru);
d5567c9df   Vitaly Wool   z3fold: fix poten...
1418
  			spin_unlock(&pool->lock);
6098d7e13   Vitaly Wool   z3fold: fix recla...
1419
  			z3fold_page_unlock(zhdr);
3f9d2b576   Vitaly Wool   z3fold: fix retry...
1420
  			clear_bit(PAGE_CLAIMED, &page->private);
5a27aa822   Vitaly Wool   z3fold: add kref ...
1421
  		}
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
1422

6098d7e13   Vitaly Wool   z3fold: fix recla...
1423
1424
  		/* We started off locked to we need to lock the pool back */
  		spin_lock(&pool->lock);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
  	}
  	spin_unlock(&pool->lock);
  	return -EAGAIN;
  }
  
  /**
   * z3fold_map() - maps the allocation associated with the given handle
   * @pool:	pool in which the allocation resides
   * @handle:	handle associated with the allocation to be mapped
   *
   * Extracts the buddy number from handle and constructs the pointer to the
   * correct starting chunk within the page.
   *
   * Returns: a pointer to the mapped allocation
   */
  static void *z3fold_map(struct z3fold_pool *pool, unsigned long handle)
  {
  	struct z3fold_header *zhdr;
  	struct page *page;
  	void *addr;
  	enum buddy buddy;
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1446
  	zhdr = get_z3fold_header(handle);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
  	addr = zhdr;
  	page = virt_to_page(zhdr);
  
  	if (test_bit(PAGE_HEADLESS, &page->private))
  		goto out;
  
  	buddy = handle_to_buddy(handle);
  	switch (buddy) {
  	case FIRST:
  		addr += ZHDR_SIZE_ALIGNED;
  		break;
  	case MIDDLE:
  		addr += zhdr->start_middle << CHUNK_SHIFT;
  		set_bit(MIDDLE_CHUNK_MAPPED, &page->private);
  		break;
  	case LAST:
ca0246bb9   Vitaly Wool   z3fold: fix possi...
1463
  		addr += PAGE_SIZE - (handle_to_chunks(handle) << CHUNK_SHIFT);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1464
1465
1466
1467
1468
1469
1470
1471
  		break;
  	default:
  		pr_err("unknown buddy id %d
  ", buddy);
  		WARN_ON(1);
  		addr = NULL;
  		break;
  	}
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
1472

1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1473
1474
  	if (addr)
  		zhdr->mapped_count++;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1475
  out:
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1476
  	put_z3fold_header(zhdr);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
  	return addr;
  }
  
  /**
   * z3fold_unmap() - unmaps the allocation associated with the given handle
   * @pool:	pool in which the allocation resides
   * @handle:	handle associated with the allocation to be unmapped
   */
  static void z3fold_unmap(struct z3fold_pool *pool, unsigned long handle)
  {
  	struct z3fold_header *zhdr;
  	struct page *page;
  	enum buddy buddy;
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1490
  	zhdr = get_z3fold_header(handle);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1491
  	page = virt_to_page(zhdr);
2f1e5e4d8   Vitaly Wool   z3fold: use per-p...
1492
  	if (test_bit(PAGE_HEADLESS, &page->private))
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1493
  		return;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1494
1495
1496
1497
  
  	buddy = handle_to_buddy(handle);
  	if (buddy == MIDDLE)
  		clear_bit(MIDDLE_CHUNK_MAPPED, &page->private);
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1498
  	zhdr->mapped_count--;
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1499
  	put_z3fold_header(zhdr);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1500
1501
1502
1503
1504
1505
  }
  
  /**
   * z3fold_get_pool_size() - gets the z3fold pool size in pages
   * @pool:	pool whose size is being queried
   *
12d59ae67   Vitaly Wool   z3fold: make page...
1506
   * Returns: size in pages of the given pool.
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1507
1508
1509
   */
  static u64 z3fold_get_pool_size(struct z3fold_pool *pool)
  {
12d59ae67   Vitaly Wool   z3fold: make page...
1510
  	return atomic64_read(&pool->pages_nr);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1511
  }
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1512
1513
1514
1515
1516
1517
1518
  static bool z3fold_page_isolate(struct page *page, isolate_mode_t mode)
  {
  	struct z3fold_header *zhdr;
  	struct z3fold_pool *pool;
  
  	VM_BUG_ON_PAGE(!PageMovable(page), page);
  	VM_BUG_ON_PAGE(PageIsolated(page), page);
746d179b0   Vitaly Wool   z3fold: stricter ...
1519
  	if (test_bit(PAGE_HEADLESS, &page->private))
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1520
1521
1522
1523
1524
1525
1526
  		return false;
  
  	zhdr = page_address(page);
  	z3fold_page_lock(zhdr);
  	if (test_bit(NEEDS_COMPACTING, &page->private) ||
  	    test_bit(PAGE_STALE, &page->private))
  		goto out;
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1527
1528
  	if (zhdr->mapped_count != 0 || zhdr->foreign_handles != 0)
  		goto out;
746d179b0   Vitaly Wool   z3fold: stricter ...
1529
1530
  	if (test_and_set_bit(PAGE_CLAIMED, &page->private))
  		goto out;
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1531
  	pool = zhdr_to_pool(zhdr);
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
  	spin_lock(&pool->lock);
  	if (!list_empty(&zhdr->buddy))
  		list_del_init(&zhdr->buddy);
  	if (!list_empty(&page->lru))
  		list_del_init(&page->lru);
  	spin_unlock(&pool->lock);
  
  	kref_get(&zhdr->refcount);
  	z3fold_page_unlock(zhdr);
  	return true;
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1542

1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
  out:
  	z3fold_page_unlock(zhdr);
  	return false;
  }
  
  static int z3fold_page_migrate(struct address_space *mapping, struct page *newpage,
  			       struct page *page, enum migrate_mode mode)
  {
  	struct z3fold_header *zhdr, *new_zhdr;
  	struct z3fold_pool *pool;
  	struct address_space *new_mapping;
  
  	VM_BUG_ON_PAGE(!PageMovable(page), page);
  	VM_BUG_ON_PAGE(!PageIsolated(page), page);
746d179b0   Vitaly Wool   z3fold: stricter ...
1557
  	VM_BUG_ON_PAGE(!test_bit(PAGE_CLAIMED, &page->private), page);
810481a24   Henry Burns   mm/z3fold.c: lock...
1558
  	VM_BUG_ON_PAGE(!PageLocked(newpage), newpage);
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1559
1560
1561
  
  	zhdr = page_address(page);
  	pool = zhdr_to_pool(zhdr);
746d179b0   Vitaly Wool   z3fold: stricter ...
1562
  	if (!z3fold_page_trylock(zhdr))
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1563
  		return -EAGAIN;
4a3ac9311   Vitaly Wool   mm/z3fold.c: add ...
1564
  	if (zhdr->mapped_count != 0 || zhdr->foreign_handles != 0) {
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1565
  		z3fold_page_unlock(zhdr);
746d179b0   Vitaly Wool   z3fold: stricter ...
1566
  		clear_bit(PAGE_CLAIMED, &page->private);
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1567
1568
  		return -EBUSY;
  	}
c92d2f385   Henry Burns   mm/z3fold.c: rein...
1569
1570
1571
1572
  	if (work_pending(&zhdr->work)) {
  		z3fold_page_unlock(zhdr);
  		return -EAGAIN;
  	}
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1573
1574
1575
1576
1577
1578
  	new_zhdr = page_address(newpage);
  	memcpy(new_zhdr, zhdr, PAGE_SIZE);
  	newpage->private = page->private;
  	page->private = 0;
  	z3fold_page_unlock(zhdr);
  	spin_lock_init(&new_zhdr->page_lock);
c92d2f385   Henry Burns   mm/z3fold.c: rein...
1579
1580
1581
1582
1583
1584
  	INIT_WORK(&new_zhdr->work, compact_page_work);
  	/*
  	 * z3fold_page_isolate() ensures that new_zhdr->buddy is empty,
  	 * so we only have to reinitialize it.
  	 */
  	INIT_LIST_HEAD(&new_zhdr->buddy);
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
  	new_mapping = page_mapping(page);
  	__ClearPageMovable(page);
  	ClearPagePrivate(page);
  
  	get_page(newpage);
  	z3fold_page_lock(new_zhdr);
  	if (new_zhdr->first_chunks)
  		encode_handle(new_zhdr, FIRST);
  	if (new_zhdr->last_chunks)
  		encode_handle(new_zhdr, LAST);
  	if (new_zhdr->middle_chunks)
  		encode_handle(new_zhdr, MIDDLE);
  	set_bit(NEEDS_COMPACTING, &newpage->private);
  	new_zhdr->cpu = smp_processor_id();
  	spin_lock(&pool->lock);
  	list_add(&newpage->lru, &pool->lru);
  	spin_unlock(&pool->lock);
  	__SetPageMovable(newpage, new_mapping);
  	z3fold_page_unlock(new_zhdr);
  
  	queue_work_on(new_zhdr->cpu, pool->compact_wq, &new_zhdr->work);
  
  	page_mapcount_reset(page);
746d179b0   Vitaly Wool   z3fold: stricter ...
1608
  	clear_bit(PAGE_CLAIMED, &page->private);
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
  	put_page(page);
  	return 0;
  }
  
  static void z3fold_page_putback(struct page *page)
  {
  	struct z3fold_header *zhdr;
  	struct z3fold_pool *pool;
  
  	zhdr = page_address(page);
  	pool = zhdr_to_pool(zhdr);
  
  	z3fold_page_lock(zhdr);
  	if (!list_empty(&zhdr->buddy))
  		list_del_init(&zhdr->buddy);
  	INIT_LIST_HEAD(&page->lru);
  	if (kref_put(&zhdr->refcount, release_z3fold_page_locked)) {
  		atomic64_dec(&pool->pages_nr);
  		return;
  	}
  	spin_lock(&pool->lock);
  	list_add(&page->lru, &pool->lru);
  	spin_unlock(&pool->lock);
746d179b0   Vitaly Wool   z3fold: stricter ...
1632
  	clear_bit(PAGE_CLAIMED, &page->private);
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1633
1634
1635
1636
1637
1638
1639
1640
  	z3fold_page_unlock(zhdr);
  }
  
  static const struct address_space_operations z3fold_aops = {
  	.isolate_page = z3fold_page_isolate,
  	.migratepage = z3fold_page_migrate,
  	.putback_page = z3fold_page_putback,
  };
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
  /*****************
   * zpool
   ****************/
  
  static int z3fold_zpool_evict(struct z3fold_pool *pool, unsigned long handle)
  {
  	if (pool->zpool && pool->zpool_ops && pool->zpool_ops->evict)
  		return pool->zpool_ops->evict(pool->zpool, handle);
  	else
  		return -ENOENT;
  }
  
  static const struct z3fold_ops z3fold_zpool_ops = {
  	.evict =	z3fold_zpool_evict
  };
  
  static void *z3fold_zpool_create(const char *name, gfp_t gfp,
  			       const struct zpool_ops *zpool_ops,
  			       struct zpool *zpool)
  {
  	struct z3fold_pool *pool;
d30561c56   Vitaly Wool   z3fold: use per-c...
1662
1663
  	pool = z3fold_create_pool(name, gfp,
  				zpool_ops ? &z3fold_zpool_ops : NULL);
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
  	if (pool) {
  		pool->zpool = zpool;
  		pool->zpool_ops = zpool_ops;
  	}
  	return pool;
  }
  
  static void z3fold_zpool_destroy(void *pool)
  {
  	z3fold_destroy_pool(pool);
  }
  
  static int z3fold_zpool_malloc(void *pool, size_t size, gfp_t gfp,
  			unsigned long *handle)
  {
  	return z3fold_alloc(pool, size, gfp, handle);
  }
  static void z3fold_zpool_free(void *pool, unsigned long handle)
  {
  	z3fold_free(pool, handle);
  }
  
  static int z3fold_zpool_shrink(void *pool, unsigned int pages,
  			unsigned int *reclaimed)
  {
  	unsigned int total = 0;
  	int ret = -EINVAL;
  
  	while (total < pages) {
  		ret = z3fold_reclaim_page(pool, 8);
  		if (ret < 0)
  			break;
  		total++;
  	}
  
  	if (reclaimed)
  		*reclaimed = total;
  
  	return ret;
  }
  
  static void *z3fold_zpool_map(void *pool, unsigned long handle,
  			enum zpool_mapmode mm)
  {
  	return z3fold_map(pool, handle);
  }
  static void z3fold_zpool_unmap(void *pool, unsigned long handle)
  {
  	z3fold_unmap(pool, handle);
  }
  
  static u64 z3fold_zpool_total_size(void *pool)
  {
  	return z3fold_get_pool_size(pool) * PAGE_SIZE;
  }
  
  static struct zpool_driver z3fold_zpool_driver = {
  	.type =		"z3fold",
  	.owner =	THIS_MODULE,
  	.create =	z3fold_zpool_create,
  	.destroy =	z3fold_zpool_destroy,
  	.malloc =	z3fold_zpool_malloc,
  	.free =		z3fold_zpool_free,
  	.shrink =	z3fold_zpool_shrink,
  	.map =		z3fold_zpool_map,
  	.unmap =	z3fold_zpool_unmap,
  	.total_size =	z3fold_zpool_total_size,
  };
  
  MODULE_ALIAS("zpool-z3fold");
  
  static int __init init_z3fold(void)
  {
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1737
  	int ret;
ede93213a   Vitaly Wool   z3fold: fix heade...
1738
1739
  	/* Make sure the z3fold header is not larger than the page size */
  	BUILD_BUG_ON(ZHDR_SIZE_ALIGNED > PAGE_SIZE);
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1740
1741
1742
  	ret = z3fold_mount();
  	if (ret)
  		return ret;
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1743
1744
1745
1746
1747
1748
1749
  	zpool_register_driver(&z3fold_zpool_driver);
  
  	return 0;
  }
  
  static void __exit exit_z3fold(void)
  {
1f862989b   Vitaly Wool   mm/z3fold.c: supp...
1750
  	z3fold_unmount();
9a001fc19   Vitaly Wool   z3fold: the 3-fol...
1751
1752
1753
1754
1755
1756
1757
1758
1759
  	zpool_unregister_driver(&z3fold_zpool_driver);
  }
  
  module_init(init_z3fold);
  module_exit(exit_z3fold);
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Vitaly Wool <vitalywool@gmail.com>");
  MODULE_DESCRIPTION("3-Fold Allocator for Compressed Pages");