Blame view

mm/zsmalloc.c 59.4 KB
61989a80f   Nitin Gupta   staging: zsmalloc...
1
2
3
4
  /*
   * zsmalloc memory allocator
   *
   * Copyright (C) 2011  Nitin Gupta
31fc00bb7   Minchan Kim   zsmalloc: add cop...
5
   * Copyright (C) 2012, 2013 Minchan Kim
61989a80f   Nitin Gupta   staging: zsmalloc...
6
7
8
9
10
11
12
   *
   * This code is released using a dual license strategy: BSD/GPL
   * You can choose the license that better fits your requirements.
   *
   * Released under the terms of 3-clause BSD License
   * Released under the terms of GNU General Public License Version 2.0
   */
2db51dae5   Nitin Gupta   staging: zsmalloc...
13
  /*
2db51dae5   Nitin Gupta   staging: zsmalloc...
14
15
16
17
   * Following is how we use various fields and flags of underlying
   * struct page(s) to form a zspage.
   *
   * Usage of struct page fields:
3783689a1   Minchan Kim   zsmalloc: introdu...
18
   *	page->private: points to zspage
48b4800a1   Minchan Kim   zsmalloc: page mi...
19
20
21
   *	page->freelist(index): links together all component pages of a zspage
   *		For the huge page, this is always 0, so we use this field
   *		to store handle.
fd8544639   Ganesh Mahendran   mm/zsmalloc: keep...
22
   *	page->units: first object offset in a subpage of zspage
2db51dae5   Nitin Gupta   staging: zsmalloc...
23
24
25
   *
   * Usage of struct page flags:
   *	PG_private: identifies the first component page
399d8eebe   Xishi Qiu   mm: fix some typo...
26
   *	PG_owner_priv_1: identifies the huge component page
2db51dae5   Nitin Gupta   staging: zsmalloc...
27
28
   *
   */
4abaac9b7   Dan Streetman   update "mm/zsmall...
29
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
61989a80f   Nitin Gupta   staging: zsmalloc...
30
31
  #include <linux/module.h>
  #include <linux/kernel.h>
312fcae22   Minchan Kim   zsmalloc: support...
32
  #include <linux/sched.h>
50d34394c   Ingo Molnar   sched/headers: Pr...
33
  #include <linux/magic.h>
61989a80f   Nitin Gupta   staging: zsmalloc...
34
35
36
  #include <linux/bitops.h>
  #include <linux/errno.h>
  #include <linux/highmem.h>
61989a80f   Nitin Gupta   staging: zsmalloc...
37
38
39
40
41
42
  #include <linux/string.h>
  #include <linux/slab.h>
  #include <asm/tlbflush.h>
  #include <asm/pgtable.h>
  #include <linux/cpumask.h>
  #include <linux/cpu.h>
0cbb613fa   Seth Jennings   staging: fix powe...
43
  #include <linux/vmalloc.h>
759b26b29   Sergey Senozhatsky   zsmalloc: use pre...
44
  #include <linux/preempt.h>
0959c63f1   Seth Jennings   zsmalloc: collaps...
45
46
  #include <linux/spinlock.h>
  #include <linux/types.h>
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
47
  #include <linux/debugfs.h>
bcf1647d0   Minchan Kim   zsmalloc: move it...
48
  #include <linux/zsmalloc.h>
c795779df   Dan Streetman   mm/zpool: zbud/zs...
49
  #include <linux/zpool.h>
48b4800a1   Minchan Kim   zsmalloc: page mi...
50
  #include <linux/mount.h>
dd4123f32   Minchan Kim   mm: fix build war...
51
  #include <linux/migrate.h>
48b4800a1   Minchan Kim   zsmalloc: page mi...
52
53
54
  #include <linux/pagemap.h>
  
  #define ZSPAGE_MAGIC	0x58
0959c63f1   Seth Jennings   zsmalloc: collaps...
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  
  /*
   * This must be power of 2 and greater than of equal to sizeof(link_free).
   * These two conditions ensure that any 'struct link_free' itself doesn't
   * span more than 1 page which avoids complex case of mapping 2 pages simply
   * to restore link_free pointer values.
   */
  #define ZS_ALIGN		8
  
  /*
   * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
   * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
   */
  #define ZS_MAX_ZSPAGE_ORDER 2
  #define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
2e40e163a   Minchan Kim   zsmalloc: decoupl...
70
  #define ZS_HANDLE_SIZE (sizeof(unsigned long))
0959c63f1   Seth Jennings   zsmalloc: collaps...
71
72
  /*
   * Object location (<PFN>, <obj_idx>) is encoded as
c3e3e88ad   Nitin Cupta   zsmalloc: add mor...
73
   * as single (unsigned long) handle value.
0959c63f1   Seth Jennings   zsmalloc: collaps...
74
   *
bfd093f5e   Minchan Kim   zsmalloc: use fre...
75
   * Note that object index <obj_idx> starts from 0.
0959c63f1   Seth Jennings   zsmalloc: collaps...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
   *
   * This is made more complicated by various memory models and PAE.
   */
  
  #ifndef MAX_PHYSMEM_BITS
  #ifdef CONFIG_HIGHMEM64G
  #define MAX_PHYSMEM_BITS 36
  #else /* !CONFIG_HIGHMEM64G */
  /*
   * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
   * be PAGE_SHIFT
   */
  #define MAX_PHYSMEM_BITS BITS_PER_LONG
  #endif
  #endif
  #define _PFN_BITS		(MAX_PHYSMEM_BITS - PAGE_SHIFT)
312fcae22   Minchan Kim   zsmalloc: support...
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  
  /*
   * Memory for allocating for handle keeps object position by
   * encoding <page, obj_idx> and the encoded value has a room
   * in least bit(ie, look at obj_to_location).
   * We use the bit to synchronize between object access by
   * user and migration.
   */
  #define HANDLE_PIN_BIT	0
  
  /*
   * Head in allocated object should have OBJ_ALLOCATED_TAG
   * to identify the object was allocated or not.
   * It's okay to add the status bit in the least bit because
   * header keeps handle which is 4byte-aligned address so we
   * have room for two bit at least.
   */
  #define OBJ_ALLOCATED_TAG 1
  #define OBJ_TAG_BITS 1
  #define OBJ_INDEX_BITS	(BITS_PER_LONG - _PFN_BITS - OBJ_TAG_BITS)
0959c63f1   Seth Jennings   zsmalloc: collaps...
112
  #define OBJ_INDEX_MASK	((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
cf8e0fedf   Jerome Marchand   mm/zsmalloc: simp...
113
114
115
116
  #define FULLNESS_BITS	2
  #define CLASS_BITS	8
  #define ISOLATED_BITS	3
  #define MAGIC_VAL_BITS	8
0959c63f1   Seth Jennings   zsmalloc: collaps...
117
118
119
120
  #define MAX(a, b) ((a) >= (b) ? (a) : (b))
  /* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
  #define ZS_MIN_ALLOC_SIZE \
  	MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
2e40e163a   Minchan Kim   zsmalloc: decoupl...
121
  /* each chunk includes extra space to keep handle */
7b60a6852   Minchan Kim   zsmalloc: record ...
122
  #define ZS_MAX_ALLOC_SIZE	PAGE_SIZE
0959c63f1   Seth Jennings   zsmalloc: collaps...
123
124
  
  /*
7eb52512a   Weijie Yang   zsmalloc: fixup t...
125
   * On systems with 4K page size, this gives 255 size classes! There is a
0959c63f1   Seth Jennings   zsmalloc: collaps...
126
127
128
129
130
131
132
133
134
135
136
   * trader-off here:
   *  - Large number of size classes is potentially wasteful as free page are
   *    spread across these classes
   *  - Small number of size classes causes large internal fragmentation
   *  - Probably its better to use specific size classes (empirically
   *    determined). NOTE: all those class sizes must be set as multiple of
   *    ZS_ALIGN to make sure link_free itself never has to span 2 pages.
   *
   *  ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
   *  (reason above)
   */
3783689a1   Minchan Kim   zsmalloc: introdu...
137
  #define ZS_SIZE_CLASS_DELTA	(PAGE_SIZE >> CLASS_BITS)
cf8e0fedf   Jerome Marchand   mm/zsmalloc: simp...
138
139
  #define ZS_SIZE_CLASSES	(DIV_ROUND_UP(ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE, \
  				      ZS_SIZE_CLASS_DELTA) + 1)
0959c63f1   Seth Jennings   zsmalloc: collaps...
140

0959c63f1   Seth Jennings   zsmalloc: collaps...
141
  enum fullness_group {
0959c63f1   Seth Jennings   zsmalloc: collaps...
142
  	ZS_EMPTY,
48b4800a1   Minchan Kim   zsmalloc: page mi...
143
144
145
146
  	ZS_ALMOST_EMPTY,
  	ZS_ALMOST_FULL,
  	ZS_FULL,
  	NR_ZS_FULLNESS,
0959c63f1   Seth Jennings   zsmalloc: collaps...
147
  };
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
148
  enum zs_stat_type {
48b4800a1   Minchan Kim   zsmalloc: page mi...
149
150
151
152
  	CLASS_EMPTY,
  	CLASS_ALMOST_EMPTY,
  	CLASS_ALMOST_FULL,
  	CLASS_FULL,
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
153
154
  	OBJ_ALLOCATED,
  	OBJ_USED,
48b4800a1   Minchan Kim   zsmalloc: page mi...
155
  	NR_ZS_STAT_TYPE,
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
156
  };
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
157
158
159
  struct zs_size_stat {
  	unsigned long objs[NR_ZS_STAT_TYPE];
  };
572445941   Sergey Senozhatsky   zsmalloc: always ...
160
161
  #ifdef CONFIG_ZSMALLOC_STAT
  static struct dentry *zs_stat_root;
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
162
  #endif
48b4800a1   Minchan Kim   zsmalloc: page mi...
163
164
165
  #ifdef CONFIG_COMPACTION
  static struct vfsmount *zsmalloc_mnt;
  #endif
0959c63f1   Seth Jennings   zsmalloc: collaps...
166
167
168
169
170
  /*
   * We assign a page to ZS_ALMOST_EMPTY fullness group when:
   *	n <= N / f, where
   * n = number of allocated objects
   * N = total number of objects zspage can store
6dd9737e3   Wang Sheng-Hui   mm/zsmalloc.c: co...
171
   * f = fullness_threshold_frac
0959c63f1   Seth Jennings   zsmalloc: collaps...
172
173
174
175
176
177
178
179
180
181
182
   *
   * Similarly, we assign zspage to:
   *	ZS_ALMOST_FULL	when n > N / f
   *	ZS_EMPTY	when n == 0
   *	ZS_FULL		when n == N
   *
   * (see: fix_fullness_group())
   */
  static const int fullness_threshold_frac = 4;
  
  struct size_class {
572445941   Sergey Senozhatsky   zsmalloc: always ...
183
  	spinlock_t lock;
48b4800a1   Minchan Kim   zsmalloc: page mi...
184
  	struct list_head fullness_list[NR_ZS_FULLNESS];
0959c63f1   Seth Jennings   zsmalloc: collaps...
185
186
187
188
189
  	/*
  	 * Size of objects stored in this class. Must be multiple
  	 * of ZS_ALIGN.
  	 */
  	int size;
1fc6e27d7   Minchan Kim   zsmalloc: keep ma...
190
  	int objs_per_zspage;
7dfa46122   Weijie Yang   zsmalloc: reorgan...
191
192
  	/* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
  	int pages_per_zspage;
48b4800a1   Minchan Kim   zsmalloc: page mi...
193
194
195
  
  	unsigned int index;
  	struct zs_size_stat stats;
0959c63f1   Seth Jennings   zsmalloc: collaps...
196
  };
48b4800a1   Minchan Kim   zsmalloc: page mi...
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  /* huge object: pages_per_zspage == 1 && maxobj_per_zspage == 1 */
  static void SetPageHugeObject(struct page *page)
  {
  	SetPageOwnerPriv1(page);
  }
  
  static void ClearPageHugeObject(struct page *page)
  {
  	ClearPageOwnerPriv1(page);
  }
  
  static int PageHugeObject(struct page *page)
  {
  	return PageOwnerPriv1(page);
  }
0959c63f1   Seth Jennings   zsmalloc: collaps...
212
213
  /*
   * Placed within free objects to form a singly linked list.
3783689a1   Minchan Kim   zsmalloc: introdu...
214
   * For every zspage, zspage->freeobj gives head of this list.
0959c63f1   Seth Jennings   zsmalloc: collaps...
215
216
217
218
   *
   * This must be power of 2 and less than or equal to ZS_ALIGN
   */
  struct link_free {
2e40e163a   Minchan Kim   zsmalloc: decoupl...
219
220
  	union {
  		/*
bfd093f5e   Minchan Kim   zsmalloc: use fre...
221
  		 * Free object index;
2e40e163a   Minchan Kim   zsmalloc: decoupl...
222
223
  		 * It's valid for non-allocated object
  		 */
bfd093f5e   Minchan Kim   zsmalloc: use fre...
224
  		unsigned long next;
2e40e163a   Minchan Kim   zsmalloc: decoupl...
225
226
227
228
229
  		/*
  		 * Handle of allocated object.
  		 */
  		unsigned long handle;
  	};
0959c63f1   Seth Jennings   zsmalloc: collaps...
230
231
232
  };
  
  struct zs_pool {
6f3526d6d   Sergey SENOZHATSKY   mm: zsmalloc: con...
233
  	const char *name;
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
234

cf8e0fedf   Jerome Marchand   mm/zsmalloc: simp...
235
  	struct size_class *size_class[ZS_SIZE_CLASSES];
2e40e163a   Minchan Kim   zsmalloc: decoupl...
236
  	struct kmem_cache *handle_cachep;
3783689a1   Minchan Kim   zsmalloc: introdu...
237
  	struct kmem_cache *zspage_cachep;
0959c63f1   Seth Jennings   zsmalloc: collaps...
238

13de8933c   Minchan Kim   zsmalloc: move pa...
239
  	atomic_long_t pages_allocated;
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
240

7d3f39382   Sergey Senozhatsky   zsmalloc/zram: in...
241
  	struct zs_pool_stats stats;
ab9d306d9   Sergey Senozhatsky   zsmalloc: use shr...
242
243
244
245
246
247
248
249
  
  	/* Compact classes */
  	struct shrinker shrinker;
  	/*
  	 * To signify that register_shrinker() was successful
  	 * and unregister_shrinker() will not Oops.
  	 */
  	bool shrinker_enabled;
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
250
251
252
  #ifdef CONFIG_ZSMALLOC_STAT
  	struct dentry *stat_dentry;
  #endif
48b4800a1   Minchan Kim   zsmalloc: page mi...
253
254
255
256
  #ifdef CONFIG_COMPACTION
  	struct inode *inode;
  	struct work_struct free_work;
  #endif
0959c63f1   Seth Jennings   zsmalloc: collaps...
257
  };
61989a80f   Nitin Gupta   staging: zsmalloc...
258

3783689a1   Minchan Kim   zsmalloc: introdu...
259
260
261
  struct zspage {
  	struct {
  		unsigned int fullness:FULLNESS_BITS;
85d492f28   Minchan Kim   zsmalloc: expand ...
262
  		unsigned int class:CLASS_BITS + 1;
48b4800a1   Minchan Kim   zsmalloc: page mi...
263
264
  		unsigned int isolated:ISOLATED_BITS;
  		unsigned int magic:MAGIC_VAL_BITS;
3783689a1   Minchan Kim   zsmalloc: introdu...
265
266
  	};
  	unsigned int inuse;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
267
  	unsigned int freeobj;
3783689a1   Minchan Kim   zsmalloc: introdu...
268
269
  	struct page *first_page;
  	struct list_head list; /* fullness list */
48b4800a1   Minchan Kim   zsmalloc: page mi...
270
271
272
  #ifdef CONFIG_COMPACTION
  	rwlock_t lock;
  #endif
3783689a1   Minchan Kim   zsmalloc: introdu...
273
  };
61989a80f   Nitin Gupta   staging: zsmalloc...
274

f553646a6   Seth Jennings   staging: zsmalloc...
275
  struct mapping_area {
1b945aeef   Minchan Kim   zsmalloc: add Kco...
276
  #ifdef CONFIG_PGTABLE_MAPPING
f553646a6   Seth Jennings   staging: zsmalloc...
277
278
279
280
281
282
283
  	struct vm_struct *vm; /* vm area for mapping object that span pages */
  #else
  	char *vm_buf; /* copy buffer for objects that span pages */
  #endif
  	char *vm_addr; /* address of kmap_atomic()'ed pages */
  	enum zs_mapmode vm_mm; /* mapping mode */
  };
48b4800a1   Minchan Kim   zsmalloc: page mi...
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  #ifdef CONFIG_COMPACTION
  static int zs_register_migration(struct zs_pool *pool);
  static void zs_unregister_migration(struct zs_pool *pool);
  static void migrate_lock_init(struct zspage *zspage);
  static void migrate_read_lock(struct zspage *zspage);
  static void migrate_read_unlock(struct zspage *zspage);
  static void kick_deferred_free(struct zs_pool *pool);
  static void init_deferred_free(struct zs_pool *pool);
  static void SetZsPageMovable(struct zs_pool *pool, struct zspage *zspage);
  #else
  static int zsmalloc_mount(void) { return 0; }
  static void zsmalloc_unmount(void) {}
  static int zs_register_migration(struct zs_pool *pool) { return 0; }
  static void zs_unregister_migration(struct zs_pool *pool) {}
  static void migrate_lock_init(struct zspage *zspage) {}
  static void migrate_read_lock(struct zspage *zspage) {}
  static void migrate_read_unlock(struct zspage *zspage) {}
  static void kick_deferred_free(struct zs_pool *pool) {}
  static void init_deferred_free(struct zs_pool *pool) {}
  static void SetZsPageMovable(struct zs_pool *pool, struct zspage *zspage) {}
  #endif
3783689a1   Minchan Kim   zsmalloc: introdu...
305
  static int create_cache(struct zs_pool *pool)
2e40e163a   Minchan Kim   zsmalloc: decoupl...
306
307
308
  {
  	pool->handle_cachep = kmem_cache_create("zs_handle", ZS_HANDLE_SIZE,
  					0, 0, NULL);
3783689a1   Minchan Kim   zsmalloc: introdu...
309
310
311
312
313
314
315
316
317
318
319
320
  	if (!pool->handle_cachep)
  		return 1;
  
  	pool->zspage_cachep = kmem_cache_create("zspage", sizeof(struct zspage),
  					0, 0, NULL);
  	if (!pool->zspage_cachep) {
  		kmem_cache_destroy(pool->handle_cachep);
  		pool->handle_cachep = NULL;
  		return 1;
  	}
  
  	return 0;
2e40e163a   Minchan Kim   zsmalloc: decoupl...
321
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
322
  static void destroy_cache(struct zs_pool *pool)
2e40e163a   Minchan Kim   zsmalloc: decoupl...
323
  {
cd10add00   Sergey Senozhatsky   zsmalloc: remove ...
324
  	kmem_cache_destroy(pool->handle_cachep);
3783689a1   Minchan Kim   zsmalloc: introdu...
325
  	kmem_cache_destroy(pool->zspage_cachep);
2e40e163a   Minchan Kim   zsmalloc: decoupl...
326
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
327
  static unsigned long cache_alloc_handle(struct zs_pool *pool, gfp_t gfp)
2e40e163a   Minchan Kim   zsmalloc: decoupl...
328
329
  {
  	return (unsigned long)kmem_cache_alloc(pool->handle_cachep,
48b4800a1   Minchan Kim   zsmalloc: page mi...
330
  			gfp & ~(__GFP_HIGHMEM|__GFP_MOVABLE));
2e40e163a   Minchan Kim   zsmalloc: decoupl...
331
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
332
  static void cache_free_handle(struct zs_pool *pool, unsigned long handle)
2e40e163a   Minchan Kim   zsmalloc: decoupl...
333
334
335
  {
  	kmem_cache_free(pool->handle_cachep, (void *)handle);
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
336
337
  static struct zspage *cache_alloc_zspage(struct zs_pool *pool, gfp_t flags)
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
338
339
  	return kmem_cache_alloc(pool->zspage_cachep,
  			flags & ~(__GFP_HIGHMEM|__GFP_MOVABLE));
399d8eebe   Xishi Qiu   mm: fix some typo...
340
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
341
342
343
344
345
  
  static void cache_free_zspage(struct zs_pool *pool, struct zspage *zspage)
  {
  	kmem_cache_free(pool->zspage_cachep, zspage);
  }
2e40e163a   Minchan Kim   zsmalloc: decoupl...
346
347
  static void record_obj(unsigned long handle, unsigned long obj)
  {
c102f07ca   Junil Lee   zsmalloc: fix mig...
348
349
350
351
352
353
  	/*
  	 * lsb of @obj represents handle lock while other bits
  	 * represent object value the handle is pointing so
  	 * updating shouldn't do store tearing.
  	 */
  	WRITE_ONCE(*(unsigned long *)handle, obj);
2e40e163a   Minchan Kim   zsmalloc: decoupl...
354
  }
c795779df   Dan Streetman   mm/zpool: zbud/zs...
355
356
357
  /* zpool driver */
  
  #ifdef CONFIG_ZPOOL
6f3526d6d   Sergey SENOZHATSKY   mm: zsmalloc: con...
358
  static void *zs_zpool_create(const char *name, gfp_t gfp,
786727799   Krzysztof Kozlowski   mm: zpool: consti...
359
  			     const struct zpool_ops *zpool_ops,
479305fd7   Dan Streetman   zpool: remove zpo...
360
  			     struct zpool *zpool)
c795779df   Dan Streetman   mm/zpool: zbud/zs...
361
  {
d0d8da2dc   Sergey Senozhatsky   zsmalloc: require...
362
363
364
365
366
367
  	/*
  	 * Ignore global gfp flags: zs_malloc() may be invoked from
  	 * different contexts and its caller must provide a valid
  	 * gfp mask.
  	 */
  	return zs_create_pool(name);
c795779df   Dan Streetman   mm/zpool: zbud/zs...
368
369
370
371
372
373
374
375
376
377
  }
  
  static void zs_zpool_destroy(void *pool)
  {
  	zs_destroy_pool(pool);
  }
  
  static int zs_zpool_malloc(void *pool, size_t size, gfp_t gfp,
  			unsigned long *handle)
  {
d0d8da2dc   Sergey Senozhatsky   zsmalloc: require...
378
  	*handle = zs_malloc(pool, size, gfp);
c795779df   Dan Streetman   mm/zpool: zbud/zs...
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
  	return *handle ? 0 : -1;
  }
  static void zs_zpool_free(void *pool, unsigned long handle)
  {
  	zs_free(pool, handle);
  }
  
  static int zs_zpool_shrink(void *pool, unsigned int pages,
  			unsigned int *reclaimed)
  {
  	return -EINVAL;
  }
  
  static void *zs_zpool_map(void *pool, unsigned long handle,
  			enum zpool_mapmode mm)
  {
  	enum zs_mapmode zs_mm;
  
  	switch (mm) {
  	case ZPOOL_MM_RO:
  		zs_mm = ZS_MM_RO;
  		break;
  	case ZPOOL_MM_WO:
  		zs_mm = ZS_MM_WO;
  		break;
  	case ZPOOL_MM_RW: /* fallthru */
  	default:
  		zs_mm = ZS_MM_RW;
  		break;
  	}
  
  	return zs_map_object(pool, handle, zs_mm);
  }
  static void zs_zpool_unmap(void *pool, unsigned long handle)
  {
  	zs_unmap_object(pool, handle);
  }
  
  static u64 zs_zpool_total_size(void *pool)
  {
722cdc172   Minchan Kim   zsmalloc: change ...
419
  	return zs_get_total_pages(pool) << PAGE_SHIFT;
c795779df   Dan Streetman   mm/zpool: zbud/zs...
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  }
  
  static struct zpool_driver zs_zpool_driver = {
  	.type =		"zsmalloc",
  	.owner =	THIS_MODULE,
  	.create =	zs_zpool_create,
  	.destroy =	zs_zpool_destroy,
  	.malloc =	zs_zpool_malloc,
  	.free =		zs_zpool_free,
  	.shrink =	zs_zpool_shrink,
  	.map =		zs_zpool_map,
  	.unmap =	zs_zpool_unmap,
  	.total_size =	zs_zpool_total_size,
  };
137f8cff5   Kees Cook   mm/zpool: use pre...
434
  MODULE_ALIAS("zpool-zsmalloc");
c795779df   Dan Streetman   mm/zpool: zbud/zs...
435
  #endif /* CONFIG_ZPOOL */
61989a80f   Nitin Gupta   staging: zsmalloc...
436
437
  /* per-cpu VM mapping areas for zspage accesses that cross page boundaries */
  static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
48b4800a1   Minchan Kim   zsmalloc: page mi...
438
439
440
441
  static bool is_zspage_isolated(struct zspage *zspage)
  {
  	return zspage->isolated;
  }
3457f4147   Nick Desaulniers   mm/zsmalloc.c: fi...
442
  static __maybe_unused int is_first_page(struct page *page)
61989a80f   Nitin Gupta   staging: zsmalloc...
443
  {
a27545bf0   Minchan Kim   zsmalloc: use Pag...
444
  	return PagePrivate(page);
61989a80f   Nitin Gupta   staging: zsmalloc...
445
  }
48b4800a1   Minchan Kim   zsmalloc: page mi...
446
  /* Protected by class->lock */
3783689a1   Minchan Kim   zsmalloc: introdu...
447
  static inline int get_zspage_inuse(struct zspage *zspage)
4f42047bb   Minchan Kim   zsmalloc: use acc...
448
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
449
  	return zspage->inuse;
4f42047bb   Minchan Kim   zsmalloc: use acc...
450
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
451
  static inline void set_zspage_inuse(struct zspage *zspage, int val)
4f42047bb   Minchan Kim   zsmalloc: use acc...
452
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
453
  	zspage->inuse = val;
4f42047bb   Minchan Kim   zsmalloc: use acc...
454
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
455
  static inline void mod_zspage_inuse(struct zspage *zspage, int val)
4f42047bb   Minchan Kim   zsmalloc: use acc...
456
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
457
  	zspage->inuse += val;
4f42047bb   Minchan Kim   zsmalloc: use acc...
458
  }
48b4800a1   Minchan Kim   zsmalloc: page mi...
459
  static inline struct page *get_first_page(struct zspage *zspage)
4f42047bb   Minchan Kim   zsmalloc: use acc...
460
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
461
  	struct page *first_page = zspage->first_page;
3783689a1   Minchan Kim   zsmalloc: introdu...
462

48b4800a1   Minchan Kim   zsmalloc: page mi...
463
464
  	VM_BUG_ON_PAGE(!is_first_page(first_page), first_page);
  	return first_page;
4f42047bb   Minchan Kim   zsmalloc: use acc...
465
  }
48b4800a1   Minchan Kim   zsmalloc: page mi...
466
  static inline int get_first_obj_offset(struct page *page)
4f42047bb   Minchan Kim   zsmalloc: use acc...
467
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
468
469
  	return page->units;
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
470

48b4800a1   Minchan Kim   zsmalloc: page mi...
471
472
473
  static inline void set_first_obj_offset(struct page *page, int offset)
  {
  	page->units = offset;
4f42047bb   Minchan Kim   zsmalloc: use acc...
474
  }
bfd093f5e   Minchan Kim   zsmalloc: use fre...
475
  static inline unsigned int get_freeobj(struct zspage *zspage)
4f42047bb   Minchan Kim   zsmalloc: use acc...
476
  {
bfd093f5e   Minchan Kim   zsmalloc: use fre...
477
  	return zspage->freeobj;
4f42047bb   Minchan Kim   zsmalloc: use acc...
478
  }
bfd093f5e   Minchan Kim   zsmalloc: use fre...
479
  static inline void set_freeobj(struct zspage *zspage, unsigned int obj)
4f42047bb   Minchan Kim   zsmalloc: use acc...
480
  {
bfd093f5e   Minchan Kim   zsmalloc: use fre...
481
  	zspage->freeobj = obj;
4f42047bb   Minchan Kim   zsmalloc: use acc...
482
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
483
  static void get_zspage_mapping(struct zspage *zspage,
a42094676   Minchan Kim   zsmalloc: use fir...
484
  				unsigned int *class_idx,
61989a80f   Nitin Gupta   staging: zsmalloc...
485
486
  				enum fullness_group *fullness)
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
487
  	BUG_ON(zspage->magic != ZSPAGE_MAGIC);
3783689a1   Minchan Kim   zsmalloc: introdu...
488
489
  	*fullness = zspage->fullness;
  	*class_idx = zspage->class;
61989a80f   Nitin Gupta   staging: zsmalloc...
490
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
491
  static void set_zspage_mapping(struct zspage *zspage,
a42094676   Minchan Kim   zsmalloc: use fir...
492
  				unsigned int class_idx,
61989a80f   Nitin Gupta   staging: zsmalloc...
493
494
  				enum fullness_group fullness)
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
495
496
  	zspage->class = class_idx;
  	zspage->fullness = fullness;
61989a80f   Nitin Gupta   staging: zsmalloc...
497
  }
c3e3e88ad   Nitin Cupta   zsmalloc: add mor...
498
499
500
501
502
503
504
  /*
   * zsmalloc divides the pool into various size classes where each
   * class maintains a list of zspages where each zspage is divided
   * into equal sized chunks. Each allocation falls into one of these
   * classes depending on its size. This function returns index of the
   * size class which has chunk size big enough to hold the give size.
   */
61989a80f   Nitin Gupta   staging: zsmalloc...
505
506
507
508
509
510
511
  static int get_size_class_index(int size)
  {
  	int idx = 0;
  
  	if (likely(size > ZS_MIN_ALLOC_SIZE))
  		idx = DIV_ROUND_UP(size - ZS_MIN_ALLOC_SIZE,
  				ZS_SIZE_CLASS_DELTA);
cf8e0fedf   Jerome Marchand   mm/zsmalloc: simp...
512
  	return min_t(int, ZS_SIZE_CLASSES - 1, idx);
61989a80f   Nitin Gupta   staging: zsmalloc...
513
  }
3eb95feac   Matthias Kaehlcke   mm/zsmalloc.c: ch...
514
  /* type can be of enum type zs_stat_type or fullness_group */
248ca1b05   Minchan Kim   zsmalloc: add ful...
515
  static inline void zs_stat_inc(struct size_class *class,
3eb95feac   Matthias Kaehlcke   mm/zsmalloc.c: ch...
516
  				int type, unsigned long cnt)
248ca1b05   Minchan Kim   zsmalloc: add ful...
517
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
518
  	class->stats.objs[type] += cnt;
248ca1b05   Minchan Kim   zsmalloc: add ful...
519
  }
3eb95feac   Matthias Kaehlcke   mm/zsmalloc.c: ch...
520
  /* type can be of enum type zs_stat_type or fullness_group */
248ca1b05   Minchan Kim   zsmalloc: add ful...
521
  static inline void zs_stat_dec(struct size_class *class,
3eb95feac   Matthias Kaehlcke   mm/zsmalloc.c: ch...
522
  				int type, unsigned long cnt)
248ca1b05   Minchan Kim   zsmalloc: add ful...
523
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
524
  	class->stats.objs[type] -= cnt;
248ca1b05   Minchan Kim   zsmalloc: add ful...
525
  }
3eb95feac   Matthias Kaehlcke   mm/zsmalloc.c: ch...
526
  /* type can be of enum type zs_stat_type or fullness_group */
248ca1b05   Minchan Kim   zsmalloc: add ful...
527
  static inline unsigned long zs_stat_get(struct size_class *class,
3eb95feac   Matthias Kaehlcke   mm/zsmalloc.c: ch...
528
  				int type)
248ca1b05   Minchan Kim   zsmalloc: add ful...
529
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
530
  	return class->stats.objs[type];
248ca1b05   Minchan Kim   zsmalloc: add ful...
531
  }
572445941   Sergey Senozhatsky   zsmalloc: always ...
532
  #ifdef CONFIG_ZSMALLOC_STAT
4abaac9b7   Dan Streetman   update "mm/zsmall...
533
  static void __init zs_stat_init(void)
248ca1b05   Minchan Kim   zsmalloc: add ful...
534
  {
4abaac9b7   Dan Streetman   update "mm/zsmall...
535
536
537
538
539
  	if (!debugfs_initialized()) {
  		pr_warn("debugfs not available, stat dir not created
  ");
  		return;
  	}
248ca1b05   Minchan Kim   zsmalloc: add ful...
540
541
542
  
  	zs_stat_root = debugfs_create_dir("zsmalloc", NULL);
  	if (!zs_stat_root)
4abaac9b7   Dan Streetman   update "mm/zsmall...
543
544
  		pr_warn("debugfs 'zsmalloc' stat dir creation failed
  ");
248ca1b05   Minchan Kim   zsmalloc: add ful...
545
546
547
548
549
550
  }
  
  static void __exit zs_stat_exit(void)
  {
  	debugfs_remove_recursive(zs_stat_root);
  }
1120ed548   Sergey Senozhatsky   mm/zsmalloc: add ...
551
  static unsigned long zs_can_compact(struct size_class *class);
248ca1b05   Minchan Kim   zsmalloc: add ful...
552
553
554
555
556
557
558
  static int zs_stats_size_show(struct seq_file *s, void *v)
  {
  	int i;
  	struct zs_pool *pool = s->private;
  	struct size_class *class;
  	int objs_per_zspage;
  	unsigned long class_almost_full, class_almost_empty;
1120ed548   Sergey Senozhatsky   mm/zsmalloc: add ...
559
  	unsigned long obj_allocated, obj_used, pages_used, freeable;
248ca1b05   Minchan Kim   zsmalloc: add ful...
560
561
  	unsigned long total_class_almost_full = 0, total_class_almost_empty = 0;
  	unsigned long total_objs = 0, total_used_objs = 0, total_pages = 0;
1120ed548   Sergey Senozhatsky   mm/zsmalloc: add ...
562
  	unsigned long total_freeable = 0;
248ca1b05   Minchan Kim   zsmalloc: add ful...
563

1120ed548   Sergey Senozhatsky   mm/zsmalloc: add ...
564
565
  	seq_printf(s, " %5s %5s %11s %12s %13s %10s %10s %16s %8s
  ",
248ca1b05   Minchan Kim   zsmalloc: add ful...
566
567
  			"class", "size", "almost_full", "almost_empty",
  			"obj_allocated", "obj_used", "pages_used",
1120ed548   Sergey Senozhatsky   mm/zsmalloc: add ...
568
  			"pages_per_zspage", "freeable");
248ca1b05   Minchan Kim   zsmalloc: add ful...
569

cf8e0fedf   Jerome Marchand   mm/zsmalloc: simp...
570
  	for (i = 0; i < ZS_SIZE_CLASSES; i++) {
248ca1b05   Minchan Kim   zsmalloc: add ful...
571
572
573
574
575
576
577
578
579
580
  		class = pool->size_class[i];
  
  		if (class->index != i)
  			continue;
  
  		spin_lock(&class->lock);
  		class_almost_full = zs_stat_get(class, CLASS_ALMOST_FULL);
  		class_almost_empty = zs_stat_get(class, CLASS_ALMOST_EMPTY);
  		obj_allocated = zs_stat_get(class, OBJ_ALLOCATED);
  		obj_used = zs_stat_get(class, OBJ_USED);
1120ed548   Sergey Senozhatsky   mm/zsmalloc: add ...
581
  		freeable = zs_can_compact(class);
248ca1b05   Minchan Kim   zsmalloc: add ful...
582
  		spin_unlock(&class->lock);
b4fd07a08   Ganesh Mahendran   mm/zsmalloc: use ...
583
  		objs_per_zspage = class->objs_per_zspage;
248ca1b05   Minchan Kim   zsmalloc: add ful...
584
585
  		pages_used = obj_allocated / objs_per_zspage *
  				class->pages_per_zspage;
1120ed548   Sergey Senozhatsky   mm/zsmalloc: add ...
586
587
588
  		seq_printf(s, " %5u %5u %11lu %12lu %13lu"
  				" %10lu %10lu %16d %8lu
  ",
248ca1b05   Minchan Kim   zsmalloc: add ful...
589
590
  			i, class->size, class_almost_full, class_almost_empty,
  			obj_allocated, obj_used, pages_used,
1120ed548   Sergey Senozhatsky   mm/zsmalloc: add ...
591
  			class->pages_per_zspage, freeable);
248ca1b05   Minchan Kim   zsmalloc: add ful...
592
593
594
595
596
597
  
  		total_class_almost_full += class_almost_full;
  		total_class_almost_empty += class_almost_empty;
  		total_objs += obj_allocated;
  		total_used_objs += obj_used;
  		total_pages += pages_used;
1120ed548   Sergey Senozhatsky   mm/zsmalloc: add ...
598
  		total_freeable += freeable;
248ca1b05   Minchan Kim   zsmalloc: add ful...
599
600
601
602
  	}
  
  	seq_puts(s, "
  ");
1120ed548   Sergey Senozhatsky   mm/zsmalloc: add ...
603
604
  	seq_printf(s, " %5s %5s %11lu %12lu %13lu %10lu %10lu %16s %8lu
  ",
248ca1b05   Minchan Kim   zsmalloc: add ful...
605
606
  			"Total", "", total_class_almost_full,
  			total_class_almost_empty, total_objs,
1120ed548   Sergey Senozhatsky   mm/zsmalloc: add ...
607
  			total_used_objs, total_pages, "", total_freeable);
248ca1b05   Minchan Kim   zsmalloc: add ful...
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
  
  	return 0;
  }
  
  static int zs_stats_size_open(struct inode *inode, struct file *file)
  {
  	return single_open(file, zs_stats_size_show, inode->i_private);
  }
  
  static const struct file_operations zs_stat_size_ops = {
  	.open           = zs_stats_size_open,
  	.read           = seq_read,
  	.llseek         = seq_lseek,
  	.release        = single_release,
  };
d34f61572   Dan Streetman   mm/zsmalloc: don'...
623
  static void zs_pool_stat_create(struct zs_pool *pool, const char *name)
248ca1b05   Minchan Kim   zsmalloc: add ful...
624
625
  {
  	struct dentry *entry;
4abaac9b7   Dan Streetman   update "mm/zsmall...
626
627
628
  	if (!zs_stat_root) {
  		pr_warn("no root stat dir, not creating <%s> stat dir
  ", name);
d34f61572   Dan Streetman   mm/zsmalloc: don'...
629
  		return;
4abaac9b7   Dan Streetman   update "mm/zsmall...
630
  	}
248ca1b05   Minchan Kim   zsmalloc: add ful...
631
632
633
634
635
  
  	entry = debugfs_create_dir(name, zs_stat_root);
  	if (!entry) {
  		pr_warn("debugfs dir <%s> creation failed
  ", name);
d34f61572   Dan Streetman   mm/zsmalloc: don'...
636
  		return;
248ca1b05   Minchan Kim   zsmalloc: add ful...
637
638
639
640
641
642
643
644
645
  	}
  	pool->stat_dentry = entry;
  
  	entry = debugfs_create_file("classes", S_IFREG | S_IRUGO,
  			pool->stat_dentry, pool, &zs_stat_size_ops);
  	if (!entry) {
  		pr_warn("%s: debugfs file entry <%s> creation failed
  ",
  				name, "classes");
4abaac9b7   Dan Streetman   update "mm/zsmall...
646
647
  		debugfs_remove_recursive(pool->stat_dentry);
  		pool->stat_dentry = NULL;
248ca1b05   Minchan Kim   zsmalloc: add ful...
648
  	}
248ca1b05   Minchan Kim   zsmalloc: add ful...
649
650
651
652
653
654
655
656
  }
  
  static void zs_pool_stat_destroy(struct zs_pool *pool)
  {
  	debugfs_remove_recursive(pool->stat_dentry);
  }
  
  #else /* CONFIG_ZSMALLOC_STAT */
4abaac9b7   Dan Streetman   update "mm/zsmall...
657
  static void __init zs_stat_init(void)
248ca1b05   Minchan Kim   zsmalloc: add ful...
658
  {
248ca1b05   Minchan Kim   zsmalloc: add ful...
659
660
661
662
663
  }
  
  static void __exit zs_stat_exit(void)
  {
  }
d34f61572   Dan Streetman   mm/zsmalloc: don'...
664
  static inline void zs_pool_stat_create(struct zs_pool *pool, const char *name)
248ca1b05   Minchan Kim   zsmalloc: add ful...
665
  {
248ca1b05   Minchan Kim   zsmalloc: add ful...
666
667
668
669
670
  }
  
  static inline void zs_pool_stat_destroy(struct zs_pool *pool)
  {
  }
248ca1b05   Minchan Kim   zsmalloc: add ful...
671
  #endif
48b4800a1   Minchan Kim   zsmalloc: page mi...
672

c3e3e88ad   Nitin Cupta   zsmalloc: add mor...
673
674
675
676
677
678
679
  /*
   * For each size class, zspages are divided into different groups
   * depending on how "full" they are. This was done so that we could
   * easily find empty or nearly empty zspages when we try to shrink
   * the pool (not yet implemented). This function returns fullness
   * status of the given page.
   */
1fc6e27d7   Minchan Kim   zsmalloc: keep ma...
680
  static enum fullness_group get_fullness_group(struct size_class *class,
3783689a1   Minchan Kim   zsmalloc: introdu...
681
  						struct zspage *zspage)
61989a80f   Nitin Gupta   staging: zsmalloc...
682
  {
1fc6e27d7   Minchan Kim   zsmalloc: keep ma...
683
  	int inuse, objs_per_zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
684
  	enum fullness_group fg;
830e4bc5b   Minchan Kim   zsmalloc: clean u...
685

3783689a1   Minchan Kim   zsmalloc: introdu...
686
  	inuse = get_zspage_inuse(zspage);
1fc6e27d7   Minchan Kim   zsmalloc: keep ma...
687
  	objs_per_zspage = class->objs_per_zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
688
689
690
  
  	if (inuse == 0)
  		fg = ZS_EMPTY;
1fc6e27d7   Minchan Kim   zsmalloc: keep ma...
691
  	else if (inuse == objs_per_zspage)
61989a80f   Nitin Gupta   staging: zsmalloc...
692
  		fg = ZS_FULL;
1fc6e27d7   Minchan Kim   zsmalloc: keep ma...
693
  	else if (inuse <= 3 * objs_per_zspage / fullness_threshold_frac)
61989a80f   Nitin Gupta   staging: zsmalloc...
694
695
696
697
698
699
  		fg = ZS_ALMOST_EMPTY;
  	else
  		fg = ZS_ALMOST_FULL;
  
  	return fg;
  }
c3e3e88ad   Nitin Cupta   zsmalloc: add mor...
700
701
702
703
704
705
  /*
   * Each size class maintains various freelists and zspages are assigned
   * to one of these freelists based on the number of live objects they
   * have. This functions inserts the given zspage into the freelist
   * identified by <class, fullness_group>.
   */
251cbb951   Minchan Kim   zsmalloc: reorder...
706
  static void insert_zspage(struct size_class *class,
3783689a1   Minchan Kim   zsmalloc: introdu...
707
708
  				struct zspage *zspage,
  				enum fullness_group fullness)
61989a80f   Nitin Gupta   staging: zsmalloc...
709
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
710
  	struct zspage *head;
61989a80f   Nitin Gupta   staging: zsmalloc...
711

48b4800a1   Minchan Kim   zsmalloc: page mi...
712
  	zs_stat_inc(class, fullness, 1);
3783689a1   Minchan Kim   zsmalloc: introdu...
713
714
  	head = list_first_entry_or_null(&class->fullness_list[fullness],
  					struct zspage, list);
58f171174   Sergey Senozhatsky   zsmalloc: partial...
715
  	/*
3783689a1   Minchan Kim   zsmalloc: introdu...
716
717
  	 * We want to see more ZS_FULL pages and less almost empty/full.
  	 * Put pages with higher ->inuse first.
58f171174   Sergey Senozhatsky   zsmalloc: partial...
718
  	 */
3783689a1   Minchan Kim   zsmalloc: introdu...
719
720
721
722
723
724
725
  	if (head) {
  		if (get_zspage_inuse(zspage) < get_zspage_inuse(head)) {
  			list_add(&zspage->list, &head->list);
  			return;
  		}
  	}
  	list_add(&zspage->list, &class->fullness_list[fullness]);
61989a80f   Nitin Gupta   staging: zsmalloc...
726
  }
c3e3e88ad   Nitin Cupta   zsmalloc: add mor...
727
728
729
730
  /*
   * This function removes the given zspage from the freelist identified
   * by <class, fullness_group>.
   */
251cbb951   Minchan Kim   zsmalloc: reorder...
731
  static void remove_zspage(struct size_class *class,
3783689a1   Minchan Kim   zsmalloc: introdu...
732
733
  				struct zspage *zspage,
  				enum fullness_group fullness)
61989a80f   Nitin Gupta   staging: zsmalloc...
734
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
735
  	VM_BUG_ON(list_empty(&class->fullness_list[fullness]));
48b4800a1   Minchan Kim   zsmalloc: page mi...
736
  	VM_BUG_ON(is_zspage_isolated(zspage));
61989a80f   Nitin Gupta   staging: zsmalloc...
737

3783689a1   Minchan Kim   zsmalloc: introdu...
738
  	list_del_init(&zspage->list);
48b4800a1   Minchan Kim   zsmalloc: page mi...
739
  	zs_stat_dec(class, fullness, 1);
61989a80f   Nitin Gupta   staging: zsmalloc...
740
  }
c3e3e88ad   Nitin Cupta   zsmalloc: add mor...
741
742
743
744
745
746
747
748
749
  /*
   * Each size class maintains zspages in different fullness groups depending
   * on the number of live objects they contain. When allocating or freeing
   * objects, the fullness status of the page can change, say, from ALMOST_FULL
   * to ALMOST_EMPTY when freeing an object. This function checks if such
   * a status change has occurred for the given page and accordingly moves the
   * page from the freelist of the old fullness group to that of the new
   * fullness group.
   */
c78062612   Minchan Kim   zsmalloc: factor ...
750
  static enum fullness_group fix_fullness_group(struct size_class *class,
3783689a1   Minchan Kim   zsmalloc: introdu...
751
  						struct zspage *zspage)
61989a80f   Nitin Gupta   staging: zsmalloc...
752
753
  {
  	int class_idx;
61989a80f   Nitin Gupta   staging: zsmalloc...
754
  	enum fullness_group currfg, newfg;
3783689a1   Minchan Kim   zsmalloc: introdu...
755
756
  	get_zspage_mapping(zspage, &class_idx, &currfg);
  	newfg = get_fullness_group(class, zspage);
61989a80f   Nitin Gupta   staging: zsmalloc...
757
758
  	if (newfg == currfg)
  		goto out;
48b4800a1   Minchan Kim   zsmalloc: page mi...
759
760
761
762
  	if (!is_zspage_isolated(zspage)) {
  		remove_zspage(class, zspage, currfg);
  		insert_zspage(class, zspage, newfg);
  	}
3783689a1   Minchan Kim   zsmalloc: introdu...
763
  	set_zspage_mapping(zspage, class_idx, newfg);
61989a80f   Nitin Gupta   staging: zsmalloc...
764
765
766
767
768
769
770
771
772
773
  
  out:
  	return newfg;
  }
  
  /*
   * We have to decide on how many pages to link together
   * to form a zspage for each size class. This is important
   * to reduce wastage due to unusable space left at end of
   * each zspage which is given as:
888fa374e   Yinghao Xie   mm/zsmalloc.c: fi...
774
775
   *     wastage = Zp % class_size
   *     usage = Zp - wastage
61989a80f   Nitin Gupta   staging: zsmalloc...
776
777
778
779
780
781
   * where Zp = zspage size = k * PAGE_SIZE where k = 1, 2, ...
   *
   * For example, for size class of 3/8 * PAGE_SIZE, we should
   * link together 3 PAGE_SIZE sized pages to form a zspage
   * since then we can perfectly fit in 8 such objects.
   */
2e3b61547   Minchan Kim   staging: zsmalloc...
782
  static int get_pages_per_zspage(int class_size)
61989a80f   Nitin Gupta   staging: zsmalloc...
783
784
785
786
  {
  	int i, max_usedpc = 0;
  	/* zspage order which gives maximum used size per KB */
  	int max_usedpc_order = 1;
84d4faaba   Seth Jennings   staging: zsmalloc...
787
  	for (i = 1; i <= ZS_MAX_PAGES_PER_ZSPAGE; i++) {
61989a80f   Nitin Gupta   staging: zsmalloc...
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
  		int zspage_size;
  		int waste, usedpc;
  
  		zspage_size = i * PAGE_SIZE;
  		waste = zspage_size % class_size;
  		usedpc = (zspage_size - waste) * 100 / zspage_size;
  
  		if (usedpc > max_usedpc) {
  			max_usedpc = usedpc;
  			max_usedpc_order = i;
  		}
  	}
  
  	return max_usedpc_order;
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
803
  static struct zspage *get_zspage(struct page *page)
61989a80f   Nitin Gupta   staging: zsmalloc...
804
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
805
806
807
808
  	struct zspage *zspage = (struct zspage *)page->private;
  
  	BUG_ON(zspage->magic != ZSPAGE_MAGIC);
  	return zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
809
810
811
812
  }
  
  static struct page *get_next_page(struct page *page)
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
813
814
815
816
  	if (unlikely(PageHugeObject(page)))
  		return NULL;
  
  	return page->freelist;
61989a80f   Nitin Gupta   staging: zsmalloc...
817
  }
bfd093f5e   Minchan Kim   zsmalloc: use fre...
818
819
820
821
  /**
   * obj_to_location - get (<page>, <obj_idx>) from encoded object value
   * @page: page object resides in zspage
   * @obj_idx: object index
67296874e   Olav Haugan   staging: zsmalloc...
822
   */
bfd093f5e   Minchan Kim   zsmalloc: use fre...
823
824
  static void obj_to_location(unsigned long obj, struct page **page,
  				unsigned int *obj_idx)
61989a80f   Nitin Gupta   staging: zsmalloc...
825
  {
bfd093f5e   Minchan Kim   zsmalloc: use fre...
826
827
828
829
  	obj >>= OBJ_TAG_BITS;
  	*page = pfn_to_page(obj >> OBJ_INDEX_BITS);
  	*obj_idx = (obj & OBJ_INDEX_MASK);
  }
61989a80f   Nitin Gupta   staging: zsmalloc...
830

bfd093f5e   Minchan Kim   zsmalloc: use fre...
831
832
833
834
835
836
837
838
  /**
   * location_to_obj - get obj value encoded from (<page>, <obj_idx>)
   * @page: page object resides in zspage
   * @obj_idx: object index
   */
  static unsigned long location_to_obj(struct page *page, unsigned int obj_idx)
  {
  	unsigned long obj;
61989a80f   Nitin Gupta   staging: zsmalloc...
839

312fcae22   Minchan Kim   zsmalloc: support...
840
  	obj = page_to_pfn(page) << OBJ_INDEX_BITS;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
841
  	obj |= obj_idx & OBJ_INDEX_MASK;
312fcae22   Minchan Kim   zsmalloc: support...
842
  	obj <<= OBJ_TAG_BITS;
61989a80f   Nitin Gupta   staging: zsmalloc...
843

bfd093f5e   Minchan Kim   zsmalloc: use fre...
844
  	return obj;
61989a80f   Nitin Gupta   staging: zsmalloc...
845
  }
2e40e163a   Minchan Kim   zsmalloc: decoupl...
846
847
848
849
  static unsigned long handle_to_obj(unsigned long handle)
  {
  	return *(unsigned long *)handle;
  }
48b4800a1   Minchan Kim   zsmalloc: page mi...
850
  static unsigned long obj_to_head(struct page *page, void *obj)
312fcae22   Minchan Kim   zsmalloc: support...
851
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
852
  	if (unlikely(PageHugeObject(page))) {
830e4bc5b   Minchan Kim   zsmalloc: clean u...
853
  		VM_BUG_ON_PAGE(!is_first_page(page), page);
3783689a1   Minchan Kim   zsmalloc: introdu...
854
  		return page->index;
7b60a6852   Minchan Kim   zsmalloc: record ...
855
856
  	} else
  		return *(unsigned long *)obj;
312fcae22   Minchan Kim   zsmalloc: support...
857
  }
48b4800a1   Minchan Kim   zsmalloc: page mi...
858
859
860
861
  static inline int testpin_tag(unsigned long handle)
  {
  	return bit_spin_is_locked(HANDLE_PIN_BIT, (unsigned long *)handle);
  }
312fcae22   Minchan Kim   zsmalloc: support...
862
863
  static inline int trypin_tag(unsigned long handle)
  {
1b8320b62   Minchan Kim   zsmalloc: use bit...
864
  	return bit_spin_trylock(HANDLE_PIN_BIT, (unsigned long *)handle);
312fcae22   Minchan Kim   zsmalloc: support...
865
866
867
868
  }
  
  static void pin_tag(unsigned long handle)
  {
1b8320b62   Minchan Kim   zsmalloc: use bit...
869
  	bit_spin_lock(HANDLE_PIN_BIT, (unsigned long *)handle);
312fcae22   Minchan Kim   zsmalloc: support...
870
871
872
873
  }
  
  static void unpin_tag(unsigned long handle)
  {
1b8320b62   Minchan Kim   zsmalloc: use bit...
874
  	bit_spin_unlock(HANDLE_PIN_BIT, (unsigned long *)handle);
312fcae22   Minchan Kim   zsmalloc: support...
875
  }
f4477e90b   Nitin Gupta   staging: zsmalloc...
876
877
  static void reset_page(struct page *page)
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
878
  	__ClearPageMovable(page);
18fd06bf7   Ganesh Mahendran   mm/zsmalloc: use ...
879
  	ClearPagePrivate(page);
f4477e90b   Nitin Gupta   staging: zsmalloc...
880
  	set_page_private(page, 0);
48b4800a1   Minchan Kim   zsmalloc: page mi...
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
  	page_mapcount_reset(page);
  	ClearPageHugeObject(page);
  	page->freelist = NULL;
  }
  
  /*
   * To prevent zspage destroy during migration, zspage freeing should
   * hold locks of all pages in the zspage.
   */
  void lock_zspage(struct zspage *zspage)
  {
  	struct page *page = get_first_page(zspage);
  
  	do {
  		lock_page(page);
  	} while ((page = get_next_page(page)) != NULL);
  }
  
  int trylock_zspage(struct zspage *zspage)
  {
  	struct page *cursor, *fail;
  
  	for (cursor = get_first_page(zspage); cursor != NULL; cursor =
  					get_next_page(cursor)) {
  		if (!trylock_page(cursor)) {
  			fail = cursor;
  			goto unlock;
  		}
  	}
  
  	return 1;
  unlock:
  	for (cursor = get_first_page(zspage); cursor != fail; cursor =
  					get_next_page(cursor))
  		unlock_page(cursor);
  
  	return 0;
f4477e90b   Nitin Gupta   staging: zsmalloc...
918
  }
48b4800a1   Minchan Kim   zsmalloc: page mi...
919
920
  static void __free_zspage(struct zs_pool *pool, struct size_class *class,
  				struct zspage *zspage)
61989a80f   Nitin Gupta   staging: zsmalloc...
921
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
922
  	struct page *page, *next;
48b4800a1   Minchan Kim   zsmalloc: page mi...
923
924
925
926
927
928
  	enum fullness_group fg;
  	unsigned int class_idx;
  
  	get_zspage_mapping(zspage, &class_idx, &fg);
  
  	assert_spin_locked(&class->lock);
61989a80f   Nitin Gupta   staging: zsmalloc...
929

3783689a1   Minchan Kim   zsmalloc: introdu...
930
  	VM_BUG_ON(get_zspage_inuse(zspage));
48b4800a1   Minchan Kim   zsmalloc: page mi...
931
  	VM_BUG_ON(fg != ZS_EMPTY);
61989a80f   Nitin Gupta   staging: zsmalloc...
932

48b4800a1   Minchan Kim   zsmalloc: page mi...
933
  	next = page = get_first_page(zspage);
3783689a1   Minchan Kim   zsmalloc: introdu...
934
  	do {
48b4800a1   Minchan Kim   zsmalloc: page mi...
935
936
  		VM_BUG_ON_PAGE(!PageLocked(page), page);
  		next = get_next_page(page);
3783689a1   Minchan Kim   zsmalloc: introdu...
937
  		reset_page(page);
48b4800a1   Minchan Kim   zsmalloc: page mi...
938
  		unlock_page(page);
91537fee0   Minchan Kim   mm: add NR_ZSMALL...
939
  		dec_zone_page_state(page, NR_ZSPAGES);
3783689a1   Minchan Kim   zsmalloc: introdu...
940
941
942
  		put_page(page);
  		page = next;
  	} while (page != NULL);
61989a80f   Nitin Gupta   staging: zsmalloc...
943

3783689a1   Minchan Kim   zsmalloc: introdu...
944
  	cache_free_zspage(pool, zspage);
48b4800a1   Minchan Kim   zsmalloc: page mi...
945

b4fd07a08   Ganesh Mahendran   mm/zsmalloc: use ...
946
  	zs_stat_dec(class, OBJ_ALLOCATED, class->objs_per_zspage);
48b4800a1   Minchan Kim   zsmalloc: page mi...
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
  	atomic_long_sub(class->pages_per_zspage,
  					&pool->pages_allocated);
  }
  
  static void free_zspage(struct zs_pool *pool, struct size_class *class,
  				struct zspage *zspage)
  {
  	VM_BUG_ON(get_zspage_inuse(zspage));
  	VM_BUG_ON(list_empty(&zspage->list));
  
  	if (!trylock_zspage(zspage)) {
  		kick_deferred_free(pool);
  		return;
  	}
  
  	remove_zspage(class, zspage, ZS_EMPTY);
  	__free_zspage(pool, class, zspage);
61989a80f   Nitin Gupta   staging: zsmalloc...
964
965
966
  }
  
  /* Initialize a newly allocated zspage */
3783689a1   Minchan Kim   zsmalloc: introdu...
967
  static void init_zspage(struct size_class *class, struct zspage *zspage)
61989a80f   Nitin Gupta   staging: zsmalloc...
968
  {
bfd093f5e   Minchan Kim   zsmalloc: use fre...
969
  	unsigned int freeobj = 1;
61989a80f   Nitin Gupta   staging: zsmalloc...
970
  	unsigned long off = 0;
48b4800a1   Minchan Kim   zsmalloc: page mi...
971
  	struct page *page = get_first_page(zspage);
830e4bc5b   Minchan Kim   zsmalloc: clean u...
972

61989a80f   Nitin Gupta   staging: zsmalloc...
973
974
975
  	while (page) {
  		struct page *next_page;
  		struct link_free *link;
af4ee5e97   Minchan Kim   zsmalloc: correct...
976
  		void *vaddr;
61989a80f   Nitin Gupta   staging: zsmalloc...
977

3783689a1   Minchan Kim   zsmalloc: introdu...
978
  		set_first_obj_offset(page, off);
61989a80f   Nitin Gupta   staging: zsmalloc...
979

af4ee5e97   Minchan Kim   zsmalloc: correct...
980
981
  		vaddr = kmap_atomic(page);
  		link = (struct link_free *)vaddr + off / sizeof(*link);
5538c5623   Dan Streetman   zsmalloc: simplif...
982
983
  
  		while ((off += class->size) < PAGE_SIZE) {
3b1d9ca65   Minchan Kim   zsmalloc: use OBJ...
984
  			link->next = freeobj++ << OBJ_TAG_BITS;
5538c5623   Dan Streetman   zsmalloc: simplif...
985
  			link += class->size / sizeof(*link);
61989a80f   Nitin Gupta   staging: zsmalloc...
986
987
988
989
990
991
992
993
  		}
  
  		/*
  		 * We now come to the last (full or partial) object on this
  		 * page, which must point to the first object on the next
  		 * page (if present)
  		 */
  		next_page = get_next_page(page);
bfd093f5e   Minchan Kim   zsmalloc: use fre...
994
  		if (next_page) {
3b1d9ca65   Minchan Kim   zsmalloc: use OBJ...
995
  			link->next = freeobj++ << OBJ_TAG_BITS;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
996
997
  		} else {
  			/*
3b1d9ca65   Minchan Kim   zsmalloc: use OBJ...
998
  			 * Reset OBJ_TAG_BITS bit to last link to tell
bfd093f5e   Minchan Kim   zsmalloc: use fre...
999
1000
  			 * whether it's allocated object or not.
  			 */
3b1d9ca65   Minchan Kim   zsmalloc: use OBJ...
1001
  			link->next = -1 << OBJ_TAG_BITS;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1002
  		}
af4ee5e97   Minchan Kim   zsmalloc: correct...
1003
  		kunmap_atomic(vaddr);
61989a80f   Nitin Gupta   staging: zsmalloc...
1004
  		page = next_page;
5538c5623   Dan Streetman   zsmalloc: simplif...
1005
  		off %= PAGE_SIZE;
61989a80f   Nitin Gupta   staging: zsmalloc...
1006
  	}
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1007

bfd093f5e   Minchan Kim   zsmalloc: use fre...
1008
  	set_freeobj(zspage, 0);
61989a80f   Nitin Gupta   staging: zsmalloc...
1009
  }
48b4800a1   Minchan Kim   zsmalloc: page mi...
1010
1011
  static void create_page_chain(struct size_class *class, struct zspage *zspage,
  				struct page *pages[])
61989a80f   Nitin Gupta   staging: zsmalloc...
1012
  {
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1013
1014
1015
  	int i;
  	struct page *page;
  	struct page *prev_page = NULL;
48b4800a1   Minchan Kim   zsmalloc: page mi...
1016
  	int nr_pages = class->pages_per_zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
1017
1018
1019
  
  	/*
  	 * Allocate individual pages and link them together as:
48b4800a1   Minchan Kim   zsmalloc: page mi...
1020
  	 * 1. all pages are linked together using page->freelist
3783689a1   Minchan Kim   zsmalloc: introdu...
1021
  	 * 2. each sub-page point to zspage using page->private
61989a80f   Nitin Gupta   staging: zsmalloc...
1022
  	 *
3783689a1   Minchan Kim   zsmalloc: introdu...
1023
  	 * we set PG_private to identify the first page (i.e. no other sub-page
22c5cef16   Yisheng Xie   mm/zsmalloc: remo...
1024
  	 * has this flag set).
61989a80f   Nitin Gupta   staging: zsmalloc...
1025
  	 */
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1026
1027
  	for (i = 0; i < nr_pages; i++) {
  		page = pages[i];
3783689a1   Minchan Kim   zsmalloc: introdu...
1028
  		set_page_private(page, (unsigned long)zspage);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1029
  		page->freelist = NULL;
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1030
  		if (i == 0) {
3783689a1   Minchan Kim   zsmalloc: introdu...
1031
  			zspage->first_page = page;
a27545bf0   Minchan Kim   zsmalloc: use Pag...
1032
  			SetPagePrivate(page);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1033
1034
1035
  			if (unlikely(class->objs_per_zspage == 1 &&
  					class->pages_per_zspage == 1))
  				SetPageHugeObject(page);
3783689a1   Minchan Kim   zsmalloc: introdu...
1036
  		} else {
48b4800a1   Minchan Kim   zsmalloc: page mi...
1037
  			prev_page->freelist = page;
61989a80f   Nitin Gupta   staging: zsmalloc...
1038
  		}
61989a80f   Nitin Gupta   staging: zsmalloc...
1039
1040
  		prev_page = page;
  	}
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1041
  }
61989a80f   Nitin Gupta   staging: zsmalloc...
1042

bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1043
1044
1045
  /*
   * Allocate a zspage for the given size class
   */
3783689a1   Minchan Kim   zsmalloc: introdu...
1046
1047
1048
  static struct zspage *alloc_zspage(struct zs_pool *pool,
  					struct size_class *class,
  					gfp_t gfp)
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1049
1050
  {
  	int i;
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1051
  	struct page *pages[ZS_MAX_PAGES_PER_ZSPAGE];
3783689a1   Minchan Kim   zsmalloc: introdu...
1052
1053
1054
1055
1056
1057
  	struct zspage *zspage = cache_alloc_zspage(pool, gfp);
  
  	if (!zspage)
  		return NULL;
  
  	memset(zspage, 0, sizeof(struct zspage));
48b4800a1   Minchan Kim   zsmalloc: page mi...
1058
1059
  	zspage->magic = ZSPAGE_MAGIC;
  	migrate_lock_init(zspage);
61989a80f   Nitin Gupta   staging: zsmalloc...
1060

bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1061
1062
  	for (i = 0; i < class->pages_per_zspage; i++) {
  		struct page *page;
61989a80f   Nitin Gupta   staging: zsmalloc...
1063

3783689a1   Minchan Kim   zsmalloc: introdu...
1064
  		page = alloc_page(gfp);
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1065
  		if (!page) {
91537fee0   Minchan Kim   mm: add NR_ZSMALL...
1066
1067
  			while (--i >= 0) {
  				dec_zone_page_state(pages[i], NR_ZSPAGES);
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1068
  				__free_page(pages[i]);
91537fee0   Minchan Kim   mm: add NR_ZSMALL...
1069
  			}
3783689a1   Minchan Kim   zsmalloc: introdu...
1070
  			cache_free_zspage(pool, zspage);
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1071
1072
  			return NULL;
  		}
91537fee0   Minchan Kim   mm: add NR_ZSMALL...
1073
1074
  
  		inc_zone_page_state(page, NR_ZSPAGES);
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1075
  		pages[i] = page;
61989a80f   Nitin Gupta   staging: zsmalloc...
1076
  	}
48b4800a1   Minchan Kim   zsmalloc: page mi...
1077
  	create_page_chain(class, zspage, pages);
3783689a1   Minchan Kim   zsmalloc: introdu...
1078
  	init_zspage(class, zspage);
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1079

3783689a1   Minchan Kim   zsmalloc: introdu...
1080
  	return zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
1081
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
1082
  static struct zspage *find_get_zspage(struct size_class *class)
61989a80f   Nitin Gupta   staging: zsmalloc...
1083
1084
  {
  	int i;
3783689a1   Minchan Kim   zsmalloc: introdu...
1085
  	struct zspage *zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
1086

48b4800a1   Minchan Kim   zsmalloc: page mi...
1087
  	for (i = ZS_ALMOST_FULL; i >= ZS_EMPTY; i--) {
3783689a1   Minchan Kim   zsmalloc: introdu...
1088
1089
1090
  		zspage = list_first_entry_or_null(&class->fullness_list[i],
  				struct zspage, list);
  		if (zspage)
61989a80f   Nitin Gupta   staging: zsmalloc...
1091
1092
  			break;
  	}
3783689a1   Minchan Kim   zsmalloc: introdu...
1093
  	return zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
1094
  }
1b945aeef   Minchan Kim   zsmalloc: add Kco...
1095
  #ifdef CONFIG_PGTABLE_MAPPING
f553646a6   Seth Jennings   staging: zsmalloc...
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
  static inline int __zs_cpu_up(struct mapping_area *area)
  {
  	/*
  	 * Make sure we don't leak memory if a cpu UP notification
  	 * and zs_init() race and both call zs_cpu_up() on the same cpu
  	 */
  	if (area->vm)
  		return 0;
  	area->vm = alloc_vm_area(PAGE_SIZE * 2, NULL);
  	if (!area->vm)
  		return -ENOMEM;
  	return 0;
  }
  
  static inline void __zs_cpu_down(struct mapping_area *area)
  {
  	if (area->vm)
  		free_vm_area(area->vm);
  	area->vm = NULL;
  }
  
  static inline void *__zs_map_object(struct mapping_area *area,
  				struct page *pages[2], int off, int size)
  {
f6f8ed473   WANG Chao   mm/vmalloc.c: cle...
1120
  	BUG_ON(map_vm_area(area->vm, PAGE_KERNEL, pages));
f553646a6   Seth Jennings   staging: zsmalloc...
1121
1122
1123
1124
1125
1126
1127
1128
  	area->vm_addr = area->vm->addr;
  	return area->vm_addr + off;
  }
  
  static inline void __zs_unmap_object(struct mapping_area *area,
  				struct page *pages[2], int off, int size)
  {
  	unsigned long addr = (unsigned long)area->vm_addr;
f553646a6   Seth Jennings   staging: zsmalloc...
1129

d95abbbb2   Joerg Roedel   staging: zsmalloc...
1130
  	unmap_kernel_range(addr, PAGE_SIZE * 2);
f553646a6   Seth Jennings   staging: zsmalloc...
1131
  }
1b945aeef   Minchan Kim   zsmalloc: add Kco...
1132
  #else /* CONFIG_PGTABLE_MAPPING */
f553646a6   Seth Jennings   staging: zsmalloc...
1133
1134
1135
1136
1137
1138
1139
1140
1141
  
  static inline int __zs_cpu_up(struct mapping_area *area)
  {
  	/*
  	 * Make sure we don't leak memory if a cpu UP notification
  	 * and zs_init() race and both call zs_cpu_up() on the same cpu
  	 */
  	if (area->vm_buf)
  		return 0;
40f9fb8cf   Mahendran Ganesh   mm/zsmalloc: supp...
1142
  	area->vm_buf = kmalloc(ZS_MAX_ALLOC_SIZE, GFP_KERNEL);
f553646a6   Seth Jennings   staging: zsmalloc...
1143
1144
1145
1146
1147
1148
1149
  	if (!area->vm_buf)
  		return -ENOMEM;
  	return 0;
  }
  
  static inline void __zs_cpu_down(struct mapping_area *area)
  {
40f9fb8cf   Mahendran Ganesh   mm/zsmalloc: supp...
1150
  	kfree(area->vm_buf);
f553646a6   Seth Jennings   staging: zsmalloc...
1151
1152
1153
1154
1155
  	area->vm_buf = NULL;
  }
  
  static void *__zs_map_object(struct mapping_area *area,
  			struct page *pages[2], int off, int size)
5f601902c   Seth Jennings   staging: zsmalloc...
1156
  {
5f601902c   Seth Jennings   staging: zsmalloc...
1157
1158
  	int sizes[2];
  	void *addr;
f553646a6   Seth Jennings   staging: zsmalloc...
1159
  	char *buf = area->vm_buf;
5f601902c   Seth Jennings   staging: zsmalloc...
1160

f553646a6   Seth Jennings   staging: zsmalloc...
1161
1162
1163
1164
1165
1166
  	/* disable page faults to match kmap_atomic() return conditions */
  	pagefault_disable();
  
  	/* no read fastpath */
  	if (area->vm_mm == ZS_MM_WO)
  		goto out;
5f601902c   Seth Jennings   staging: zsmalloc...
1167
1168
1169
  
  	sizes[0] = PAGE_SIZE - off;
  	sizes[1] = size - sizes[0];
5f601902c   Seth Jennings   staging: zsmalloc...
1170
1171
1172
1173
1174
1175
1176
  	/* copy object to per-cpu buffer */
  	addr = kmap_atomic(pages[0]);
  	memcpy(buf, addr + off, sizes[0]);
  	kunmap_atomic(addr);
  	addr = kmap_atomic(pages[1]);
  	memcpy(buf + sizes[0], addr, sizes[1]);
  	kunmap_atomic(addr);
f553646a6   Seth Jennings   staging: zsmalloc...
1177
1178
  out:
  	return area->vm_buf;
5f601902c   Seth Jennings   staging: zsmalloc...
1179
  }
f553646a6   Seth Jennings   staging: zsmalloc...
1180
1181
  static void __zs_unmap_object(struct mapping_area *area,
  			struct page *pages[2], int off, int size)
5f601902c   Seth Jennings   staging: zsmalloc...
1182
  {
5f601902c   Seth Jennings   staging: zsmalloc...
1183
1184
  	int sizes[2];
  	void *addr;
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1185
  	char *buf;
5f601902c   Seth Jennings   staging: zsmalloc...
1186

f553646a6   Seth Jennings   staging: zsmalloc...
1187
1188
1189
  	/* no write fastpath */
  	if (area->vm_mm == ZS_MM_RO)
  		goto out;
5f601902c   Seth Jennings   staging: zsmalloc...
1190

7b60a6852   Minchan Kim   zsmalloc: record ...
1191
  	buf = area->vm_buf;
a82cbf071   YiPing Xu   zsmalloc: drop un...
1192
1193
1194
  	buf = buf + ZS_HANDLE_SIZE;
  	size -= ZS_HANDLE_SIZE;
  	off += ZS_HANDLE_SIZE;
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1195

5f601902c   Seth Jennings   staging: zsmalloc...
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
  	sizes[0] = PAGE_SIZE - off;
  	sizes[1] = size - sizes[0];
  
  	/* copy per-cpu buffer to object */
  	addr = kmap_atomic(pages[0]);
  	memcpy(addr + off, buf, sizes[0]);
  	kunmap_atomic(addr);
  	addr = kmap_atomic(pages[1]);
  	memcpy(addr, buf + sizes[0], sizes[1]);
  	kunmap_atomic(addr);
f553646a6   Seth Jennings   staging: zsmalloc...
1206
1207
1208
1209
  
  out:
  	/* enable page faults to match kunmap_atomic() return conditions */
  	pagefault_enable();
5f601902c   Seth Jennings   staging: zsmalloc...
1210
  }
61989a80f   Nitin Gupta   staging: zsmalloc...
1211

1b945aeef   Minchan Kim   zsmalloc: add Kco...
1212
  #endif /* CONFIG_PGTABLE_MAPPING */
f553646a6   Seth Jennings   staging: zsmalloc...
1213

215c89d05   Sebastian Andrzej Siewior   mm/zsmalloc: Conv...
1214
  static int zs_cpu_prepare(unsigned int cpu)
61989a80f   Nitin Gupta   staging: zsmalloc...
1215
  {
61989a80f   Nitin Gupta   staging: zsmalloc...
1216
  	struct mapping_area *area;
215c89d05   Sebastian Andrzej Siewior   mm/zsmalloc: Conv...
1217
1218
  	area = &per_cpu(zs_map_area, cpu);
  	return __zs_cpu_up(area);
61989a80f   Nitin Gupta   staging: zsmalloc...
1219
  }
215c89d05   Sebastian Andrzej Siewior   mm/zsmalloc: Conv...
1220
  static int zs_cpu_dead(unsigned int cpu)
61989a80f   Nitin Gupta   staging: zsmalloc...
1221
  {
215c89d05   Sebastian Andrzej Siewior   mm/zsmalloc: Conv...
1222
  	struct mapping_area *area;
40f9fb8cf   Mahendran Ganesh   mm/zsmalloc: supp...
1223

215c89d05   Sebastian Andrzej Siewior   mm/zsmalloc: Conv...
1224
1225
1226
  	area = &per_cpu(zs_map_area, cpu);
  	__zs_cpu_down(area);
  	return 0;
b1b00a5b8   Sergey Senozhatsky   zsmalloc: fix zs_...
1227
  }
64d90465f   Ganesh Mahendran   mm/zsmalloc: avoi...
1228
1229
  static bool can_merge(struct size_class *prev, int pages_per_zspage,
  					int objs_per_zspage)
9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1230
  {
64d90465f   Ganesh Mahendran   mm/zsmalloc: avoi...
1231
1232
1233
  	if (prev->pages_per_zspage == pages_per_zspage &&
  		prev->objs_per_zspage == objs_per_zspage)
  		return true;
9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1234

64d90465f   Ganesh Mahendran   mm/zsmalloc: avoi...
1235
  	return false;
9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1236
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
1237
  static bool zspage_full(struct size_class *class, struct zspage *zspage)
312fcae22   Minchan Kim   zsmalloc: support...
1238
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
1239
  	return get_zspage_inuse(zspage) == class->objs_per_zspage;
312fcae22   Minchan Kim   zsmalloc: support...
1240
  }
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1241
1242
1243
1244
1245
  unsigned long zs_get_total_pages(struct zs_pool *pool)
  {
  	return atomic_long_read(&pool->pages_allocated);
  }
  EXPORT_SYMBOL_GPL(zs_get_total_pages);
4bbc0bc06   Davidlohr Bueso   staging: zsmalloc...
1246
  /**
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1247
1248
1249
   * zs_map_object - get address of allocated object from handle.
   * @pool: pool from which the object was allocated
   * @handle: handle returned from zs_malloc
4bbc0bc06   Davidlohr Bueso   staging: zsmalloc...
1250
   *
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1251
1252
1253
   * Before using an object allocated from zs_malloc, it must be mapped using
   * this function. When done with the object, it must be unmapped using
   * zs_unmap_object.
4bbc0bc06   Davidlohr Bueso   staging: zsmalloc...
1254
   *
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1255
1256
1257
1258
   * Only one object can be mapped per cpu at a time. There is no protection
   * against nested mappings.
   *
   * This function returns with preemption and page faults disabled.
4bbc0bc06   Davidlohr Bueso   staging: zsmalloc...
1259
   */
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1260
1261
  void *zs_map_object(struct zs_pool *pool, unsigned long handle,
  			enum zs_mapmode mm)
61989a80f   Nitin Gupta   staging: zsmalloc...
1262
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
1263
  	struct zspage *zspage;
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1264
  	struct page *page;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1265
1266
  	unsigned long obj, off;
  	unsigned int obj_idx;
61989a80f   Nitin Gupta   staging: zsmalloc...
1267

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1268
1269
1270
1271
1272
  	unsigned int class_idx;
  	enum fullness_group fg;
  	struct size_class *class;
  	struct mapping_area *area;
  	struct page *pages[2];
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1273
  	void *ret;
61989a80f   Nitin Gupta   staging: zsmalloc...
1274

9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1275
  	/*
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1276
1277
1278
  	 * Because we use per-cpu mapping areas shared among the
  	 * pools/users, we can't allow mapping in interrupt context
  	 * because it can corrupt another users mappings.
9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1279
  	 */
123833408   Sergey Senozhatsky   zsmalloc: calling...
1280
  	BUG_ON(in_interrupt());
61989a80f   Nitin Gupta   staging: zsmalloc...
1281

312fcae22   Minchan Kim   zsmalloc: support...
1282
1283
  	/* From now on, migration cannot move the object */
  	pin_tag(handle);
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1284
1285
  	obj = handle_to_obj(handle);
  	obj_to_location(obj, &page, &obj_idx);
3783689a1   Minchan Kim   zsmalloc: introdu...
1286
  	zspage = get_zspage(page);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1287
1288
1289
  
  	/* migration cannot move any subpage in this zspage */
  	migrate_read_lock(zspage);
3783689a1   Minchan Kim   zsmalloc: introdu...
1290
  	get_zspage_mapping(zspage, &class_idx, &fg);
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1291
  	class = pool->size_class[class_idx];
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1292
  	off = (class->size * obj_idx) & ~PAGE_MASK;
df8b5bb99   Ganesh Mahendran   mm/zsmalloc: avoi...
1293

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1294
1295
1296
1297
1298
  	area = &get_cpu_var(zs_map_area);
  	area->vm_mm = mm;
  	if (off + class->size <= PAGE_SIZE) {
  		/* this object is contained entirely within a page */
  		area->vm_addr = kmap_atomic(page);
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1299
1300
  		ret = area->vm_addr + off;
  		goto out;
61989a80f   Nitin Gupta   staging: zsmalloc...
1301
  	}
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1302
1303
1304
1305
  	/* this object spans two pages */
  	pages[0] = page;
  	pages[1] = get_next_page(page);
  	BUG_ON(!pages[1]);
9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1306

2e40e163a   Minchan Kim   zsmalloc: decoupl...
1307
1308
  	ret = __zs_map_object(area, pages, off, class->size);
  out:
48b4800a1   Minchan Kim   zsmalloc: page mi...
1309
  	if (likely(!PageHugeObject(page)))
7b60a6852   Minchan Kim   zsmalloc: record ...
1310
1311
1312
  		ret += ZS_HANDLE_SIZE;
  
  	return ret;
61989a80f   Nitin Gupta   staging: zsmalloc...
1313
  }
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1314
  EXPORT_SYMBOL_GPL(zs_map_object);
61989a80f   Nitin Gupta   staging: zsmalloc...
1315

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1316
  void zs_unmap_object(struct zs_pool *pool, unsigned long handle)
61989a80f   Nitin Gupta   staging: zsmalloc...
1317
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
1318
  	struct zspage *zspage;
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1319
  	struct page *page;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1320
1321
  	unsigned long obj, off;
  	unsigned int obj_idx;
61989a80f   Nitin Gupta   staging: zsmalloc...
1322

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1323
1324
1325
1326
  	unsigned int class_idx;
  	enum fullness_group fg;
  	struct size_class *class;
  	struct mapping_area *area;
9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1327

2e40e163a   Minchan Kim   zsmalloc: decoupl...
1328
1329
  	obj = handle_to_obj(handle);
  	obj_to_location(obj, &page, &obj_idx);
3783689a1   Minchan Kim   zsmalloc: introdu...
1330
1331
  	zspage = get_zspage(page);
  	get_zspage_mapping(zspage, &class_idx, &fg);
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1332
  	class = pool->size_class[class_idx];
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1333
  	off = (class->size * obj_idx) & ~PAGE_MASK;
61989a80f   Nitin Gupta   staging: zsmalloc...
1334

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1335
1336
1337
1338
1339
  	area = this_cpu_ptr(&zs_map_area);
  	if (off + class->size <= PAGE_SIZE)
  		kunmap_atomic(area->vm_addr);
  	else {
  		struct page *pages[2];
40f9fb8cf   Mahendran Ganesh   mm/zsmalloc: supp...
1340

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1341
1342
1343
1344
1345
1346
1347
  		pages[0] = page;
  		pages[1] = get_next_page(page);
  		BUG_ON(!pages[1]);
  
  		__zs_unmap_object(area, pages, off, class->size);
  	}
  	put_cpu_var(zs_map_area);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1348
1349
  
  	migrate_read_unlock(zspage);
312fcae22   Minchan Kim   zsmalloc: support...
1350
  	unpin_tag(handle);
61989a80f   Nitin Gupta   staging: zsmalloc...
1351
  }
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1352
  EXPORT_SYMBOL_GPL(zs_unmap_object);
61989a80f   Nitin Gupta   staging: zsmalloc...
1353

251cbb951   Minchan Kim   zsmalloc: reorder...
1354
  static unsigned long obj_malloc(struct size_class *class,
3783689a1   Minchan Kim   zsmalloc: introdu...
1355
  				struct zspage *zspage, unsigned long handle)
c78062612   Minchan Kim   zsmalloc: factor ...
1356
  {
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1357
  	int i, nr_page, offset;
c78062612   Minchan Kim   zsmalloc: factor ...
1358
1359
1360
1361
  	unsigned long obj;
  	struct link_free *link;
  
  	struct page *m_page;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1362
  	unsigned long m_offset;
c78062612   Minchan Kim   zsmalloc: factor ...
1363
  	void *vaddr;
312fcae22   Minchan Kim   zsmalloc: support...
1364
  	handle |= OBJ_ALLOCATED_TAG;
3783689a1   Minchan Kim   zsmalloc: introdu...
1365
  	obj = get_freeobj(zspage);
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1366
1367
1368
1369
1370
1371
1372
1373
  
  	offset = obj * class->size;
  	nr_page = offset >> PAGE_SHIFT;
  	m_offset = offset & ~PAGE_MASK;
  	m_page = get_first_page(zspage);
  
  	for (i = 0; i < nr_page; i++)
  		m_page = get_next_page(m_page);
c78062612   Minchan Kim   zsmalloc: factor ...
1374
1375
1376
  
  	vaddr = kmap_atomic(m_page);
  	link = (struct link_free *)vaddr + m_offset / sizeof(*link);
3b1d9ca65   Minchan Kim   zsmalloc: use OBJ...
1377
  	set_freeobj(zspage, link->next >> OBJ_TAG_BITS);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1378
  	if (likely(!PageHugeObject(m_page)))
7b60a6852   Minchan Kim   zsmalloc: record ...
1379
1380
1381
  		/* record handle in the header of allocated chunk */
  		link->handle = handle;
  	else
3783689a1   Minchan Kim   zsmalloc: introdu...
1382
1383
  		/* record handle to page->index */
  		zspage->first_page->index = handle;
c78062612   Minchan Kim   zsmalloc: factor ...
1384
  	kunmap_atomic(vaddr);
3783689a1   Minchan Kim   zsmalloc: introdu...
1385
  	mod_zspage_inuse(zspage, 1);
c78062612   Minchan Kim   zsmalloc: factor ...
1386
  	zs_stat_inc(class, OBJ_USED, 1);
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1387
  	obj = location_to_obj(m_page, obj);
c78062612   Minchan Kim   zsmalloc: factor ...
1388
1389
  	return obj;
  }
61989a80f   Nitin Gupta   staging: zsmalloc...
1390
1391
1392
1393
  /**
   * zs_malloc - Allocate block of given size from pool.
   * @pool: pool to allocate from
   * @size: size of block to allocate
fd8544639   Ganesh Mahendran   mm/zsmalloc: keep...
1394
   * @gfp: gfp flags when allocating object
61989a80f   Nitin Gupta   staging: zsmalloc...
1395
   *
00a61d861   Minchan Kim   staging: zsmalloc...
1396
   * On success, handle to the allocated object is returned,
c23443483   Minchan Kim   staging: zsmalloc...
1397
   * otherwise 0.
61989a80f   Nitin Gupta   staging: zsmalloc...
1398
1399
   * Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail.
   */
d0d8da2dc   Sergey Senozhatsky   zsmalloc: require...
1400
  unsigned long zs_malloc(struct zs_pool *pool, size_t size, gfp_t gfp)
61989a80f   Nitin Gupta   staging: zsmalloc...
1401
  {
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1402
  	unsigned long handle, obj;
61989a80f   Nitin Gupta   staging: zsmalloc...
1403
  	struct size_class *class;
48b4800a1   Minchan Kim   zsmalloc: page mi...
1404
  	enum fullness_group newfg;
3783689a1   Minchan Kim   zsmalloc: introdu...
1405
  	struct zspage *zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
1406

7b60a6852   Minchan Kim   zsmalloc: record ...
1407
  	if (unlikely(!size || size > ZS_MAX_ALLOC_SIZE))
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1408
  		return 0;
3783689a1   Minchan Kim   zsmalloc: introdu...
1409
  	handle = cache_alloc_handle(pool, gfp);
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1410
  	if (!handle)
c23443483   Minchan Kim   staging: zsmalloc...
1411
  		return 0;
61989a80f   Nitin Gupta   staging: zsmalloc...
1412

2e40e163a   Minchan Kim   zsmalloc: decoupl...
1413
1414
  	/* extra space in chunk to keep the handle */
  	size += ZS_HANDLE_SIZE;
9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1415
  	class = pool->size_class[get_size_class_index(size)];
61989a80f   Nitin Gupta   staging: zsmalloc...
1416
1417
  
  	spin_lock(&class->lock);
3783689a1   Minchan Kim   zsmalloc: introdu...
1418
  	zspage = find_get_zspage(class);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1419
1420
1421
1422
1423
  	if (likely(zspage)) {
  		obj = obj_malloc(class, zspage, handle);
  		/* Now move the zspage to another fullness group, if required */
  		fix_fullness_group(class, zspage);
  		record_obj(handle, obj);
61989a80f   Nitin Gupta   staging: zsmalloc...
1424
  		spin_unlock(&class->lock);
61989a80f   Nitin Gupta   staging: zsmalloc...
1425

48b4800a1   Minchan Kim   zsmalloc: page mi...
1426
1427
  		return handle;
  	}
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
1428

48b4800a1   Minchan Kim   zsmalloc: page mi...
1429
1430
1431
1432
1433
1434
  	spin_unlock(&class->lock);
  
  	zspage = alloc_zspage(pool, class, gfp);
  	if (!zspage) {
  		cache_free_handle(pool, handle);
  		return 0;
61989a80f   Nitin Gupta   staging: zsmalloc...
1435
  	}
48b4800a1   Minchan Kim   zsmalloc: page mi...
1436
  	spin_lock(&class->lock);
3783689a1   Minchan Kim   zsmalloc: introdu...
1437
  	obj = obj_malloc(class, zspage, handle);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1438
1439
1440
  	newfg = get_fullness_group(class, zspage);
  	insert_zspage(class, zspage, newfg);
  	set_zspage_mapping(zspage, class->index, newfg);
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1441
  	record_obj(handle, obj);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1442
1443
  	atomic_long_add(class->pages_per_zspage,
  				&pool->pages_allocated);
b4fd07a08   Ganesh Mahendran   mm/zsmalloc: use ...
1444
  	zs_stat_inc(class, OBJ_ALLOCATED, class->objs_per_zspage);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1445
1446
1447
  
  	/* We completely set up zspage so mark them as movable */
  	SetZsPageMovable(pool, zspage);
61989a80f   Nitin Gupta   staging: zsmalloc...
1448
  	spin_unlock(&class->lock);
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1449
  	return handle;
61989a80f   Nitin Gupta   staging: zsmalloc...
1450
1451
  }
  EXPORT_SYMBOL_GPL(zs_malloc);
1ee471658   Minchan Kim   zsmalloc: remove ...
1452
  static void obj_free(struct size_class *class, unsigned long obj)
61989a80f   Nitin Gupta   staging: zsmalloc...
1453
1454
  {
  	struct link_free *link;
3783689a1   Minchan Kim   zsmalloc: introdu...
1455
1456
  	struct zspage *zspage;
  	struct page *f_page;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1457
1458
  	unsigned long f_offset;
  	unsigned int f_objidx;
af4ee5e97   Minchan Kim   zsmalloc: correct...
1459
  	void *vaddr;
61989a80f   Nitin Gupta   staging: zsmalloc...
1460

312fcae22   Minchan Kim   zsmalloc: support...
1461
  	obj &= ~OBJ_ALLOCATED_TAG;
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1462
  	obj_to_location(obj, &f_page, &f_objidx);
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1463
  	f_offset = (class->size * f_objidx) & ~PAGE_MASK;
3783689a1   Minchan Kim   zsmalloc: introdu...
1464
  	zspage = get_zspage(f_page);
61989a80f   Nitin Gupta   staging: zsmalloc...
1465

c78062612   Minchan Kim   zsmalloc: factor ...
1466
  	vaddr = kmap_atomic(f_page);
61989a80f   Nitin Gupta   staging: zsmalloc...
1467
1468
  
  	/* Insert this object in containing zspage's freelist */
af4ee5e97   Minchan Kim   zsmalloc: correct...
1469
  	link = (struct link_free *)(vaddr + f_offset);
3b1d9ca65   Minchan Kim   zsmalloc: use OBJ...
1470
  	link->next = get_freeobj(zspage) << OBJ_TAG_BITS;
af4ee5e97   Minchan Kim   zsmalloc: correct...
1471
  	kunmap_atomic(vaddr);
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1472
  	set_freeobj(zspage, f_objidx);
3783689a1   Minchan Kim   zsmalloc: introdu...
1473
  	mod_zspage_inuse(zspage, -1);
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
1474
  	zs_stat_dec(class, OBJ_USED, 1);
c78062612   Minchan Kim   zsmalloc: factor ...
1475
1476
1477
1478
  }
  
  void zs_free(struct zs_pool *pool, unsigned long handle)
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
1479
1480
  	struct zspage *zspage;
  	struct page *f_page;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1481
1482
  	unsigned long obj;
  	unsigned int f_objidx;
c78062612   Minchan Kim   zsmalloc: factor ...
1483
1484
1485
  	int class_idx;
  	struct size_class *class;
  	enum fullness_group fullness;
48b4800a1   Minchan Kim   zsmalloc: page mi...
1486
  	bool isolated;
c78062612   Minchan Kim   zsmalloc: factor ...
1487
1488
1489
  
  	if (unlikely(!handle))
  		return;
312fcae22   Minchan Kim   zsmalloc: support...
1490
  	pin_tag(handle);
c78062612   Minchan Kim   zsmalloc: factor ...
1491
  	obj = handle_to_obj(handle);
c78062612   Minchan Kim   zsmalloc: factor ...
1492
  	obj_to_location(obj, &f_page, &f_objidx);
3783689a1   Minchan Kim   zsmalloc: introdu...
1493
  	zspage = get_zspage(f_page);
c78062612   Minchan Kim   zsmalloc: factor ...
1494

48b4800a1   Minchan Kim   zsmalloc: page mi...
1495
  	migrate_read_lock(zspage);
3783689a1   Minchan Kim   zsmalloc: introdu...
1496
  	get_zspage_mapping(zspage, &class_idx, &fullness);
c78062612   Minchan Kim   zsmalloc: factor ...
1497
1498
1499
  	class = pool->size_class[class_idx];
  
  	spin_lock(&class->lock);
1ee471658   Minchan Kim   zsmalloc: remove ...
1500
  	obj_free(class, obj);
3783689a1   Minchan Kim   zsmalloc: introdu...
1501
  	fullness = fix_fullness_group(class, zspage);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1502
1503
1504
  	if (fullness != ZS_EMPTY) {
  		migrate_read_unlock(zspage);
  		goto out;
312fcae22   Minchan Kim   zsmalloc: support...
1505
  	}
48b4800a1   Minchan Kim   zsmalloc: page mi...
1506
1507
1508
1509
1510
1511
1512
  
  	isolated = is_zspage_isolated(zspage);
  	migrate_read_unlock(zspage);
  	/* If zspage is isolated, zs_page_putback will free the zspage */
  	if (likely(!isolated))
  		free_zspage(pool, class, zspage);
  out:
61989a80f   Nitin Gupta   staging: zsmalloc...
1513
  	spin_unlock(&class->lock);
312fcae22   Minchan Kim   zsmalloc: support...
1514
  	unpin_tag(handle);
3783689a1   Minchan Kim   zsmalloc: introdu...
1515
  	cache_free_handle(pool, handle);
312fcae22   Minchan Kim   zsmalloc: support...
1516
1517
  }
  EXPORT_SYMBOL_GPL(zs_free);
251cbb951   Minchan Kim   zsmalloc: reorder...
1518
1519
  static void zs_object_copy(struct size_class *class, unsigned long dst,
  				unsigned long src)
312fcae22   Minchan Kim   zsmalloc: support...
1520
1521
  {
  	struct page *s_page, *d_page;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1522
  	unsigned int s_objidx, d_objidx;
312fcae22   Minchan Kim   zsmalloc: support...
1523
1524
1525
1526
1527
1528
1529
1530
1531
  	unsigned long s_off, d_off;
  	void *s_addr, *d_addr;
  	int s_size, d_size, size;
  	int written = 0;
  
  	s_size = d_size = class->size;
  
  	obj_to_location(src, &s_page, &s_objidx);
  	obj_to_location(dst, &d_page, &d_objidx);
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1532
1533
  	s_off = (class->size * s_objidx) & ~PAGE_MASK;
  	d_off = (class->size * d_objidx) & ~PAGE_MASK;
312fcae22   Minchan Kim   zsmalloc: support...
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
  
  	if (s_off + class->size > PAGE_SIZE)
  		s_size = PAGE_SIZE - s_off;
  
  	if (d_off + class->size > PAGE_SIZE)
  		d_size = PAGE_SIZE - d_off;
  
  	s_addr = kmap_atomic(s_page);
  	d_addr = kmap_atomic(d_page);
  
  	while (1) {
  		size = min(s_size, d_size);
  		memcpy(d_addr + d_off, s_addr + s_off, size);
  		written += size;
  
  		if (written == class->size)
  			break;
495819ead   Sergey Senozhatsky   zsmalloc: micro-o...
1551
1552
1553
1554
1555
1556
  		s_off += size;
  		s_size -= size;
  		d_off += size;
  		d_size -= size;
  
  		if (s_off >= PAGE_SIZE) {
312fcae22   Minchan Kim   zsmalloc: support...
1557
1558
1559
  			kunmap_atomic(d_addr);
  			kunmap_atomic(s_addr);
  			s_page = get_next_page(s_page);
312fcae22   Minchan Kim   zsmalloc: support...
1560
1561
1562
1563
  			s_addr = kmap_atomic(s_page);
  			d_addr = kmap_atomic(d_page);
  			s_size = class->size - written;
  			s_off = 0;
312fcae22   Minchan Kim   zsmalloc: support...
1564
  		}
495819ead   Sergey Senozhatsky   zsmalloc: micro-o...
1565
  		if (d_off >= PAGE_SIZE) {
312fcae22   Minchan Kim   zsmalloc: support...
1566
1567
  			kunmap_atomic(d_addr);
  			d_page = get_next_page(d_page);
312fcae22   Minchan Kim   zsmalloc: support...
1568
1569
1570
  			d_addr = kmap_atomic(d_page);
  			d_size = class->size - written;
  			d_off = 0;
312fcae22   Minchan Kim   zsmalloc: support...
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
  		}
  	}
  
  	kunmap_atomic(d_addr);
  	kunmap_atomic(s_addr);
  }
  
  /*
   * Find alloced object in zspage from index object and
   * return handle.
   */
251cbb951   Minchan Kim   zsmalloc: reorder...
1582
  static unsigned long find_alloced_obj(struct size_class *class,
cf675acb7   Ganesh Mahendran   mm/zsmalloc: take...
1583
  					struct page *page, int *obj_idx)
312fcae22   Minchan Kim   zsmalloc: support...
1584
1585
1586
  {
  	unsigned long head;
  	int offset = 0;
cf675acb7   Ganesh Mahendran   mm/zsmalloc: take...
1587
  	int index = *obj_idx;
312fcae22   Minchan Kim   zsmalloc: support...
1588
1589
  	unsigned long handle = 0;
  	void *addr = kmap_atomic(page);
3783689a1   Minchan Kim   zsmalloc: introdu...
1590
  	offset = get_first_obj_offset(page);
312fcae22   Minchan Kim   zsmalloc: support...
1591
1592
1593
  	offset += class->size * index;
  
  	while (offset < PAGE_SIZE) {
48b4800a1   Minchan Kim   zsmalloc: page mi...
1594
  		head = obj_to_head(page, addr + offset);
312fcae22   Minchan Kim   zsmalloc: support...
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
  		if (head & OBJ_ALLOCATED_TAG) {
  			handle = head & ~OBJ_ALLOCATED_TAG;
  			if (trypin_tag(handle))
  				break;
  			handle = 0;
  		}
  
  		offset += class->size;
  		index++;
  	}
  
  	kunmap_atomic(addr);
cf675acb7   Ganesh Mahendran   mm/zsmalloc: take...
1607
1608
  
  	*obj_idx = index;
312fcae22   Minchan Kim   zsmalloc: support...
1609
1610
1611
1612
  	return handle;
  }
  
  struct zs_compact_control {
3783689a1   Minchan Kim   zsmalloc: introdu...
1613
  	/* Source spage for migration which could be a subpage of zspage */
312fcae22   Minchan Kim   zsmalloc: support...
1614
1615
1616
1617
1618
1619
  	struct page *s_page;
  	/* Destination page for migration which should be a first page
  	 * of zspage. */
  	struct page *d_page;
  	 /* Starting object index within @s_page which used for live object
  	  * in the subpage. */
41b88e14c   Ganesh Mahendran   mm/zsmalloc: use ...
1620
  	int obj_idx;
312fcae22   Minchan Kim   zsmalloc: support...
1621
1622
1623
1624
1625
1626
1627
1628
1629
  };
  
  static int migrate_zspage(struct zs_pool *pool, struct size_class *class,
  				struct zs_compact_control *cc)
  {
  	unsigned long used_obj, free_obj;
  	unsigned long handle;
  	struct page *s_page = cc->s_page;
  	struct page *d_page = cc->d_page;
41b88e14c   Ganesh Mahendran   mm/zsmalloc: use ...
1630
  	int obj_idx = cc->obj_idx;
312fcae22   Minchan Kim   zsmalloc: support...
1631
1632
1633
  	int ret = 0;
  
  	while (1) {
cf675acb7   Ganesh Mahendran   mm/zsmalloc: take...
1634
  		handle = find_alloced_obj(class, s_page, &obj_idx);
312fcae22   Minchan Kim   zsmalloc: support...
1635
1636
1637
1638
  		if (!handle) {
  			s_page = get_next_page(s_page);
  			if (!s_page)
  				break;
41b88e14c   Ganesh Mahendran   mm/zsmalloc: use ...
1639
  			obj_idx = 0;
312fcae22   Minchan Kim   zsmalloc: support...
1640
1641
1642
1643
  			continue;
  		}
  
  		/* Stop if there is no more space */
3783689a1   Minchan Kim   zsmalloc: introdu...
1644
  		if (zspage_full(class, get_zspage(d_page))) {
312fcae22   Minchan Kim   zsmalloc: support...
1645
1646
1647
1648
1649
1650
  			unpin_tag(handle);
  			ret = -ENOMEM;
  			break;
  		}
  
  		used_obj = handle_to_obj(handle);
3783689a1   Minchan Kim   zsmalloc: introdu...
1651
  		free_obj = obj_malloc(class, get_zspage(d_page), handle);
251cbb951   Minchan Kim   zsmalloc: reorder...
1652
  		zs_object_copy(class, free_obj, used_obj);
41b88e14c   Ganesh Mahendran   mm/zsmalloc: use ...
1653
  		obj_idx++;
c102f07ca   Junil Lee   zsmalloc: fix mig...
1654
1655
1656
1657
1658
1659
1660
  		/*
  		 * record_obj updates handle's value to free_obj and it will
  		 * invalidate lock bit(ie, HANDLE_PIN_BIT) of handle, which
  		 * breaks synchronization using pin_tag(e,g, zs_free) so
  		 * let's keep the lock bit.
  		 */
  		free_obj |= BIT(HANDLE_PIN_BIT);
312fcae22   Minchan Kim   zsmalloc: support...
1661
1662
  		record_obj(handle, free_obj);
  		unpin_tag(handle);
1ee471658   Minchan Kim   zsmalloc: remove ...
1663
  		obj_free(class, used_obj);
312fcae22   Minchan Kim   zsmalloc: support...
1664
1665
1666
1667
  	}
  
  	/* Remember last position in this iteration */
  	cc->s_page = s_page;
41b88e14c   Ganesh Mahendran   mm/zsmalloc: use ...
1668
  	cc->obj_idx = obj_idx;
312fcae22   Minchan Kim   zsmalloc: support...
1669
1670
1671
  
  	return ret;
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
1672
  static struct zspage *isolate_zspage(struct size_class *class, bool source)
312fcae22   Minchan Kim   zsmalloc: support...
1673
1674
  {
  	int i;
3783689a1   Minchan Kim   zsmalloc: introdu...
1675
1676
  	struct zspage *zspage;
  	enum fullness_group fg[2] = {ZS_ALMOST_EMPTY, ZS_ALMOST_FULL};
312fcae22   Minchan Kim   zsmalloc: support...
1677

3783689a1   Minchan Kim   zsmalloc: introdu...
1678
1679
1680
1681
1682
1683
1684
1685
1686
  	if (!source) {
  		fg[0] = ZS_ALMOST_FULL;
  		fg[1] = ZS_ALMOST_EMPTY;
  	}
  
  	for (i = 0; i < 2; i++) {
  		zspage = list_first_entry_or_null(&class->fullness_list[fg[i]],
  							struct zspage, list);
  		if (zspage) {
48b4800a1   Minchan Kim   zsmalloc: page mi...
1687
  			VM_BUG_ON(is_zspage_isolated(zspage));
3783689a1   Minchan Kim   zsmalloc: introdu...
1688
1689
  			remove_zspage(class, zspage, fg[i]);
  			return zspage;
312fcae22   Minchan Kim   zsmalloc: support...
1690
1691
  		}
  	}
3783689a1   Minchan Kim   zsmalloc: introdu...
1692
  	return zspage;
312fcae22   Minchan Kim   zsmalloc: support...
1693
  }
860c707dc   Sergey Senozhatsky   zsmalloc: account...
1694
  /*
3783689a1   Minchan Kim   zsmalloc: introdu...
1695
   * putback_zspage - add @zspage into right class's fullness list
860c707dc   Sergey Senozhatsky   zsmalloc: account...
1696
   * @class: destination class
3783689a1   Minchan Kim   zsmalloc: introdu...
1697
   * @zspage: target page
860c707dc   Sergey Senozhatsky   zsmalloc: account...
1698
   *
3783689a1   Minchan Kim   zsmalloc: introdu...
1699
   * Return @zspage's fullness_group
860c707dc   Sergey Senozhatsky   zsmalloc: account...
1700
   */
4aa409cab   Minchan Kim   zsmalloc: separat...
1701
  static enum fullness_group putback_zspage(struct size_class *class,
3783689a1   Minchan Kim   zsmalloc: introdu...
1702
  			struct zspage *zspage)
312fcae22   Minchan Kim   zsmalloc: support...
1703
  {
312fcae22   Minchan Kim   zsmalloc: support...
1704
  	enum fullness_group fullness;
48b4800a1   Minchan Kim   zsmalloc: page mi...
1705
  	VM_BUG_ON(is_zspage_isolated(zspage));
3783689a1   Minchan Kim   zsmalloc: introdu...
1706
1707
1708
  	fullness = get_fullness_group(class, zspage);
  	insert_zspage(class, zspage, fullness);
  	set_zspage_mapping(zspage, class->index, fullness);
839373e64   Minchan Kim   zsmalloc: remove ...
1709

860c707dc   Sergey Senozhatsky   zsmalloc: account...
1710
  	return fullness;
61989a80f   Nitin Gupta   staging: zsmalloc...
1711
  }
312fcae22   Minchan Kim   zsmalloc: support...
1712

48b4800a1   Minchan Kim   zsmalloc: page mi...
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
  #ifdef CONFIG_COMPACTION
  static struct dentry *zs_mount(struct file_system_type *fs_type,
  				int flags, const char *dev_name, void *data)
  {
  	static const struct dentry_operations ops = {
  		.d_dname = simple_dname,
  	};
  
  	return mount_pseudo(fs_type, "zsmalloc:", NULL, &ops, ZSMALLOC_MAGIC);
  }
  
  static struct file_system_type zsmalloc_fs = {
  	.name		= "zsmalloc",
  	.mount		= zs_mount,
  	.kill_sb	= kill_anon_super,
  };
  
  static int zsmalloc_mount(void)
  {
  	int ret = 0;
  
  	zsmalloc_mnt = kern_mount(&zsmalloc_fs);
  	if (IS_ERR(zsmalloc_mnt))
  		ret = PTR_ERR(zsmalloc_mnt);
  
  	return ret;
  }
  
  static void zsmalloc_unmount(void)
  {
  	kern_unmount(zsmalloc_mnt);
  }
  
  static void migrate_lock_init(struct zspage *zspage)
  {
  	rwlock_init(&zspage->lock);
  }
  
  static void migrate_read_lock(struct zspage *zspage)
  {
  	read_lock(&zspage->lock);
  }
  
  static void migrate_read_unlock(struct zspage *zspage)
  {
  	read_unlock(&zspage->lock);
  }
  
  static void migrate_write_lock(struct zspage *zspage)
  {
  	write_lock(&zspage->lock);
  }
  
  static void migrate_write_unlock(struct zspage *zspage)
  {
  	write_unlock(&zspage->lock);
  }
  
  /* Number of isolated subpage for *page migration* in this zspage */
  static void inc_zspage_isolation(struct zspage *zspage)
  {
  	zspage->isolated++;
  }
  
  static void dec_zspage_isolation(struct zspage *zspage)
  {
  	zspage->isolated--;
  }
  
  static void replace_sub_page(struct size_class *class, struct zspage *zspage,
  				struct page *newpage, struct page *oldpage)
  {
  	struct page *page;
  	struct page *pages[ZS_MAX_PAGES_PER_ZSPAGE] = {NULL, };
  	int idx = 0;
  
  	page = get_first_page(zspage);
  	do {
  		if (page == oldpage)
  			pages[idx] = newpage;
  		else
  			pages[idx] = page;
  		idx++;
  	} while ((page = get_next_page(page)) != NULL);
  
  	create_page_chain(class, zspage, pages);
  	set_first_obj_offset(newpage, get_first_obj_offset(oldpage));
  	if (unlikely(PageHugeObject(oldpage)))
  		newpage->index = oldpage->index;
  	__SetPageMovable(newpage, page_mapping(oldpage));
  }
  
  bool zs_page_isolate(struct page *page, isolate_mode_t mode)
  {
  	struct zs_pool *pool;
  	struct size_class *class;
  	int class_idx;
  	enum fullness_group fullness;
  	struct zspage *zspage;
  	struct address_space *mapping;
  
  	/*
  	 * Page is locked so zspage couldn't be destroyed. For detail, look at
  	 * lock_zspage in free_zspage.
  	 */
  	VM_BUG_ON_PAGE(!PageMovable(page), page);
  	VM_BUG_ON_PAGE(PageIsolated(page), page);
  
  	zspage = get_zspage(page);
  
  	/*
  	 * Without class lock, fullness could be stale while class_idx is okay
  	 * because class_idx is constant unless page is freed so we should get
  	 * fullness again under class lock.
  	 */
  	get_zspage_mapping(zspage, &class_idx, &fullness);
  	mapping = page_mapping(page);
  	pool = mapping->private_data;
  	class = pool->size_class[class_idx];
  
  	spin_lock(&class->lock);
  	if (get_zspage_inuse(zspage) == 0) {
  		spin_unlock(&class->lock);
  		return false;
  	}
  
  	/* zspage is isolated for object migration */
  	if (list_empty(&zspage->list) && !is_zspage_isolated(zspage)) {
  		spin_unlock(&class->lock);
  		return false;
  	}
  
  	/*
  	 * If this is first time isolation for the zspage, isolate zspage from
  	 * size_class to prevent further object allocation from the zspage.
  	 */
  	if (!list_empty(&zspage->list) && !is_zspage_isolated(zspage)) {
  		get_zspage_mapping(zspage, &class_idx, &fullness);
  		remove_zspage(class, zspage, fullness);
  	}
  
  	inc_zspage_isolation(zspage);
  	spin_unlock(&class->lock);
  
  	return true;
  }
  
  int zs_page_migrate(struct address_space *mapping, struct page *newpage,
  		struct page *page, enum migrate_mode mode)
  {
  	struct zs_pool *pool;
  	struct size_class *class;
  	int class_idx;
  	enum fullness_group fullness;
  	struct zspage *zspage;
  	struct page *dummy;
  	void *s_addr, *d_addr, *addr;
  	int offset, pos;
  	unsigned long handle, head;
  	unsigned long old_obj, new_obj;
  	unsigned int obj_idx;
  	int ret = -EAGAIN;
2916ecc0f   Jérôme Glisse   mm/migrate: new m...
1875
1876
1877
1878
1879
1880
1881
  	/*
  	 * We cannot support the _NO_COPY case here, because copy needs to
  	 * happen under the zs lock, which does not work with
  	 * MIGRATE_SYNC_NO_COPY workflow.
  	 */
  	if (mode == MIGRATE_SYNC_NO_COPY)
  		return -EINVAL;
48b4800a1   Minchan Kim   zsmalloc: page mi...
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
  	VM_BUG_ON_PAGE(!PageMovable(page), page);
  	VM_BUG_ON_PAGE(!PageIsolated(page), page);
  
  	zspage = get_zspage(page);
  
  	/* Concurrent compactor cannot migrate any subpage in zspage */
  	migrate_write_lock(zspage);
  	get_zspage_mapping(zspage, &class_idx, &fullness);
  	pool = mapping->private_data;
  	class = pool->size_class[class_idx];
  	offset = get_first_obj_offset(page);
  
  	spin_lock(&class->lock);
  	if (!get_zspage_inuse(zspage)) {
77ff46579   Hui Zhu   zsmalloc: zs_page...
1896
1897
1898
1899
1900
  		/*
  		 * Set "offset" to end of the page so that every loops
  		 * skips unnecessary object scanning.
  		 */
  		offset = PAGE_SIZE;
48b4800a1   Minchan Kim   zsmalloc: page mi...
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
  	}
  
  	pos = offset;
  	s_addr = kmap_atomic(page);
  	while (pos < PAGE_SIZE) {
  		head = obj_to_head(page, s_addr + pos);
  		if (head & OBJ_ALLOCATED_TAG) {
  			handle = head & ~OBJ_ALLOCATED_TAG;
  			if (!trypin_tag(handle))
  				goto unpin_objects;
  		}
  		pos += class->size;
  	}
  
  	/*
  	 * Here, any user cannot access all objects in the zspage so let's move.
  	 */
  	d_addr = kmap_atomic(newpage);
  	memcpy(d_addr, s_addr, PAGE_SIZE);
  	kunmap_atomic(d_addr);
  
  	for (addr = s_addr + offset; addr < s_addr + pos;
  					addr += class->size) {
  		head = obj_to_head(page, addr);
  		if (head & OBJ_ALLOCATED_TAG) {
  			handle = head & ~OBJ_ALLOCATED_TAG;
  			if (!testpin_tag(handle))
  				BUG();
  
  			old_obj = handle_to_obj(handle);
  			obj_to_location(old_obj, &dummy, &obj_idx);
  			new_obj = (unsigned long)location_to_obj(newpage,
  								obj_idx);
  			new_obj |= BIT(HANDLE_PIN_BIT);
  			record_obj(handle, new_obj);
  		}
  	}
  
  	replace_sub_page(class, zspage, newpage, page);
  	get_page(newpage);
  
  	dec_zspage_isolation(zspage);
  
  	/*
  	 * Page migration is done so let's putback isolated zspage to
  	 * the list if @page is final isolated subpage in the zspage.
  	 */
  	if (!is_zspage_isolated(zspage))
  		putback_zspage(class, zspage);
  
  	reset_page(page);
  	put_page(page);
  	page = newpage;
dd4123f32   Minchan Kim   mm: fix build war...
1954
  	ret = MIGRATEPAGE_SUCCESS;
48b4800a1   Minchan Kim   zsmalloc: page mi...
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
  unpin_objects:
  	for (addr = s_addr + offset; addr < s_addr + pos;
  						addr += class->size) {
  		head = obj_to_head(page, addr);
  		if (head & OBJ_ALLOCATED_TAG) {
  			handle = head & ~OBJ_ALLOCATED_TAG;
  			if (!testpin_tag(handle))
  				BUG();
  			unpin_tag(handle);
  		}
  	}
  	kunmap_atomic(s_addr);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
  	spin_unlock(&class->lock);
  	migrate_write_unlock(zspage);
  
  	return ret;
  }
  
  void zs_page_putback(struct page *page)
  {
  	struct zs_pool *pool;
  	struct size_class *class;
  	int class_idx;
  	enum fullness_group fg;
  	struct address_space *mapping;
  	struct zspage *zspage;
  
  	VM_BUG_ON_PAGE(!PageMovable(page), page);
  	VM_BUG_ON_PAGE(!PageIsolated(page), page);
  
  	zspage = get_zspage(page);
  	get_zspage_mapping(zspage, &class_idx, &fg);
  	mapping = page_mapping(page);
  	pool = mapping->private_data;
  	class = pool->size_class[class_idx];
  
  	spin_lock(&class->lock);
  	dec_zspage_isolation(zspage);
  	if (!is_zspage_isolated(zspage)) {
  		fg = putback_zspage(class, zspage);
  		/*
  		 * Due to page_lock, we cannot free zspage immediately
  		 * so let's defer.
  		 */
  		if (fg == ZS_EMPTY)
  			schedule_work(&pool->free_work);
  	}
  	spin_unlock(&class->lock);
  }
  
  const struct address_space_operations zsmalloc_aops = {
  	.isolate_page = zs_page_isolate,
  	.migratepage = zs_page_migrate,
  	.putback_page = zs_page_putback,
  };
  
  static int zs_register_migration(struct zs_pool *pool)
  {
  	pool->inode = alloc_anon_inode(zsmalloc_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 = &zsmalloc_aops;
  	return 0;
  }
  
  static void zs_unregister_migration(struct zs_pool *pool)
  {
  	flush_work(&pool->free_work);
c3491eca3   Markus Elfring   zsmalloc: Delete ...
2027
  	iput(pool->inode);
48b4800a1   Minchan Kim   zsmalloc: page mi...
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
  }
  
  /*
   * Caller should hold page_lock of all pages in the zspage
   * In here, we cannot use zspage meta data.
   */
  static void async_free_zspage(struct work_struct *work)
  {
  	int i;
  	struct size_class *class;
  	unsigned int class_idx;
  	enum fullness_group fullness;
  	struct zspage *zspage, *tmp;
  	LIST_HEAD(free_pages);
  	struct zs_pool *pool = container_of(work, struct zs_pool,
  					free_work);
cf8e0fedf   Jerome Marchand   mm/zsmalloc: simp...
2044
  	for (i = 0; i < ZS_SIZE_CLASSES; i++) {
48b4800a1   Minchan Kim   zsmalloc: page mi...
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
  		class = pool->size_class[i];
  		if (class->index != i)
  			continue;
  
  		spin_lock(&class->lock);
  		list_splice_init(&class->fullness_list[ZS_EMPTY], &free_pages);
  		spin_unlock(&class->lock);
  	}
  
  
  	list_for_each_entry_safe(zspage, tmp, &free_pages, list) {
  		list_del(&zspage->list);
  		lock_zspage(zspage);
  
  		get_zspage_mapping(zspage, &class_idx, &fullness);
  		VM_BUG_ON(fullness != ZS_EMPTY);
  		class = pool->size_class[class_idx];
  		spin_lock(&class->lock);
  		__free_zspage(pool, pool->size_class[class_idx], zspage);
  		spin_unlock(&class->lock);
  	}
  };
  
  static void kick_deferred_free(struct zs_pool *pool)
  {
  	schedule_work(&pool->free_work);
  }
  
  static void init_deferred_free(struct zs_pool *pool)
  {
  	INIT_WORK(&pool->free_work, async_free_zspage);
  }
  
  static void SetZsPageMovable(struct zs_pool *pool, struct zspage *zspage)
  {
  	struct page *page = get_first_page(zspage);
  
  	do {
  		WARN_ON(!trylock_page(page));
  		__SetPageMovable(page, pool->inode->i_mapping);
  		unlock_page(page);
  	} while ((page = get_next_page(page)) != NULL);
  }
  #endif
04f05909e   Sergey Senozhatsky   zsmalloc: introdu...
2089
2090
2091
2092
  /*
   *
   * Based on the number of unused allocated objects calculate
   * and return the number of pages that we can free.
04f05909e   Sergey Senozhatsky   zsmalloc: introdu...
2093
2094
2095
2096
   */
  static unsigned long zs_can_compact(struct size_class *class)
  {
  	unsigned long obj_wasted;
44f43e99f   Sergey Senozhatsky   zsmalloc: fix zs_...
2097
2098
  	unsigned long obj_allocated = zs_stat_get(class, OBJ_ALLOCATED);
  	unsigned long obj_used = zs_stat_get(class, OBJ_USED);
04f05909e   Sergey Senozhatsky   zsmalloc: introdu...
2099

44f43e99f   Sergey Senozhatsky   zsmalloc: fix zs_...
2100
2101
  	if (obj_allocated <= obj_used)
  		return 0;
04f05909e   Sergey Senozhatsky   zsmalloc: introdu...
2102

44f43e99f   Sergey Senozhatsky   zsmalloc: fix zs_...
2103
  	obj_wasted = obj_allocated - obj_used;
b4fd07a08   Ganesh Mahendran   mm/zsmalloc: use ...
2104
  	obj_wasted /= class->objs_per_zspage;
04f05909e   Sergey Senozhatsky   zsmalloc: introdu...
2105

6cbf16b3b   Minchan Kim   zsmalloc: use cla...
2106
  	return obj_wasted * class->pages_per_zspage;
04f05909e   Sergey Senozhatsky   zsmalloc: introdu...
2107
  }
7d3f39382   Sergey Senozhatsky   zsmalloc/zram: in...
2108
  static void __zs_compact(struct zs_pool *pool, struct size_class *class)
312fcae22   Minchan Kim   zsmalloc: support...
2109
  {
312fcae22   Minchan Kim   zsmalloc: support...
2110
  	struct zs_compact_control cc;
3783689a1   Minchan Kim   zsmalloc: introdu...
2111
2112
  	struct zspage *src_zspage;
  	struct zspage *dst_zspage = NULL;
312fcae22   Minchan Kim   zsmalloc: support...
2113

312fcae22   Minchan Kim   zsmalloc: support...
2114
  	spin_lock(&class->lock);
3783689a1   Minchan Kim   zsmalloc: introdu...
2115
  	while ((src_zspage = isolate_zspage(class, true))) {
312fcae22   Minchan Kim   zsmalloc: support...
2116

04f05909e   Sergey Senozhatsky   zsmalloc: introdu...
2117
2118
  		if (!zs_can_compact(class))
  			break;
41b88e14c   Ganesh Mahendran   mm/zsmalloc: use ...
2119
  		cc.obj_idx = 0;
48b4800a1   Minchan Kim   zsmalloc: page mi...
2120
  		cc.s_page = get_first_page(src_zspage);
312fcae22   Minchan Kim   zsmalloc: support...
2121

3783689a1   Minchan Kim   zsmalloc: introdu...
2122
  		while ((dst_zspage = isolate_zspage(class, false))) {
48b4800a1   Minchan Kim   zsmalloc: page mi...
2123
  			cc.d_page = get_first_page(dst_zspage);
312fcae22   Minchan Kim   zsmalloc: support...
2124
  			/*
0dc63d488   Sergey Senozhatsky   zsmalloc: cosmeti...
2125
2126
  			 * If there is no more space in dst_page, resched
  			 * and see if anyone had allocated another zspage.
312fcae22   Minchan Kim   zsmalloc: support...
2127
2128
2129
  			 */
  			if (!migrate_zspage(pool, class, &cc))
  				break;
4aa409cab   Minchan Kim   zsmalloc: separat...
2130
  			putback_zspage(class, dst_zspage);
312fcae22   Minchan Kim   zsmalloc: support...
2131
2132
2133
  		}
  
  		/* Stop if we couldn't find slot */
3783689a1   Minchan Kim   zsmalloc: introdu...
2134
  		if (dst_zspage == NULL)
312fcae22   Minchan Kim   zsmalloc: support...
2135
  			break;
4aa409cab   Minchan Kim   zsmalloc: separat...
2136
2137
  		putback_zspage(class, dst_zspage);
  		if (putback_zspage(class, src_zspage) == ZS_EMPTY) {
48b4800a1   Minchan Kim   zsmalloc: page mi...
2138
  			free_zspage(pool, class, src_zspage);
6cbf16b3b   Minchan Kim   zsmalloc: use cla...
2139
  			pool->stats.pages_compacted += class->pages_per_zspage;
4aa409cab   Minchan Kim   zsmalloc: separat...
2140
  		}
312fcae22   Minchan Kim   zsmalloc: support...
2141
  		spin_unlock(&class->lock);
312fcae22   Minchan Kim   zsmalloc: support...
2142
2143
2144
  		cond_resched();
  		spin_lock(&class->lock);
  	}
3783689a1   Minchan Kim   zsmalloc: introdu...
2145
  	if (src_zspage)
4aa409cab   Minchan Kim   zsmalloc: separat...
2146
  		putback_zspage(class, src_zspage);
312fcae22   Minchan Kim   zsmalloc: support...
2147

7d3f39382   Sergey Senozhatsky   zsmalloc/zram: in...
2148
  	spin_unlock(&class->lock);
312fcae22   Minchan Kim   zsmalloc: support...
2149
2150
2151
2152
2153
  }
  
  unsigned long zs_compact(struct zs_pool *pool)
  {
  	int i;
312fcae22   Minchan Kim   zsmalloc: support...
2154
  	struct size_class *class;
cf8e0fedf   Jerome Marchand   mm/zsmalloc: simp...
2155
  	for (i = ZS_SIZE_CLASSES - 1; i >= 0; i--) {
312fcae22   Minchan Kim   zsmalloc: support...
2156
2157
2158
2159
2160
  		class = pool->size_class[i];
  		if (!class)
  			continue;
  		if (class->index != i)
  			continue;
7d3f39382   Sergey Senozhatsky   zsmalloc/zram: in...
2161
  		__zs_compact(pool, class);
312fcae22   Minchan Kim   zsmalloc: support...
2162
  	}
860c707dc   Sergey Senozhatsky   zsmalloc: account...
2163
  	return pool->stats.pages_compacted;
312fcae22   Minchan Kim   zsmalloc: support...
2164
2165
  }
  EXPORT_SYMBOL_GPL(zs_compact);
61989a80f   Nitin Gupta   staging: zsmalloc...
2166

7d3f39382   Sergey Senozhatsky   zsmalloc/zram: in...
2167
2168
2169
2170
2171
  void zs_pool_stats(struct zs_pool *pool, struct zs_pool_stats *stats)
  {
  	memcpy(stats, &pool->stats, sizeof(struct zs_pool_stats));
  }
  EXPORT_SYMBOL_GPL(zs_pool_stats);
ab9d306d9   Sergey Senozhatsky   zsmalloc: use shr...
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
  static unsigned long zs_shrinker_scan(struct shrinker *shrinker,
  		struct shrink_control *sc)
  {
  	unsigned long pages_freed;
  	struct zs_pool *pool = container_of(shrinker, struct zs_pool,
  			shrinker);
  
  	pages_freed = pool->stats.pages_compacted;
  	/*
  	 * Compact classes and calculate compaction delta.
  	 * Can run concurrently with a manually triggered
  	 * (by user) compaction.
  	 */
  	pages_freed = zs_compact(pool) - pages_freed;
  
  	return pages_freed ? pages_freed : SHRINK_STOP;
  }
  
  static unsigned long zs_shrinker_count(struct shrinker *shrinker,
  		struct shrink_control *sc)
  {
  	int i;
  	struct size_class *class;
  	unsigned long pages_to_free = 0;
  	struct zs_pool *pool = container_of(shrinker, struct zs_pool,
  			shrinker);
cf8e0fedf   Jerome Marchand   mm/zsmalloc: simp...
2198
  	for (i = ZS_SIZE_CLASSES - 1; i >= 0; i--) {
ab9d306d9   Sergey Senozhatsky   zsmalloc: use shr...
2199
2200
2201
2202
2203
  		class = pool->size_class[i];
  		if (!class)
  			continue;
  		if (class->index != i)
  			continue;
ab9d306d9   Sergey Senozhatsky   zsmalloc: use shr...
2204
  		pages_to_free += zs_can_compact(class);
ab9d306d9   Sergey Senozhatsky   zsmalloc: use shr...
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
  	}
  
  	return pages_to_free;
  }
  
  static void zs_unregister_shrinker(struct zs_pool *pool)
  {
  	if (pool->shrinker_enabled) {
  		unregister_shrinker(&pool->shrinker);
  		pool->shrinker_enabled = false;
  	}
  }
  
  static int zs_register_shrinker(struct zs_pool *pool)
  {
  	pool->shrinker.scan_objects = zs_shrinker_scan;
  	pool->shrinker.count_objects = zs_shrinker_count;
  	pool->shrinker.batch = 0;
  	pool->shrinker.seeks = DEFAULT_SEEKS;
  
  	return register_shrinker(&pool->shrinker);
  }
00a61d861   Minchan Kim   staging: zsmalloc...
2227
  /**
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2228
   * zs_create_pool - Creates an allocation pool to work from.
fd8544639   Ganesh Mahendran   mm/zsmalloc: keep...
2229
   * @name: pool name to be created
166cfda75   Seth Jennings   staging: zsmalloc...
2230
   *
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2231
2232
   * This function must be called before anything when using
   * the zsmalloc allocator.
166cfda75   Seth Jennings   staging: zsmalloc...
2233
   *
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2234
2235
   * On success, a pointer to the newly created pool is returned,
   * otherwise NULL.
396b7fd6f   Sara Bird   staging/zsmalloc:...
2236
   */
d0d8da2dc   Sergey Senozhatsky   zsmalloc: require...
2237
  struct zs_pool *zs_create_pool(const char *name)
61989a80f   Nitin Gupta   staging: zsmalloc...
2238
  {
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2239
2240
2241
  	int i;
  	struct zs_pool *pool;
  	struct size_class *prev_class = NULL;
61989a80f   Nitin Gupta   staging: zsmalloc...
2242

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2243
2244
2245
  	pool = kzalloc(sizeof(*pool), GFP_KERNEL);
  	if (!pool)
  		return NULL;
61989a80f   Nitin Gupta   staging: zsmalloc...
2246

48b4800a1   Minchan Kim   zsmalloc: page mi...
2247
  	init_deferred_free(pool);
61989a80f   Nitin Gupta   staging: zsmalloc...
2248

2e40e163a   Minchan Kim   zsmalloc: decoupl...
2249
2250
2251
  	pool->name = kstrdup(name, GFP_KERNEL);
  	if (!pool->name)
  		goto err;
3783689a1   Minchan Kim   zsmalloc: introdu...
2252
  	if (create_cache(pool))
2e40e163a   Minchan Kim   zsmalloc: decoupl...
2253
  		goto err;
c60369f01   Seth Jennings   staging: zsmalloc...
2254
  	/*
399d8eebe   Xishi Qiu   mm: fix some typo...
2255
  	 * Iterate reversely, because, size of size_class that we want to use
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2256
  	 * for merging should be larger or equal to current size.
c60369f01   Seth Jennings   staging: zsmalloc...
2257
  	 */
cf8e0fedf   Jerome Marchand   mm/zsmalloc: simp...
2258
  	for (i = ZS_SIZE_CLASSES - 1; i >= 0; i--) {
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2259
2260
  		int size;
  		int pages_per_zspage;
64d90465f   Ganesh Mahendran   mm/zsmalloc: avoi...
2261
  		int objs_per_zspage;
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2262
  		struct size_class *class;
3783689a1   Minchan Kim   zsmalloc: introdu...
2263
  		int fullness = 0;
c60369f01   Seth Jennings   staging: zsmalloc...
2264

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2265
2266
2267
2268
  		size = ZS_MIN_ALLOC_SIZE + i * ZS_SIZE_CLASS_DELTA;
  		if (size > ZS_MAX_ALLOC_SIZE)
  			size = ZS_MAX_ALLOC_SIZE;
  		pages_per_zspage = get_pages_per_zspage(size);
64d90465f   Ganesh Mahendran   mm/zsmalloc: avoi...
2269
  		objs_per_zspage = pages_per_zspage * PAGE_SIZE / size;
61989a80f   Nitin Gupta   staging: zsmalloc...
2270

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
  		/*
  		 * size_class is used for normal zsmalloc operation such
  		 * as alloc/free for that size. Although it is natural that we
  		 * have one size_class for each size, there is a chance that we
  		 * can get more memory utilization if we use one size_class for
  		 * many different sizes whose size_class have same
  		 * characteristics. So, we makes size_class point to
  		 * previous size_class if possible.
  		 */
  		if (prev_class) {
64d90465f   Ganesh Mahendran   mm/zsmalloc: avoi...
2281
  			if (can_merge(prev_class, pages_per_zspage, objs_per_zspage)) {
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
  				pool->size_class[i] = prev_class;
  				continue;
  			}
  		}
  
  		class = kzalloc(sizeof(struct size_class), GFP_KERNEL);
  		if (!class)
  			goto err;
  
  		class->size = size;
  		class->index = i;
  		class->pages_per_zspage = pages_per_zspage;
64d90465f   Ganesh Mahendran   mm/zsmalloc: avoi...
2294
  		class->objs_per_zspage = objs_per_zspage;
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2295
2296
  		spin_lock_init(&class->lock);
  		pool->size_class[i] = class;
48b4800a1   Minchan Kim   zsmalloc: page mi...
2297
2298
  		for (fullness = ZS_EMPTY; fullness < NR_ZS_FULLNESS;
  							fullness++)
3783689a1   Minchan Kim   zsmalloc: introdu...
2299
  			INIT_LIST_HEAD(&class->fullness_list[fullness]);
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2300
2301
  
  		prev_class = class;
61989a80f   Nitin Gupta   staging: zsmalloc...
2302
  	}
d34f61572   Dan Streetman   mm/zsmalloc: don'...
2303
2304
  	/* debug only, don't abort if it fails */
  	zs_pool_stat_create(pool, name);
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2305

48b4800a1   Minchan Kim   zsmalloc: page mi...
2306
2307
  	if (zs_register_migration(pool))
  		goto err;
ab9d306d9   Sergey Senozhatsky   zsmalloc: use shr...
2308
2309
2310
2311
2312
2313
  	/*
  	 * Not critical, we still can use the pool
  	 * and user can trigger compaction manually.
  	 */
  	if (zs_register_shrinker(pool) == 0)
  		pool->shrinker_enabled = true;
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2314
2315
2316
2317
2318
  	return pool;
  
  err:
  	zs_destroy_pool(pool);
  	return NULL;
61989a80f   Nitin Gupta   staging: zsmalloc...
2319
  }
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2320
  EXPORT_SYMBOL_GPL(zs_create_pool);
61989a80f   Nitin Gupta   staging: zsmalloc...
2321

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2322
  void zs_destroy_pool(struct zs_pool *pool)
61989a80f   Nitin Gupta   staging: zsmalloc...
2323
  {
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2324
  	int i;
61989a80f   Nitin Gupta   staging: zsmalloc...
2325

ab9d306d9   Sergey Senozhatsky   zsmalloc: use shr...
2326
  	zs_unregister_shrinker(pool);
48b4800a1   Minchan Kim   zsmalloc: page mi...
2327
  	zs_unregister_migration(pool);
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2328
  	zs_pool_stat_destroy(pool);
cf8e0fedf   Jerome Marchand   mm/zsmalloc: simp...
2329
  	for (i = 0; i < ZS_SIZE_CLASSES; i++) {
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2330
2331
  		int fg;
  		struct size_class *class = pool->size_class[i];
61989a80f   Nitin Gupta   staging: zsmalloc...
2332

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2333
2334
  		if (!class)
  			continue;
61989a80f   Nitin Gupta   staging: zsmalloc...
2335

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2336
2337
  		if (class->index != i)
  			continue;
61989a80f   Nitin Gupta   staging: zsmalloc...
2338

48b4800a1   Minchan Kim   zsmalloc: page mi...
2339
  		for (fg = ZS_EMPTY; fg < NR_ZS_FULLNESS; fg++) {
3783689a1   Minchan Kim   zsmalloc: introdu...
2340
  			if (!list_empty(&class->fullness_list[fg])) {
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2341
2342
2343
2344
2345
2346
2347
  				pr_info("Freeing non-empty class with size %db, fullness group %d
  ",
  					class->size, fg);
  			}
  		}
  		kfree(class);
  	}
f553646a6   Seth Jennings   staging: zsmalloc...
2348

3783689a1   Minchan Kim   zsmalloc: introdu...
2349
  	destroy_cache(pool);
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2350
  	kfree(pool->name);
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2351
2352
2353
  	kfree(pool);
  }
  EXPORT_SYMBOL_GPL(zs_destroy_pool);
b74185108   Seth Jennings   staging: zsmalloc...
2354

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2355
2356
  static int __init zs_init(void)
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
2357
2358
2359
2360
2361
  	int ret;
  
  	ret = zsmalloc_mount();
  	if (ret)
  		goto out;
215c89d05   Sebastian Andrzej Siewior   mm/zsmalloc: Conv...
2362
2363
  	ret = cpuhp_setup_state(CPUHP_MM_ZS_PREPARE, "mm/zsmalloc:prepare",
  				zs_cpu_prepare, zs_cpu_dead);
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2364
  	if (ret)
215c89d05   Sebastian Andrzej Siewior   mm/zsmalloc: Conv...
2365
  		goto hp_setup_fail;
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2366

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2367
2368
2369
  #ifdef CONFIG_ZPOOL
  	zpool_register_driver(&zs_zpool_driver);
  #endif
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2370

4abaac9b7   Dan Streetman   update "mm/zsmall...
2371
  	zs_stat_init();
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2372
  	return 0;
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2373

215c89d05   Sebastian Andrzej Siewior   mm/zsmalloc: Conv...
2374
  hp_setup_fail:
48b4800a1   Minchan Kim   zsmalloc: page mi...
2375
2376
  	zsmalloc_unmount();
  out:
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2377
  	return ret;
61989a80f   Nitin Gupta   staging: zsmalloc...
2378
  }
61989a80f   Nitin Gupta   staging: zsmalloc...
2379

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2380
  static void __exit zs_exit(void)
61989a80f   Nitin Gupta   staging: zsmalloc...
2381
  {
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2382
2383
2384
  #ifdef CONFIG_ZPOOL
  	zpool_unregister_driver(&zs_zpool_driver);
  #endif
48b4800a1   Minchan Kim   zsmalloc: page mi...
2385
  	zsmalloc_unmount();
215c89d05   Sebastian Andrzej Siewior   mm/zsmalloc: Conv...
2386
  	cpuhp_remove_state(CPUHP_MM_ZS_PREPARE);
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2387
2388
  
  	zs_stat_exit();
61989a80f   Nitin Gupta   staging: zsmalloc...
2389
  }
069f101fa   Ben Hutchings   staging: zsmalloc...
2390
2391
2392
2393
2394
2395
  
  module_init(zs_init);
  module_exit(zs_exit);
  
  MODULE_LICENSE("Dual BSD/GPL");
  MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");