Blame view

mm/zsmalloc.c 60.3 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
26
   *
   * Usage of struct page flags:
   *	PG_private: identifies the first component page
   *	PG_private2: identifies the last component page
48b4800a1   Minchan Kim   zsmalloc: page mi...
27
   *	PG_owner_priv_1: indentifies the huge component page
2db51dae5   Nitin Gupta   staging: zsmalloc...
28
29
   *
   */
4abaac9b7   Dan Streetman   update "mm/zsmall...
30
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
61989a80f   Nitin Gupta   staging: zsmalloc...
31
32
  #include <linux/module.h>
  #include <linux/kernel.h>
312fcae22   Minchan Kim   zsmalloc: support...
33
  #include <linux/sched.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
113
114
115
116
117
  #define OBJ_INDEX_MASK	((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
  
  #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...
118
  /* each chunk includes extra space to keep handle */
7b60a6852   Minchan Kim   zsmalloc: record ...
119
  #define ZS_MAX_ALLOC_SIZE	PAGE_SIZE
0959c63f1   Seth Jennings   zsmalloc: collaps...
120
121
  
  /*
7eb52512a   Weijie Yang   zsmalloc: fixup t...
122
   * On systems with 4K page size, this gives 255 size classes! There is a
0959c63f1   Seth Jennings   zsmalloc: collaps...
123
124
125
126
127
128
129
130
131
132
133
   * 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...
134
  #define ZS_SIZE_CLASS_DELTA	(PAGE_SIZE >> CLASS_BITS)
0959c63f1   Seth Jennings   zsmalloc: collaps...
135

0959c63f1   Seth Jennings   zsmalloc: collaps...
136
  enum fullness_group {
0959c63f1   Seth Jennings   zsmalloc: collaps...
137
  	ZS_EMPTY,
48b4800a1   Minchan Kim   zsmalloc: page mi...
138
139
140
141
  	ZS_ALMOST_EMPTY,
  	ZS_ALMOST_FULL,
  	ZS_FULL,
  	NR_ZS_FULLNESS,
0959c63f1   Seth Jennings   zsmalloc: collaps...
142
  };
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
143
  enum zs_stat_type {
48b4800a1   Minchan Kim   zsmalloc: page mi...
144
145
146
147
  	CLASS_EMPTY,
  	CLASS_ALMOST_EMPTY,
  	CLASS_ALMOST_FULL,
  	CLASS_FULL,
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
148
149
  	OBJ_ALLOCATED,
  	OBJ_USED,
48b4800a1   Minchan Kim   zsmalloc: page mi...
150
  	NR_ZS_STAT_TYPE,
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
151
  };
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
152
153
154
  struct zs_size_stat {
  	unsigned long objs[NR_ZS_STAT_TYPE];
  };
572445941   Sergey Senozhatsky   zsmalloc: always ...
155
156
  #ifdef CONFIG_ZSMALLOC_STAT
  static struct dentry *zs_stat_root;
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
157
  #endif
48b4800a1   Minchan Kim   zsmalloc: page mi...
158
159
160
  #ifdef CONFIG_COMPACTION
  static struct vfsmount *zsmalloc_mnt;
  #endif
0959c63f1   Seth Jennings   zsmalloc: collaps...
161
  /*
40f9fb8cf   Mahendran Ganesh   mm/zsmalloc: supp...
162
163
164
165
166
   * number of size_classes
   */
  static int zs_size_classes;
  
  /*
0959c63f1   Seth Jennings   zsmalloc: collaps...
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

40f9fb8cf   Mahendran Ganesh   mm/zsmalloc: supp...
235
  	struct size_class **size_class;
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
259
260
261
262
  
  /*
   * A zspage's class index and fullness group
   * are encoded in its (first)page->mapping
   */
3783689a1   Minchan Kim   zsmalloc: introdu...
263
264
  #define FULLNESS_BITS	2
  #define CLASS_BITS	8
48b4800a1   Minchan Kim   zsmalloc: page mi...
265
266
  #define ISOLATED_BITS	3
  #define MAGIC_VAL_BITS	8
4f42047bb   Minchan Kim   zsmalloc: use acc...
267

3783689a1   Minchan Kim   zsmalloc: introdu...
268
269
270
271
  struct zspage {
  	struct {
  		unsigned int fullness:FULLNESS_BITS;
  		unsigned int class:CLASS_BITS;
48b4800a1   Minchan Kim   zsmalloc: page mi...
272
273
  		unsigned int isolated:ISOLATED_BITS;
  		unsigned int magic:MAGIC_VAL_BITS;
3783689a1   Minchan Kim   zsmalloc: introdu...
274
275
  	};
  	unsigned int inuse;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
276
  	unsigned int freeobj;
3783689a1   Minchan Kim   zsmalloc: introdu...
277
278
  	struct page *first_page;
  	struct list_head list; /* fullness list */
48b4800a1   Minchan Kim   zsmalloc: page mi...
279
280
281
  #ifdef CONFIG_COMPACTION
  	rwlock_t lock;
  #endif
3783689a1   Minchan Kim   zsmalloc: introdu...
282
  };
61989a80f   Nitin Gupta   staging: zsmalloc...
283

f553646a6   Seth Jennings   staging: zsmalloc...
284
  struct mapping_area {
1b945aeef   Minchan Kim   zsmalloc: add Kco...
285
  #ifdef CONFIG_PGTABLE_MAPPING
f553646a6   Seth Jennings   staging: zsmalloc...
286
287
288
289
290
291
292
  	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...
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
  #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...
314
  static int create_cache(struct zs_pool *pool)
2e40e163a   Minchan Kim   zsmalloc: decoupl...
315
316
317
  {
  	pool->handle_cachep = kmem_cache_create("zs_handle", ZS_HANDLE_SIZE,
  					0, 0, NULL);
3783689a1   Minchan Kim   zsmalloc: introdu...
318
319
320
321
322
323
324
325
326
327
328
329
  	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...
330
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
331
  static void destroy_cache(struct zs_pool *pool)
2e40e163a   Minchan Kim   zsmalloc: decoupl...
332
  {
cd10add00   Sergey Senozhatsky   zsmalloc: remove ...
333
  	kmem_cache_destroy(pool->handle_cachep);
3783689a1   Minchan Kim   zsmalloc: introdu...
334
  	kmem_cache_destroy(pool->zspage_cachep);
2e40e163a   Minchan Kim   zsmalloc: decoupl...
335
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
336
  static unsigned long cache_alloc_handle(struct zs_pool *pool, gfp_t gfp)
2e40e163a   Minchan Kim   zsmalloc: decoupl...
337
338
  {
  	return (unsigned long)kmem_cache_alloc(pool->handle_cachep,
48b4800a1   Minchan Kim   zsmalloc: page mi...
339
  			gfp & ~(__GFP_HIGHMEM|__GFP_MOVABLE));
2e40e163a   Minchan Kim   zsmalloc: decoupl...
340
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
341
  static void cache_free_handle(struct zs_pool *pool, unsigned long handle)
2e40e163a   Minchan Kim   zsmalloc: decoupl...
342
343
344
  {
  	kmem_cache_free(pool->handle_cachep, (void *)handle);
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
345
346
  static struct zspage *cache_alloc_zspage(struct zs_pool *pool, gfp_t flags)
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
347
348
  	return kmem_cache_alloc(pool->zspage_cachep,
  			flags & ~(__GFP_HIGHMEM|__GFP_MOVABLE));
3783689a1   Minchan Kim   zsmalloc: introdu...
349
350
351
352
353
354
  };
  
  static void cache_free_zspage(struct zs_pool *pool, struct zspage *zspage)
  {
  	kmem_cache_free(pool->zspage_cachep, zspage);
  }
2e40e163a   Minchan Kim   zsmalloc: decoupl...
355
356
  static void record_obj(unsigned long handle, unsigned long obj)
  {
c102f07ca   Junil Lee   zsmalloc: fix mig...
357
358
359
360
361
362
  	/*
  	 * 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...
363
  }
c795779df   Dan Streetman   mm/zpool: zbud/zs...
364
365
366
  /* zpool driver */
  
  #ifdef CONFIG_ZPOOL
6f3526d6d   Sergey SENOZHATSKY   mm: zsmalloc: con...
367
  static void *zs_zpool_create(const char *name, gfp_t gfp,
786727799   Krzysztof Kozlowski   mm: zpool: consti...
368
  			     const struct zpool_ops *zpool_ops,
479305fd7   Dan Streetman   zpool: remove zpo...
369
  			     struct zpool *zpool)
c795779df   Dan Streetman   mm/zpool: zbud/zs...
370
  {
d0d8da2dc   Sergey Senozhatsky   zsmalloc: require...
371
372
373
374
375
376
  	/*
  	 * 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...
377
378
379
380
381
382
383
384
385
386
  }
  
  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...
387
  	*handle = zs_malloc(pool, size, gfp);
c795779df   Dan Streetman   mm/zpool: zbud/zs...
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
419
420
421
422
423
424
425
426
427
  	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 ...
428
  	return zs_get_total_pages(pool) << PAGE_SHIFT;
c795779df   Dan Streetman   mm/zpool: zbud/zs...
429
430
431
432
433
434
435
436
437
438
439
440
441
442
  }
  
  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...
443
  MODULE_ALIAS("zpool-zsmalloc");
c795779df   Dan Streetman   mm/zpool: zbud/zs...
444
  #endif /* CONFIG_ZPOOL */
61989a80f   Nitin Gupta   staging: zsmalloc...
445
446
  /* 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...
447
448
449
450
  static bool is_zspage_isolated(struct zspage *zspage)
  {
  	return zspage->isolated;
  }
61989a80f   Nitin Gupta   staging: zsmalloc...
451
452
  static int is_first_page(struct page *page)
  {
a27545bf0   Minchan Kim   zsmalloc: use Pag...
453
  	return PagePrivate(page);
61989a80f   Nitin Gupta   staging: zsmalloc...
454
  }
48b4800a1   Minchan Kim   zsmalloc: page mi...
455
  /* Protected by class->lock */
3783689a1   Minchan Kim   zsmalloc: introdu...
456
  static inline int get_zspage_inuse(struct zspage *zspage)
4f42047bb   Minchan Kim   zsmalloc: use acc...
457
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
458
  	return zspage->inuse;
4f42047bb   Minchan Kim   zsmalloc: use acc...
459
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
460
  static inline void set_zspage_inuse(struct zspage *zspage, int val)
4f42047bb   Minchan Kim   zsmalloc: use acc...
461
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
462
  	zspage->inuse = val;
4f42047bb   Minchan Kim   zsmalloc: use acc...
463
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
464
  static inline void mod_zspage_inuse(struct zspage *zspage, int val)
4f42047bb   Minchan Kim   zsmalloc: use acc...
465
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
466
  	zspage->inuse += val;
4f42047bb   Minchan Kim   zsmalloc: use acc...
467
  }
48b4800a1   Minchan Kim   zsmalloc: page mi...
468
  static inline struct page *get_first_page(struct zspage *zspage)
4f42047bb   Minchan Kim   zsmalloc: use acc...
469
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
470
  	struct page *first_page = zspage->first_page;
3783689a1   Minchan Kim   zsmalloc: introdu...
471

48b4800a1   Minchan Kim   zsmalloc: page mi...
472
473
  	VM_BUG_ON_PAGE(!is_first_page(first_page), first_page);
  	return first_page;
4f42047bb   Minchan Kim   zsmalloc: use acc...
474
  }
48b4800a1   Minchan Kim   zsmalloc: page mi...
475
  static inline int get_first_obj_offset(struct page *page)
4f42047bb   Minchan Kim   zsmalloc: use acc...
476
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
477
478
  	return page->units;
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
479

48b4800a1   Minchan Kim   zsmalloc: page mi...
480
481
482
  static inline void set_first_obj_offset(struct page *page, int offset)
  {
  	page->units = offset;
4f42047bb   Minchan Kim   zsmalloc: use acc...
483
  }
bfd093f5e   Minchan Kim   zsmalloc: use fre...
484
  static inline unsigned int get_freeobj(struct zspage *zspage)
4f42047bb   Minchan Kim   zsmalloc: use acc...
485
  {
bfd093f5e   Minchan Kim   zsmalloc: use fre...
486
  	return zspage->freeobj;
4f42047bb   Minchan Kim   zsmalloc: use acc...
487
  }
bfd093f5e   Minchan Kim   zsmalloc: use fre...
488
  static inline void set_freeobj(struct zspage *zspage, unsigned int obj)
4f42047bb   Minchan Kim   zsmalloc: use acc...
489
  {
bfd093f5e   Minchan Kim   zsmalloc: use fre...
490
  	zspage->freeobj = obj;
4f42047bb   Minchan Kim   zsmalloc: use acc...
491
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
492
  static void get_zspage_mapping(struct zspage *zspage,
a42094676   Minchan Kim   zsmalloc: use fir...
493
  				unsigned int *class_idx,
61989a80f   Nitin Gupta   staging: zsmalloc...
494
495
  				enum fullness_group *fullness)
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
496
  	BUG_ON(zspage->magic != ZSPAGE_MAGIC);
3783689a1   Minchan Kim   zsmalloc: introdu...
497
498
  	*fullness = zspage->fullness;
  	*class_idx = zspage->class;
61989a80f   Nitin Gupta   staging: zsmalloc...
499
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
500
  static void set_zspage_mapping(struct zspage *zspage,
a42094676   Minchan Kim   zsmalloc: use fir...
501
  				unsigned int class_idx,
61989a80f   Nitin Gupta   staging: zsmalloc...
502
503
  				enum fullness_group fullness)
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
504
505
  	zspage->class = class_idx;
  	zspage->fullness = fullness;
61989a80f   Nitin Gupta   staging: zsmalloc...
506
  }
c3e3e88ad   Nitin Cupta   zsmalloc: add mor...
507
508
509
510
511
512
513
  /*
   * 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...
514
515
516
517
518
519
520
  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);
7b60a6852   Minchan Kim   zsmalloc: record ...
521
  	return min(zs_size_classes - 1, idx);
61989a80f   Nitin Gupta   staging: zsmalloc...
522
  }
248ca1b05   Minchan Kim   zsmalloc: add ful...
523
524
525
  static inline void zs_stat_inc(struct size_class *class,
  				enum zs_stat_type type, unsigned long cnt)
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
526
  	class->stats.objs[type] += cnt;
248ca1b05   Minchan Kim   zsmalloc: add ful...
527
528
529
530
531
  }
  
  static inline void zs_stat_dec(struct size_class *class,
  				enum zs_stat_type type, unsigned long cnt)
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
532
  	class->stats.objs[type] -= cnt;
248ca1b05   Minchan Kim   zsmalloc: add ful...
533
534
535
536
537
  }
  
  static inline unsigned long zs_stat_get(struct size_class *class,
  				enum zs_stat_type type)
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
538
  	return class->stats.objs[type];
248ca1b05   Minchan Kim   zsmalloc: add ful...
539
  }
572445941   Sergey Senozhatsky   zsmalloc: always ...
540
  #ifdef CONFIG_ZSMALLOC_STAT
4abaac9b7   Dan Streetman   update "mm/zsmall...
541
  static void __init zs_stat_init(void)
248ca1b05   Minchan Kim   zsmalloc: add ful...
542
  {
4abaac9b7   Dan Streetman   update "mm/zsmall...
543
544
545
546
547
  	if (!debugfs_initialized()) {
  		pr_warn("debugfs not available, stat dir not created
  ");
  		return;
  	}
248ca1b05   Minchan Kim   zsmalloc: add ful...
548
549
550
  
  	zs_stat_root = debugfs_create_dir("zsmalloc", NULL);
  	if (!zs_stat_root)
4abaac9b7   Dan Streetman   update "mm/zsmall...
551
552
  		pr_warn("debugfs 'zsmalloc' stat dir creation failed
  ");
248ca1b05   Minchan Kim   zsmalloc: add ful...
553
554
555
556
557
558
  }
  
  static void __exit zs_stat_exit(void)
  {
  	debugfs_remove_recursive(zs_stat_root);
  }
1120ed548   Sergey Senozhatsky   mm/zsmalloc: add ...
559
  static unsigned long zs_can_compact(struct size_class *class);
248ca1b05   Minchan Kim   zsmalloc: add ful...
560
561
562
563
564
565
566
  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 ...
567
  	unsigned long obj_allocated, obj_used, pages_used, freeable;
248ca1b05   Minchan Kim   zsmalloc: add ful...
568
569
  	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 ...
570
  	unsigned long total_freeable = 0;
248ca1b05   Minchan Kim   zsmalloc: add ful...
571

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

c3e3e88ad   Nitin Cupta   zsmalloc: add mor...
681
682
683
684
685
686
687
  /*
   * 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...
688
  static enum fullness_group get_fullness_group(struct size_class *class,
3783689a1   Minchan Kim   zsmalloc: introdu...
689
  						struct zspage *zspage)
61989a80f   Nitin Gupta   staging: zsmalloc...
690
  {
1fc6e27d7   Minchan Kim   zsmalloc: keep ma...
691
  	int inuse, objs_per_zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
692
  	enum fullness_group fg;
830e4bc5b   Minchan Kim   zsmalloc: clean u...
693

3783689a1   Minchan Kim   zsmalloc: introdu...
694
  	inuse = get_zspage_inuse(zspage);
1fc6e27d7   Minchan Kim   zsmalloc: keep ma...
695
  	objs_per_zspage = class->objs_per_zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
696
697
698
  
  	if (inuse == 0)
  		fg = ZS_EMPTY;
1fc6e27d7   Minchan Kim   zsmalloc: keep ma...
699
  	else if (inuse == objs_per_zspage)
61989a80f   Nitin Gupta   staging: zsmalloc...
700
  		fg = ZS_FULL;
1fc6e27d7   Minchan Kim   zsmalloc: keep ma...
701
  	else if (inuse <= 3 * objs_per_zspage / fullness_threshold_frac)
61989a80f   Nitin Gupta   staging: zsmalloc...
702
703
704
705
706
707
  		fg = ZS_ALMOST_EMPTY;
  	else
  		fg = ZS_ALMOST_FULL;
  
  	return fg;
  }
c3e3e88ad   Nitin Cupta   zsmalloc: add mor...
708
709
710
711
712
713
  /*
   * 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...
714
  static void insert_zspage(struct size_class *class,
3783689a1   Minchan Kim   zsmalloc: introdu...
715
716
  				struct zspage *zspage,
  				enum fullness_group fullness)
61989a80f   Nitin Gupta   staging: zsmalloc...
717
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
718
  	struct zspage *head;
61989a80f   Nitin Gupta   staging: zsmalloc...
719

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

3783689a1   Minchan Kim   zsmalloc: introdu...
746
  	list_del_init(&zspage->list);
48b4800a1   Minchan Kim   zsmalloc: page mi...
747
  	zs_stat_dec(class, fullness, 1);
61989a80f   Nitin Gupta   staging: zsmalloc...
748
  }
c3e3e88ad   Nitin Cupta   zsmalloc: add mor...
749
750
751
752
753
754
755
756
757
  /*
   * 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 ...
758
  static enum fullness_group fix_fullness_group(struct size_class *class,
3783689a1   Minchan Kim   zsmalloc: introdu...
759
  						struct zspage *zspage)
61989a80f   Nitin Gupta   staging: zsmalloc...
760
761
  {
  	int class_idx;
61989a80f   Nitin Gupta   staging: zsmalloc...
762
  	enum fullness_group currfg, newfg;
3783689a1   Minchan Kim   zsmalloc: introdu...
763
764
  	get_zspage_mapping(zspage, &class_idx, &currfg);
  	newfg = get_fullness_group(class, zspage);
61989a80f   Nitin Gupta   staging: zsmalloc...
765
766
  	if (newfg == currfg)
  		goto out;
48b4800a1   Minchan Kim   zsmalloc: page mi...
767
768
769
770
  	if (!is_zspage_isolated(zspage)) {
  		remove_zspage(class, zspage, currfg);
  		insert_zspage(class, zspage, newfg);
  	}
3783689a1   Minchan Kim   zsmalloc: introdu...
771
  	set_zspage_mapping(zspage, class_idx, newfg);
61989a80f   Nitin Gupta   staging: zsmalloc...
772
773
774
775
776
777
778
779
780
781
  
  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...
782
783
   *     wastage = Zp % class_size
   *     usage = Zp - wastage
61989a80f   Nitin Gupta   staging: zsmalloc...
784
785
786
787
788
789
   * 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...
790
  static int get_pages_per_zspage(int class_size)
61989a80f   Nitin Gupta   staging: zsmalloc...
791
792
793
794
  {
  	int i, max_usedpc = 0;
  	/* zspage order which gives maximum used size per KB */
  	int max_usedpc_order = 1;
84d4faaba   Seth Jennings   staging: zsmalloc...
795
  	for (i = 1; i <= ZS_MAX_PAGES_PER_ZSPAGE; i++) {
61989a80f   Nitin Gupta   staging: zsmalloc...
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
  		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...
811
  static struct zspage *get_zspage(struct page *page)
61989a80f   Nitin Gupta   staging: zsmalloc...
812
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
813
814
815
816
  	struct zspage *zspage = (struct zspage *)page->private;
  
  	BUG_ON(zspage->magic != ZSPAGE_MAGIC);
  	return zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
817
818
819
820
  }
  
  static struct page *get_next_page(struct page *page)
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
821
822
823
824
  	if (unlikely(PageHugeObject(page)))
  		return NULL;
  
  	return page->freelist;
61989a80f   Nitin Gupta   staging: zsmalloc...
825
  }
bfd093f5e   Minchan Kim   zsmalloc: use fre...
826
827
828
829
  /**
   * 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...
830
   */
bfd093f5e   Minchan Kim   zsmalloc: use fre...
831
832
  static void obj_to_location(unsigned long obj, struct page **page,
  				unsigned int *obj_idx)
61989a80f   Nitin Gupta   staging: zsmalloc...
833
  {
bfd093f5e   Minchan Kim   zsmalloc: use fre...
834
835
836
837
  	obj >>= OBJ_TAG_BITS;
  	*page = pfn_to_page(obj >> OBJ_INDEX_BITS);
  	*obj_idx = (obj & OBJ_INDEX_MASK);
  }
61989a80f   Nitin Gupta   staging: zsmalloc...
838

bfd093f5e   Minchan Kim   zsmalloc: use fre...
839
840
841
842
843
844
845
846
  /**
   * 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...
847

312fcae22   Minchan Kim   zsmalloc: support...
848
  	obj = page_to_pfn(page) << OBJ_INDEX_BITS;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
849
  	obj |= obj_idx & OBJ_INDEX_MASK;
312fcae22   Minchan Kim   zsmalloc: support...
850
  	obj <<= OBJ_TAG_BITS;
61989a80f   Nitin Gupta   staging: zsmalloc...
851

bfd093f5e   Minchan Kim   zsmalloc: use fre...
852
  	return obj;
61989a80f   Nitin Gupta   staging: zsmalloc...
853
  }
2e40e163a   Minchan Kim   zsmalloc: decoupl...
854
855
856
857
  static unsigned long handle_to_obj(unsigned long handle)
  {
  	return *(unsigned long *)handle;
  }
48b4800a1   Minchan Kim   zsmalloc: page mi...
858
  static unsigned long obj_to_head(struct page *page, void *obj)
312fcae22   Minchan Kim   zsmalloc: support...
859
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
860
  	if (unlikely(PageHugeObject(page))) {
830e4bc5b   Minchan Kim   zsmalloc: clean u...
861
  		VM_BUG_ON_PAGE(!is_first_page(page), page);
3783689a1   Minchan Kim   zsmalloc: introdu...
862
  		return page->index;
7b60a6852   Minchan Kim   zsmalloc: record ...
863
864
  	} else
  		return *(unsigned long *)obj;
312fcae22   Minchan Kim   zsmalloc: support...
865
  }
48b4800a1   Minchan Kim   zsmalloc: page mi...
866
867
868
869
  static inline int testpin_tag(unsigned long handle)
  {
  	return bit_spin_is_locked(HANDLE_PIN_BIT, (unsigned long *)handle);
  }
312fcae22   Minchan Kim   zsmalloc: support...
870
871
  static inline int trypin_tag(unsigned long handle)
  {
1b8320b62   Minchan Kim   zsmalloc: use bit...
872
  	return bit_spin_trylock(HANDLE_PIN_BIT, (unsigned long *)handle);
312fcae22   Minchan Kim   zsmalloc: support...
873
874
875
876
  }
  
  static void pin_tag(unsigned long handle)
  {
1b8320b62   Minchan Kim   zsmalloc: use bit...
877
  	bit_spin_lock(HANDLE_PIN_BIT, (unsigned long *)handle);
312fcae22   Minchan Kim   zsmalloc: support...
878
879
880
881
  }
  
  static void unpin_tag(unsigned long handle)
  {
1b8320b62   Minchan Kim   zsmalloc: use bit...
882
  	bit_spin_unlock(HANDLE_PIN_BIT, (unsigned long *)handle);
312fcae22   Minchan Kim   zsmalloc: support...
883
  }
f4477e90b   Nitin Gupta   staging: zsmalloc...
884
885
  static void reset_page(struct page *page)
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
886
  	__ClearPageMovable(page);
18fd06bf7   Ganesh Mahendran   mm/zsmalloc: use ...
887
888
  	ClearPagePrivate(page);
  	ClearPagePrivate2(page);
f4477e90b   Nitin Gupta   staging: zsmalloc...
889
  	set_page_private(page, 0);
48b4800a1   Minchan Kim   zsmalloc: page mi...
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
918
919
920
921
922
923
924
925
926
  	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...
927
  }
48b4800a1   Minchan Kim   zsmalloc: page mi...
928
929
  static void __free_zspage(struct zs_pool *pool, struct size_class *class,
  				struct zspage *zspage)
61989a80f   Nitin Gupta   staging: zsmalloc...
930
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
931
  	struct page *page, *next;
48b4800a1   Minchan Kim   zsmalloc: page mi...
932
933
934
935
936
937
  	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...
938

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

48b4800a1   Minchan Kim   zsmalloc: page mi...
942
  	next = page = get_first_page(zspage);
3783689a1   Minchan Kim   zsmalloc: introdu...
943
  	do {
48b4800a1   Minchan Kim   zsmalloc: page mi...
944
945
  		VM_BUG_ON_PAGE(!PageLocked(page), page);
  		next = get_next_page(page);
3783689a1   Minchan Kim   zsmalloc: introdu...
946
  		reset_page(page);
48b4800a1   Minchan Kim   zsmalloc: page mi...
947
  		unlock_page(page);
91537fee0   Minchan Kim   mm: add NR_ZSMALL...
948
  		dec_zone_page_state(page, NR_ZSPAGES);
3783689a1   Minchan Kim   zsmalloc: introdu...
949
950
951
  		put_page(page);
  		page = next;
  	} while (page != NULL);
61989a80f   Nitin Gupta   staging: zsmalloc...
952

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

b4fd07a08   Ganesh Mahendran   mm/zsmalloc: use ...
955
  	zs_stat_dec(class, OBJ_ALLOCATED, class->objs_per_zspage);
48b4800a1   Minchan Kim   zsmalloc: page mi...
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
  	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...
973
974
975
  }
  
  /* Initialize a newly allocated zspage */
3783689a1   Minchan Kim   zsmalloc: introdu...
976
  static void init_zspage(struct size_class *class, struct zspage *zspage)
61989a80f   Nitin Gupta   staging: zsmalloc...
977
  {
bfd093f5e   Minchan Kim   zsmalloc: use fre...
978
  	unsigned int freeobj = 1;
61989a80f   Nitin Gupta   staging: zsmalloc...
979
  	unsigned long off = 0;
48b4800a1   Minchan Kim   zsmalloc: page mi...
980
  	struct page *page = get_first_page(zspage);
830e4bc5b   Minchan Kim   zsmalloc: clean u...
981

61989a80f   Nitin Gupta   staging: zsmalloc...
982
983
984
  	while (page) {
  		struct page *next_page;
  		struct link_free *link;
af4ee5e97   Minchan Kim   zsmalloc: correct...
985
  		void *vaddr;
61989a80f   Nitin Gupta   staging: zsmalloc...
986

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

af4ee5e97   Minchan Kim   zsmalloc: correct...
989
990
  		vaddr = kmap_atomic(page);
  		link = (struct link_free *)vaddr + off / sizeof(*link);
5538c5623   Dan Streetman   zsmalloc: simplif...
991
992
  
  		while ((off += class->size) < PAGE_SIZE) {
3b1d9ca65   Minchan Kim   zsmalloc: use OBJ...
993
  			link->next = freeobj++ << OBJ_TAG_BITS;
5538c5623   Dan Streetman   zsmalloc: simplif...
994
  			link += class->size / sizeof(*link);
61989a80f   Nitin Gupta   staging: zsmalloc...
995
996
997
998
999
1000
1001
1002
  		}
  
  		/*
  		 * 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...
1003
  		if (next_page) {
3b1d9ca65   Minchan Kim   zsmalloc: use OBJ...
1004
  			link->next = freeobj++ << OBJ_TAG_BITS;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1005
1006
  		} else {
  			/*
3b1d9ca65   Minchan Kim   zsmalloc: use OBJ...
1007
  			 * Reset OBJ_TAG_BITS bit to last link to tell
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1008
1009
  			 * whether it's allocated object or not.
  			 */
3b1d9ca65   Minchan Kim   zsmalloc: use OBJ...
1010
  			link->next = -1 << OBJ_TAG_BITS;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1011
  		}
af4ee5e97   Minchan Kim   zsmalloc: correct...
1012
  		kunmap_atomic(vaddr);
61989a80f   Nitin Gupta   staging: zsmalloc...
1013
  		page = next_page;
5538c5623   Dan Streetman   zsmalloc: simplif...
1014
  		off %= PAGE_SIZE;
61989a80f   Nitin Gupta   staging: zsmalloc...
1015
  	}
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1016

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

bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1054
1055
1056
  /*
   * Allocate a zspage for the given size class
   */
3783689a1   Minchan Kim   zsmalloc: introdu...
1057
1058
1059
  static struct zspage *alloc_zspage(struct zs_pool *pool,
  					struct size_class *class,
  					gfp_t gfp)
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1060
1061
  {
  	int i;
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1062
  	struct page *pages[ZS_MAX_PAGES_PER_ZSPAGE];
3783689a1   Minchan Kim   zsmalloc: introdu...
1063
1064
1065
1066
1067
1068
  	struct zspage *zspage = cache_alloc_zspage(pool, gfp);
  
  	if (!zspage)
  		return NULL;
  
  	memset(zspage, 0, sizeof(struct zspage));
48b4800a1   Minchan Kim   zsmalloc: page mi...
1069
1070
  	zspage->magic = ZSPAGE_MAGIC;
  	migrate_lock_init(zspage);
61989a80f   Nitin Gupta   staging: zsmalloc...
1071

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

3783689a1   Minchan Kim   zsmalloc: introdu...
1075
  		page = alloc_page(gfp);
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1076
  		if (!page) {
91537fee0   Minchan Kim   mm: add NR_ZSMALL...
1077
1078
  			while (--i >= 0) {
  				dec_zone_page_state(pages[i], NR_ZSPAGES);
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1079
  				__free_page(pages[i]);
91537fee0   Minchan Kim   mm: add NR_ZSMALL...
1080
  			}
3783689a1   Minchan Kim   zsmalloc: introdu...
1081
  			cache_free_zspage(pool, zspage);
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1082
1083
  			return NULL;
  		}
91537fee0   Minchan Kim   mm: add NR_ZSMALL...
1084
1085
  
  		inc_zone_page_state(page, NR_ZSPAGES);
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1086
  		pages[i] = page;
61989a80f   Nitin Gupta   staging: zsmalloc...
1087
  	}
48b4800a1   Minchan Kim   zsmalloc: page mi...
1088
  	create_page_chain(class, zspage, pages);
3783689a1   Minchan Kim   zsmalloc: introdu...
1089
  	init_zspage(class, zspage);
bdb0af7ca   Minchan Kim   zsmalloc: factor ...
1090

3783689a1   Minchan Kim   zsmalloc: introdu...
1091
  	return zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
1092
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
1093
  static struct zspage *find_get_zspage(struct size_class *class)
61989a80f   Nitin Gupta   staging: zsmalloc...
1094
1095
  {
  	int i;
3783689a1   Minchan Kim   zsmalloc: introdu...
1096
  	struct zspage *zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
1097

48b4800a1   Minchan Kim   zsmalloc: page mi...
1098
  	for (i = ZS_ALMOST_FULL; i >= ZS_EMPTY; i--) {
3783689a1   Minchan Kim   zsmalloc: introdu...
1099
1100
1101
  		zspage = list_first_entry_or_null(&class->fullness_list[i],
  				struct zspage, list);
  		if (zspage)
61989a80f   Nitin Gupta   staging: zsmalloc...
1102
1103
  			break;
  	}
3783689a1   Minchan Kim   zsmalloc: introdu...
1104
  	return zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
1105
  }
1b945aeef   Minchan Kim   zsmalloc: add Kco...
1106
  #ifdef CONFIG_PGTABLE_MAPPING
f553646a6   Seth Jennings   staging: zsmalloc...
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
  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...
1131
  	BUG_ON(map_vm_area(area->vm, PAGE_KERNEL, pages));
f553646a6   Seth Jennings   staging: zsmalloc...
1132
1133
1134
1135
1136
1137
1138
1139
  	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...
1140

d95abbbb2   Joerg Roedel   staging: zsmalloc...
1141
  	unmap_kernel_range(addr, PAGE_SIZE * 2);
f553646a6   Seth Jennings   staging: zsmalloc...
1142
  }
1b945aeef   Minchan Kim   zsmalloc: add Kco...
1143
  #else /* CONFIG_PGTABLE_MAPPING */
f553646a6   Seth Jennings   staging: zsmalloc...
1144
1145
1146
1147
1148
1149
1150
1151
1152
  
  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...
1153
  	area->vm_buf = kmalloc(ZS_MAX_ALLOC_SIZE, GFP_KERNEL);
f553646a6   Seth Jennings   staging: zsmalloc...
1154
1155
1156
1157
1158
1159
1160
  	if (!area->vm_buf)
  		return -ENOMEM;
  	return 0;
  }
  
  static inline void __zs_cpu_down(struct mapping_area *area)
  {
40f9fb8cf   Mahendran Ganesh   mm/zsmalloc: supp...
1161
  	kfree(area->vm_buf);
f553646a6   Seth Jennings   staging: zsmalloc...
1162
1163
1164
1165
1166
  	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...
1167
  {
5f601902c   Seth Jennings   staging: zsmalloc...
1168
1169
  	int sizes[2];
  	void *addr;
f553646a6   Seth Jennings   staging: zsmalloc...
1170
  	char *buf = area->vm_buf;
5f601902c   Seth Jennings   staging: zsmalloc...
1171

f553646a6   Seth Jennings   staging: zsmalloc...
1172
1173
1174
1175
1176
1177
  	/* 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...
1178
1179
1180
  
  	sizes[0] = PAGE_SIZE - off;
  	sizes[1] = size - sizes[0];
5f601902c   Seth Jennings   staging: zsmalloc...
1181
1182
1183
1184
1185
1186
1187
  	/* 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...
1188
1189
  out:
  	return area->vm_buf;
5f601902c   Seth Jennings   staging: zsmalloc...
1190
  }
f553646a6   Seth Jennings   staging: zsmalloc...
1191
1192
  static void __zs_unmap_object(struct mapping_area *area,
  			struct page *pages[2], int off, int size)
5f601902c   Seth Jennings   staging: zsmalloc...
1193
  {
5f601902c   Seth Jennings   staging: zsmalloc...
1194
1195
  	int sizes[2];
  	void *addr;
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1196
  	char *buf;
5f601902c   Seth Jennings   staging: zsmalloc...
1197

f553646a6   Seth Jennings   staging: zsmalloc...
1198
1199
1200
  	/* no write fastpath */
  	if (area->vm_mm == ZS_MM_RO)
  		goto out;
5f601902c   Seth Jennings   staging: zsmalloc...
1201

7b60a6852   Minchan Kim   zsmalloc: record ...
1202
  	buf = area->vm_buf;
a82cbf071   YiPing Xu   zsmalloc: drop un...
1203
1204
1205
  	buf = buf + ZS_HANDLE_SIZE;
  	size -= ZS_HANDLE_SIZE;
  	off += ZS_HANDLE_SIZE;
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1206

5f601902c   Seth Jennings   staging: zsmalloc...
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
  	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...
1217
1218
1219
1220
  
  out:
  	/* enable page faults to match kunmap_atomic() return conditions */
  	pagefault_enable();
5f601902c   Seth Jennings   staging: zsmalloc...
1221
  }
61989a80f   Nitin Gupta   staging: zsmalloc...
1222

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

61989a80f   Nitin Gupta   staging: zsmalloc...
1225
1226
1227
  static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action,
  				void *pcpu)
  {
f553646a6   Seth Jennings   staging: zsmalloc...
1228
  	int ret, cpu = (long)pcpu;
61989a80f   Nitin Gupta   staging: zsmalloc...
1229
1230
1231
1232
1233
  	struct mapping_area *area;
  
  	switch (action) {
  	case CPU_UP_PREPARE:
  		area = &per_cpu(zs_map_area, cpu);
f553646a6   Seth Jennings   staging: zsmalloc...
1234
1235
1236
  		ret = __zs_cpu_up(area);
  		if (ret)
  			return notifier_from_errno(ret);
61989a80f   Nitin Gupta   staging: zsmalloc...
1237
1238
1239
1240
  		break;
  	case CPU_DEAD:
  	case CPU_UP_CANCELED:
  		area = &per_cpu(zs_map_area, cpu);
f553646a6   Seth Jennings   staging: zsmalloc...
1241
  		__zs_cpu_down(area);
61989a80f   Nitin Gupta   staging: zsmalloc...
1242
1243
1244
1245
1246
1247
1248
1249
1250
  		break;
  	}
  
  	return NOTIFY_OK;
  }
  
  static struct notifier_block zs_cpu_nb = {
  	.notifier_call = zs_cpu_notifier
  };
b1b00a5b8   Sergey Senozhatsky   zsmalloc: fix zs_...
1251
  static int zs_register_cpu_notifier(void)
61989a80f   Nitin Gupta   staging: zsmalloc...
1252
  {
b1b00a5b8   Sergey Senozhatsky   zsmalloc: fix zs_...
1253
  	int cpu, uninitialized_var(ret);
61989a80f   Nitin Gupta   staging: zsmalloc...
1254

f0e71fcd0   Srivatsa S. Bhat   zsmalloc: Fix CPU...
1255
1256
1257
  	cpu_notifier_register_begin();
  
  	__register_cpu_notifier(&zs_cpu_nb);
61989a80f   Nitin Gupta   staging: zsmalloc...
1258
1259
  	for_each_online_cpu(cpu) {
  		ret = zs_cpu_notifier(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
b1b00a5b8   Sergey Senozhatsky   zsmalloc: fix zs_...
1260
1261
  		if (notifier_to_errno(ret))
  			break;
61989a80f   Nitin Gupta   staging: zsmalloc...
1262
  	}
f0e71fcd0   Srivatsa S. Bhat   zsmalloc: Fix CPU...
1263
1264
  
  	cpu_notifier_register_done();
b1b00a5b8   Sergey Senozhatsky   zsmalloc: fix zs_...
1265
1266
  	return notifier_to_errno(ret);
  }
f0e71fcd0   Srivatsa S. Bhat   zsmalloc: Fix CPU...
1267

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1268
  static void zs_unregister_cpu_notifier(void)
40f9fb8cf   Mahendran Ganesh   mm/zsmalloc: supp...
1269
  {
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1270
  	int cpu;
40f9fb8cf   Mahendran Ganesh   mm/zsmalloc: supp...
1271

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1272
  	cpu_notifier_register_begin();
40f9fb8cf   Mahendran Ganesh   mm/zsmalloc: supp...
1273

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1274
1275
1276
  	for_each_online_cpu(cpu)
  		zs_cpu_notifier(NULL, CPU_DEAD, (void *)(long)cpu);
  	__unregister_cpu_notifier(&zs_cpu_nb);
40f9fb8cf   Mahendran Ganesh   mm/zsmalloc: supp...
1277

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1278
  	cpu_notifier_register_done();
b1b00a5b8   Sergey Senozhatsky   zsmalloc: fix zs_...
1279
  }
35b3445e9   Ganesh Mahendran   mm/zsmalloc: add ...
1280
  static void __init init_zs_size_classes(void)
b1b00a5b8   Sergey Senozhatsky   zsmalloc: fix zs_...
1281
  {
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1282
  	int nr;
c795779df   Dan Streetman   mm/zpool: zbud/zs...
1283

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1284
1285
1286
  	nr = (ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / ZS_SIZE_CLASS_DELTA + 1;
  	if ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) % ZS_SIZE_CLASS_DELTA)
  		nr += 1;
40f9fb8cf   Mahendran Ganesh   mm/zsmalloc: supp...
1287

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1288
  	zs_size_classes = nr;
61989a80f   Nitin Gupta   staging: zsmalloc...
1289
  }
64d90465f   Ganesh Mahendran   mm/zsmalloc: avoi...
1290
1291
  static bool can_merge(struct size_class *prev, int pages_per_zspage,
  					int objs_per_zspage)
9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1292
  {
64d90465f   Ganesh Mahendran   mm/zsmalloc: avoi...
1293
1294
1295
  	if (prev->pages_per_zspage == pages_per_zspage &&
  		prev->objs_per_zspage == objs_per_zspage)
  		return true;
9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1296

64d90465f   Ganesh Mahendran   mm/zsmalloc: avoi...
1297
  	return false;
9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1298
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
1299
  static bool zspage_full(struct size_class *class, struct zspage *zspage)
312fcae22   Minchan Kim   zsmalloc: support...
1300
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
1301
  	return get_zspage_inuse(zspage) == class->objs_per_zspage;
312fcae22   Minchan Kim   zsmalloc: support...
1302
  }
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1303
1304
1305
1306
1307
  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...
1308
  /**
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1309
1310
1311
   * 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...
1312
   *
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1313
1314
1315
   * 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...
1316
   *
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1317
1318
1319
1320
   * 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...
1321
   */
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1322
1323
  void *zs_map_object(struct zs_pool *pool, unsigned long handle,
  			enum zs_mapmode mm)
61989a80f   Nitin Gupta   staging: zsmalloc...
1324
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
1325
  	struct zspage *zspage;
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1326
  	struct page *page;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1327
1328
  	unsigned long obj, off;
  	unsigned int obj_idx;
61989a80f   Nitin Gupta   staging: zsmalloc...
1329

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1330
1331
1332
1333
1334
  	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...
1335
  	void *ret;
61989a80f   Nitin Gupta   staging: zsmalloc...
1336

9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1337
  	/*
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1338
1339
1340
  	 * 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...
1341
  	 */
830e4bc5b   Minchan Kim   zsmalloc: clean u...
1342
  	WARN_ON_ONCE(in_interrupt());
61989a80f   Nitin Gupta   staging: zsmalloc...
1343

312fcae22   Minchan Kim   zsmalloc: support...
1344
1345
  	/* From now on, migration cannot move the object */
  	pin_tag(handle);
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1346
1347
  	obj = handle_to_obj(handle);
  	obj_to_location(obj, &page, &obj_idx);
3783689a1   Minchan Kim   zsmalloc: introdu...
1348
  	zspage = get_zspage(page);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1349
1350
1351
  
  	/* migration cannot move any subpage in this zspage */
  	migrate_read_lock(zspage);
3783689a1   Minchan Kim   zsmalloc: introdu...
1352
  	get_zspage_mapping(zspage, &class_idx, &fg);
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1353
  	class = pool->size_class[class_idx];
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1354
  	off = (class->size * obj_idx) & ~PAGE_MASK;
df8b5bb99   Ganesh Mahendran   mm/zsmalloc: avoi...
1355

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1356
1357
1358
1359
1360
  	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...
1361
1362
  		ret = area->vm_addr + off;
  		goto out;
61989a80f   Nitin Gupta   staging: zsmalloc...
1363
  	}
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1364
1365
1366
1367
  	/* this object spans two pages */
  	pages[0] = page;
  	pages[1] = get_next_page(page);
  	BUG_ON(!pages[1]);
9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1368

2e40e163a   Minchan Kim   zsmalloc: decoupl...
1369
1370
  	ret = __zs_map_object(area, pages, off, class->size);
  out:
48b4800a1   Minchan Kim   zsmalloc: page mi...
1371
  	if (likely(!PageHugeObject(page)))
7b60a6852   Minchan Kim   zsmalloc: record ...
1372
1373
1374
  		ret += ZS_HANDLE_SIZE;
  
  	return ret;
61989a80f   Nitin Gupta   staging: zsmalloc...
1375
  }
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1376
  EXPORT_SYMBOL_GPL(zs_map_object);
61989a80f   Nitin Gupta   staging: zsmalloc...
1377

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1378
  void zs_unmap_object(struct zs_pool *pool, unsigned long handle)
61989a80f   Nitin Gupta   staging: zsmalloc...
1379
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
1380
  	struct zspage *zspage;
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1381
  	struct page *page;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1382
1383
  	unsigned long obj, off;
  	unsigned int obj_idx;
61989a80f   Nitin Gupta   staging: zsmalloc...
1384

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1385
1386
1387
1388
  	unsigned int class_idx;
  	enum fullness_group fg;
  	struct size_class *class;
  	struct mapping_area *area;
9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1389

2e40e163a   Minchan Kim   zsmalloc: decoupl...
1390
1391
  	obj = handle_to_obj(handle);
  	obj_to_location(obj, &page, &obj_idx);
3783689a1   Minchan Kim   zsmalloc: introdu...
1392
1393
  	zspage = get_zspage(page);
  	get_zspage_mapping(zspage, &class_idx, &fg);
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1394
  	class = pool->size_class[class_idx];
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1395
  	off = (class->size * obj_idx) & ~PAGE_MASK;
61989a80f   Nitin Gupta   staging: zsmalloc...
1396

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1397
1398
1399
1400
1401
  	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...
1402

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1403
1404
1405
1406
1407
1408
1409
  		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...
1410
1411
  
  	migrate_read_unlock(zspage);
312fcae22   Minchan Kim   zsmalloc: support...
1412
  	unpin_tag(handle);
61989a80f   Nitin Gupta   staging: zsmalloc...
1413
  }
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
1414
  EXPORT_SYMBOL_GPL(zs_unmap_object);
61989a80f   Nitin Gupta   staging: zsmalloc...
1415

251cbb951   Minchan Kim   zsmalloc: reorder...
1416
  static unsigned long obj_malloc(struct size_class *class,
3783689a1   Minchan Kim   zsmalloc: introdu...
1417
  				struct zspage *zspage, unsigned long handle)
c78062612   Minchan Kim   zsmalloc: factor ...
1418
  {
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1419
  	int i, nr_page, offset;
c78062612   Minchan Kim   zsmalloc: factor ...
1420
1421
1422
1423
  	unsigned long obj;
  	struct link_free *link;
  
  	struct page *m_page;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1424
  	unsigned long m_offset;
c78062612   Minchan Kim   zsmalloc: factor ...
1425
  	void *vaddr;
312fcae22   Minchan Kim   zsmalloc: support...
1426
  	handle |= OBJ_ALLOCATED_TAG;
3783689a1   Minchan Kim   zsmalloc: introdu...
1427
  	obj = get_freeobj(zspage);
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1428
1429
1430
1431
1432
1433
1434
1435
  
  	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 ...
1436
1437
1438
  
  	vaddr = kmap_atomic(m_page);
  	link = (struct link_free *)vaddr + m_offset / sizeof(*link);
3b1d9ca65   Minchan Kim   zsmalloc: use OBJ...
1439
  	set_freeobj(zspage, link->next >> OBJ_TAG_BITS);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1440
  	if (likely(!PageHugeObject(m_page)))
7b60a6852   Minchan Kim   zsmalloc: record ...
1441
1442
1443
  		/* record handle in the header of allocated chunk */
  		link->handle = handle;
  	else
3783689a1   Minchan Kim   zsmalloc: introdu...
1444
1445
  		/* record handle to page->index */
  		zspage->first_page->index = handle;
c78062612   Minchan Kim   zsmalloc: factor ...
1446
  	kunmap_atomic(vaddr);
3783689a1   Minchan Kim   zsmalloc: introdu...
1447
  	mod_zspage_inuse(zspage, 1);
c78062612   Minchan Kim   zsmalloc: factor ...
1448
  	zs_stat_inc(class, OBJ_USED, 1);
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1449
  	obj = location_to_obj(m_page, obj);
c78062612   Minchan Kim   zsmalloc: factor ...
1450
1451
  	return obj;
  }
61989a80f   Nitin Gupta   staging: zsmalloc...
1452
1453
1454
1455
  /**
   * 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...
1456
   * @gfp: gfp flags when allocating object
61989a80f   Nitin Gupta   staging: zsmalloc...
1457
   *
00a61d861   Minchan Kim   staging: zsmalloc...
1458
   * On success, handle to the allocated object is returned,
c23443483   Minchan Kim   staging: zsmalloc...
1459
   * otherwise 0.
61989a80f   Nitin Gupta   staging: zsmalloc...
1460
1461
   * Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail.
   */
d0d8da2dc   Sergey Senozhatsky   zsmalloc: require...
1462
  unsigned long zs_malloc(struct zs_pool *pool, size_t size, gfp_t gfp)
61989a80f   Nitin Gupta   staging: zsmalloc...
1463
  {
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1464
  	unsigned long handle, obj;
61989a80f   Nitin Gupta   staging: zsmalloc...
1465
  	struct size_class *class;
48b4800a1   Minchan Kim   zsmalloc: page mi...
1466
  	enum fullness_group newfg;
3783689a1   Minchan Kim   zsmalloc: introdu...
1467
  	struct zspage *zspage;
61989a80f   Nitin Gupta   staging: zsmalloc...
1468

7b60a6852   Minchan Kim   zsmalloc: record ...
1469
  	if (unlikely(!size || size > ZS_MAX_ALLOC_SIZE))
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1470
  		return 0;
3783689a1   Minchan Kim   zsmalloc: introdu...
1471
  	handle = cache_alloc_handle(pool, gfp);
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1472
  	if (!handle)
c23443483   Minchan Kim   staging: zsmalloc...
1473
  		return 0;
61989a80f   Nitin Gupta   staging: zsmalloc...
1474

2e40e163a   Minchan Kim   zsmalloc: decoupl...
1475
1476
  	/* extra space in chunk to keep the handle */
  	size += ZS_HANDLE_SIZE;
9eec4cd53   Joonsoo Kim   zsmalloc: merge s...
1477
  	class = pool->size_class[get_size_class_index(size)];
61989a80f   Nitin Gupta   staging: zsmalloc...
1478
1479
  
  	spin_lock(&class->lock);
3783689a1   Minchan Kim   zsmalloc: introdu...
1480
  	zspage = find_get_zspage(class);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1481
1482
1483
1484
1485
  	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...
1486
  		spin_unlock(&class->lock);
61989a80f   Nitin Gupta   staging: zsmalloc...
1487

48b4800a1   Minchan Kim   zsmalloc: page mi...
1488
1489
  		return handle;
  	}
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
1490

48b4800a1   Minchan Kim   zsmalloc: page mi...
1491
1492
1493
1494
1495
1496
  	spin_unlock(&class->lock);
  
  	zspage = alloc_zspage(pool, class, gfp);
  	if (!zspage) {
  		cache_free_handle(pool, handle);
  		return 0;
61989a80f   Nitin Gupta   staging: zsmalloc...
1497
  	}
48b4800a1   Minchan Kim   zsmalloc: page mi...
1498
  	spin_lock(&class->lock);
3783689a1   Minchan Kim   zsmalloc: introdu...
1499
  	obj = obj_malloc(class, zspage, handle);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1500
1501
1502
  	newfg = get_fullness_group(class, zspage);
  	insert_zspage(class, zspage, newfg);
  	set_zspage_mapping(zspage, class->index, newfg);
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1503
  	record_obj(handle, obj);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1504
1505
  	atomic_long_add(class->pages_per_zspage,
  				&pool->pages_allocated);
b4fd07a08   Ganesh Mahendran   mm/zsmalloc: use ...
1506
  	zs_stat_inc(class, OBJ_ALLOCATED, class->objs_per_zspage);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1507
1508
1509
  
  	/* We completely set up zspage so mark them as movable */
  	SetZsPageMovable(pool, zspage);
61989a80f   Nitin Gupta   staging: zsmalloc...
1510
  	spin_unlock(&class->lock);
2e40e163a   Minchan Kim   zsmalloc: decoupl...
1511
  	return handle;
61989a80f   Nitin Gupta   staging: zsmalloc...
1512
1513
  }
  EXPORT_SYMBOL_GPL(zs_malloc);
1ee471658   Minchan Kim   zsmalloc: remove ...
1514
  static void obj_free(struct size_class *class, unsigned long obj)
61989a80f   Nitin Gupta   staging: zsmalloc...
1515
1516
  {
  	struct link_free *link;
3783689a1   Minchan Kim   zsmalloc: introdu...
1517
1518
  	struct zspage *zspage;
  	struct page *f_page;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1519
1520
  	unsigned long f_offset;
  	unsigned int f_objidx;
af4ee5e97   Minchan Kim   zsmalloc: correct...
1521
  	void *vaddr;
61989a80f   Nitin Gupta   staging: zsmalloc...
1522

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

c78062612   Minchan Kim   zsmalloc: factor ...
1528
  	vaddr = kmap_atomic(f_page);
61989a80f   Nitin Gupta   staging: zsmalloc...
1529
1530
  
  	/* Insert this object in containing zspage's freelist */
af4ee5e97   Minchan Kim   zsmalloc: correct...
1531
  	link = (struct link_free *)(vaddr + f_offset);
3b1d9ca65   Minchan Kim   zsmalloc: use OBJ...
1532
  	link->next = get_freeobj(zspage) << OBJ_TAG_BITS;
af4ee5e97   Minchan Kim   zsmalloc: correct...
1533
  	kunmap_atomic(vaddr);
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1534
  	set_freeobj(zspage, f_objidx);
3783689a1   Minchan Kim   zsmalloc: introdu...
1535
  	mod_zspage_inuse(zspage, -1);
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
1536
  	zs_stat_dec(class, OBJ_USED, 1);
c78062612   Minchan Kim   zsmalloc: factor ...
1537
1538
1539
1540
  }
  
  void zs_free(struct zs_pool *pool, unsigned long handle)
  {
3783689a1   Minchan Kim   zsmalloc: introdu...
1541
1542
  	struct zspage *zspage;
  	struct page *f_page;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1543
1544
  	unsigned long obj;
  	unsigned int f_objidx;
c78062612   Minchan Kim   zsmalloc: factor ...
1545
1546
1547
  	int class_idx;
  	struct size_class *class;
  	enum fullness_group fullness;
48b4800a1   Minchan Kim   zsmalloc: page mi...
1548
  	bool isolated;
c78062612   Minchan Kim   zsmalloc: factor ...
1549
1550
1551
  
  	if (unlikely(!handle))
  		return;
312fcae22   Minchan Kim   zsmalloc: support...
1552
  	pin_tag(handle);
c78062612   Minchan Kim   zsmalloc: factor ...
1553
  	obj = handle_to_obj(handle);
c78062612   Minchan Kim   zsmalloc: factor ...
1554
  	obj_to_location(obj, &f_page, &f_objidx);
3783689a1   Minchan Kim   zsmalloc: introdu...
1555
  	zspage = get_zspage(f_page);
c78062612   Minchan Kim   zsmalloc: factor ...
1556

48b4800a1   Minchan Kim   zsmalloc: page mi...
1557
  	migrate_read_lock(zspage);
3783689a1   Minchan Kim   zsmalloc: introdu...
1558
  	get_zspage_mapping(zspage, &class_idx, &fullness);
c78062612   Minchan Kim   zsmalloc: factor ...
1559
1560
1561
  	class = pool->size_class[class_idx];
  
  	spin_lock(&class->lock);
1ee471658   Minchan Kim   zsmalloc: remove ...
1562
  	obj_free(class, obj);
3783689a1   Minchan Kim   zsmalloc: introdu...
1563
  	fullness = fix_fullness_group(class, zspage);
48b4800a1   Minchan Kim   zsmalloc: page mi...
1564
1565
1566
  	if (fullness != ZS_EMPTY) {
  		migrate_read_unlock(zspage);
  		goto out;
312fcae22   Minchan Kim   zsmalloc: support...
1567
  	}
48b4800a1   Minchan Kim   zsmalloc: page mi...
1568
1569
1570
1571
1572
1573
1574
  
  	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...
1575
  	spin_unlock(&class->lock);
312fcae22   Minchan Kim   zsmalloc: support...
1576
  	unpin_tag(handle);
3783689a1   Minchan Kim   zsmalloc: introdu...
1577
  	cache_free_handle(pool, handle);
312fcae22   Minchan Kim   zsmalloc: support...
1578
1579
  }
  EXPORT_SYMBOL_GPL(zs_free);
251cbb951   Minchan Kim   zsmalloc: reorder...
1580
1581
  static void zs_object_copy(struct size_class *class, unsigned long dst,
  				unsigned long src)
312fcae22   Minchan Kim   zsmalloc: support...
1582
1583
  {
  	struct page *s_page, *d_page;
bfd093f5e   Minchan Kim   zsmalloc: use fre...
1584
  	unsigned int s_objidx, d_objidx;
312fcae22   Minchan Kim   zsmalloc: support...
1585
1586
1587
1588
1589
1590
1591
1592
1593
  	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...
1594
1595
  	s_off = (class->size * s_objidx) & ~PAGE_MASK;
  	d_off = (class->size * d_objidx) & ~PAGE_MASK;
312fcae22   Minchan Kim   zsmalloc: support...
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
  
  	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...
1613
1614
1615
1616
1617
1618
  		s_off += size;
  		s_size -= size;
  		d_off += size;
  		d_size -= size;
  
  		if (s_off >= PAGE_SIZE) {
312fcae22   Minchan Kim   zsmalloc: support...
1619
1620
1621
  			kunmap_atomic(d_addr);
  			kunmap_atomic(s_addr);
  			s_page = get_next_page(s_page);
312fcae22   Minchan Kim   zsmalloc: support...
1622
1623
1624
1625
  			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...
1626
  		}
495819ead   Sergey Senozhatsky   zsmalloc: micro-o...
1627
  		if (d_off >= PAGE_SIZE) {
312fcae22   Minchan Kim   zsmalloc: support...
1628
1629
  			kunmap_atomic(d_addr);
  			d_page = get_next_page(d_page);
312fcae22   Minchan Kim   zsmalloc: support...
1630
1631
1632
  			d_addr = kmap_atomic(d_page);
  			d_size = class->size - written;
  			d_off = 0;
312fcae22   Minchan Kim   zsmalloc: support...
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
  		}
  	}
  
  	kunmap_atomic(d_addr);
  	kunmap_atomic(s_addr);
  }
  
  /*
   * Find alloced object in zspage from index object and
   * return handle.
   */
251cbb951   Minchan Kim   zsmalloc: reorder...
1644
  static unsigned long find_alloced_obj(struct size_class *class,
cf675acb7   Ganesh Mahendran   mm/zsmalloc: take...
1645
  					struct page *page, int *obj_idx)
312fcae22   Minchan Kim   zsmalloc: support...
1646
1647
1648
  {
  	unsigned long head;
  	int offset = 0;
cf675acb7   Ganesh Mahendran   mm/zsmalloc: take...
1649
  	int index = *obj_idx;
312fcae22   Minchan Kim   zsmalloc: support...
1650
1651
  	unsigned long handle = 0;
  	void *addr = kmap_atomic(page);
3783689a1   Minchan Kim   zsmalloc: introdu...
1652
  	offset = get_first_obj_offset(page);
312fcae22   Minchan Kim   zsmalloc: support...
1653
1654
1655
  	offset += class->size * index;
  
  	while (offset < PAGE_SIZE) {
48b4800a1   Minchan Kim   zsmalloc: page mi...
1656
  		head = obj_to_head(page, addr + offset);
312fcae22   Minchan Kim   zsmalloc: support...
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
  		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...
1669
1670
  
  	*obj_idx = index;
312fcae22   Minchan Kim   zsmalloc: support...
1671
1672
1673
1674
  	return handle;
  }
  
  struct zs_compact_control {
3783689a1   Minchan Kim   zsmalloc: introdu...
1675
  	/* Source spage for migration which could be a subpage of zspage */
312fcae22   Minchan Kim   zsmalloc: support...
1676
1677
1678
1679
1680
1681
  	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 ...
1682
  	int obj_idx;
312fcae22   Minchan Kim   zsmalloc: support...
1683
1684
1685
1686
1687
1688
1689
1690
1691
  };
  
  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 ...
1692
  	int obj_idx = cc->obj_idx;
312fcae22   Minchan Kim   zsmalloc: support...
1693
1694
1695
  	int ret = 0;
  
  	while (1) {
cf675acb7   Ganesh Mahendran   mm/zsmalloc: take...
1696
  		handle = find_alloced_obj(class, s_page, &obj_idx);
312fcae22   Minchan Kim   zsmalloc: support...
1697
1698
1699
1700
  		if (!handle) {
  			s_page = get_next_page(s_page);
  			if (!s_page)
  				break;
41b88e14c   Ganesh Mahendran   mm/zsmalloc: use ...
1701
  			obj_idx = 0;
312fcae22   Minchan Kim   zsmalloc: support...
1702
1703
1704
1705
  			continue;
  		}
  
  		/* Stop if there is no more space */
3783689a1   Minchan Kim   zsmalloc: introdu...
1706
  		if (zspage_full(class, get_zspage(d_page))) {
312fcae22   Minchan Kim   zsmalloc: support...
1707
1708
1709
1710
1711
1712
  			unpin_tag(handle);
  			ret = -ENOMEM;
  			break;
  		}
  
  		used_obj = handle_to_obj(handle);
3783689a1   Minchan Kim   zsmalloc: introdu...
1713
  		free_obj = obj_malloc(class, get_zspage(d_page), handle);
251cbb951   Minchan Kim   zsmalloc: reorder...
1714
  		zs_object_copy(class, free_obj, used_obj);
41b88e14c   Ganesh Mahendran   mm/zsmalloc: use ...
1715
  		obj_idx++;
c102f07ca   Junil Lee   zsmalloc: fix mig...
1716
1717
1718
1719
1720
1721
1722
  		/*
  		 * 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...
1723
1724
  		record_obj(handle, free_obj);
  		unpin_tag(handle);
1ee471658   Minchan Kim   zsmalloc: remove ...
1725
  		obj_free(class, used_obj);
312fcae22   Minchan Kim   zsmalloc: support...
1726
1727
1728
1729
  	}
  
  	/* Remember last position in this iteration */
  	cc->s_page = s_page;
41b88e14c   Ganesh Mahendran   mm/zsmalloc: use ...
1730
  	cc->obj_idx = obj_idx;
312fcae22   Minchan Kim   zsmalloc: support...
1731
1732
1733
  
  	return ret;
  }
3783689a1   Minchan Kim   zsmalloc: introdu...
1734
  static struct zspage *isolate_zspage(struct size_class *class, bool source)
312fcae22   Minchan Kim   zsmalloc: support...
1735
1736
  {
  	int i;
3783689a1   Minchan Kim   zsmalloc: introdu...
1737
1738
  	struct zspage *zspage;
  	enum fullness_group fg[2] = {ZS_ALMOST_EMPTY, ZS_ALMOST_FULL};
312fcae22   Minchan Kim   zsmalloc: support...
1739

3783689a1   Minchan Kim   zsmalloc: introdu...
1740
1741
1742
1743
1744
1745
1746
1747
1748
  	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...
1749
  			VM_BUG_ON(is_zspage_isolated(zspage));
3783689a1   Minchan Kim   zsmalloc: introdu...
1750
1751
  			remove_zspage(class, zspage, fg[i]);
  			return zspage;
312fcae22   Minchan Kim   zsmalloc: support...
1752
1753
  		}
  	}
3783689a1   Minchan Kim   zsmalloc: introdu...
1754
  	return zspage;
312fcae22   Minchan Kim   zsmalloc: support...
1755
  }
860c707dc   Sergey Senozhatsky   zsmalloc: account...
1756
  /*
3783689a1   Minchan Kim   zsmalloc: introdu...
1757
   * putback_zspage - add @zspage into right class's fullness list
860c707dc   Sergey Senozhatsky   zsmalloc: account...
1758
   * @class: destination class
3783689a1   Minchan Kim   zsmalloc: introdu...
1759
   * @zspage: target page
860c707dc   Sergey Senozhatsky   zsmalloc: account...
1760
   *
3783689a1   Minchan Kim   zsmalloc: introdu...
1761
   * Return @zspage's fullness_group
860c707dc   Sergey Senozhatsky   zsmalloc: account...
1762
   */
4aa409cab   Minchan Kim   zsmalloc: separat...
1763
  static enum fullness_group putback_zspage(struct size_class *class,
3783689a1   Minchan Kim   zsmalloc: introdu...
1764
  			struct zspage *zspage)
312fcae22   Minchan Kim   zsmalloc: support...
1765
  {
312fcae22   Minchan Kim   zsmalloc: support...
1766
  	enum fullness_group fullness;
48b4800a1   Minchan Kim   zsmalloc: page mi...
1767
  	VM_BUG_ON(is_zspage_isolated(zspage));
3783689a1   Minchan Kim   zsmalloc: introdu...
1768
1769
1770
  	fullness = get_fullness_group(class, zspage);
  	insert_zspage(class, zspage, fullness);
  	set_zspage_mapping(zspage, class->index, fullness);
839373e64   Minchan Kim   zsmalloc: remove ...
1771

860c707dc   Sergey Senozhatsky   zsmalloc: account...
1772
  	return fullness;
61989a80f   Nitin Gupta   staging: zsmalloc...
1773
  }
312fcae22   Minchan Kim   zsmalloc: support...
1774

48b4800a1   Minchan Kim   zsmalloc: page mi...
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
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
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
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
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
  #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;
  
  	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)) {
  		ret = -EBUSY;
  		goto unlock_class;
  	}
  
  	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...
2007
  	ret = MIGRATEPAGE_SUCCESS;
48b4800a1   Minchan Kim   zsmalloc: page mi...
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
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
  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);
  unlock_class:
  	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 ...
2081
  	iput(pool->inode);
48b4800a1   Minchan Kim   zsmalloc: page mi...
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
  }
  
  /*
   * 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);
  
  	for (i = 0; i < zs_size_classes; i++) {
  		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...
2144
2145
2146
2147
  /*
   *
   * Based on the number of unused allocated objects calculate
   * and return the number of pages that we can free.
04f05909e   Sergey Senozhatsky   zsmalloc: introdu...
2148
2149
2150
2151
   */
  static unsigned long zs_can_compact(struct size_class *class)
  {
  	unsigned long obj_wasted;
44f43e99f   Sergey Senozhatsky   zsmalloc: fix zs_...
2152
2153
  	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...
2154

44f43e99f   Sergey Senozhatsky   zsmalloc: fix zs_...
2155
2156
  	if (obj_allocated <= obj_used)
  		return 0;
04f05909e   Sergey Senozhatsky   zsmalloc: introdu...
2157

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

6cbf16b3b   Minchan Kim   zsmalloc: use cla...
2161
  	return obj_wasted * class->pages_per_zspage;
04f05909e   Sergey Senozhatsky   zsmalloc: introdu...
2162
  }
7d3f39382   Sergey Senozhatsky   zsmalloc/zram: in...
2163
  static void __zs_compact(struct zs_pool *pool, struct size_class *class)
312fcae22   Minchan Kim   zsmalloc: support...
2164
  {
312fcae22   Minchan Kim   zsmalloc: support...
2165
  	struct zs_compact_control cc;
3783689a1   Minchan Kim   zsmalloc: introdu...
2166
2167
  	struct zspage *src_zspage;
  	struct zspage *dst_zspage = NULL;
312fcae22   Minchan Kim   zsmalloc: support...
2168

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

04f05909e   Sergey Senozhatsky   zsmalloc: introdu...
2172
2173
  		if (!zs_can_compact(class))
  			break;
41b88e14c   Ganesh Mahendran   mm/zsmalloc: use ...
2174
  		cc.obj_idx = 0;
48b4800a1   Minchan Kim   zsmalloc: page mi...
2175
  		cc.s_page = get_first_page(src_zspage);
312fcae22   Minchan Kim   zsmalloc: support...
2176

3783689a1   Minchan Kim   zsmalloc: introdu...
2177
  		while ((dst_zspage = isolate_zspage(class, false))) {
48b4800a1   Minchan Kim   zsmalloc: page mi...
2178
  			cc.d_page = get_first_page(dst_zspage);
312fcae22   Minchan Kim   zsmalloc: support...
2179
  			/*
0dc63d488   Sergey Senozhatsky   zsmalloc: cosmeti...
2180
2181
  			 * If there is no more space in dst_page, resched
  			 * and see if anyone had allocated another zspage.
312fcae22   Minchan Kim   zsmalloc: support...
2182
2183
2184
  			 */
  			if (!migrate_zspage(pool, class, &cc))
  				break;
4aa409cab   Minchan Kim   zsmalloc: separat...
2185
  			putback_zspage(class, dst_zspage);
312fcae22   Minchan Kim   zsmalloc: support...
2186
2187
2188
  		}
  
  		/* Stop if we couldn't find slot */
3783689a1   Minchan Kim   zsmalloc: introdu...
2189
  		if (dst_zspage == NULL)
312fcae22   Minchan Kim   zsmalloc: support...
2190
  			break;
4aa409cab   Minchan Kim   zsmalloc: separat...
2191
2192
  		putback_zspage(class, dst_zspage);
  		if (putback_zspage(class, src_zspage) == ZS_EMPTY) {
48b4800a1   Minchan Kim   zsmalloc: page mi...
2193
  			free_zspage(pool, class, src_zspage);
6cbf16b3b   Minchan Kim   zsmalloc: use cla...
2194
  			pool->stats.pages_compacted += class->pages_per_zspage;
4aa409cab   Minchan Kim   zsmalloc: separat...
2195
  		}
312fcae22   Minchan Kim   zsmalloc: support...
2196
  		spin_unlock(&class->lock);
312fcae22   Minchan Kim   zsmalloc: support...
2197
2198
2199
  		cond_resched();
  		spin_lock(&class->lock);
  	}
3783689a1   Minchan Kim   zsmalloc: introdu...
2200
  	if (src_zspage)
4aa409cab   Minchan Kim   zsmalloc: separat...
2201
  		putback_zspage(class, src_zspage);
312fcae22   Minchan Kim   zsmalloc: support...
2202

7d3f39382   Sergey Senozhatsky   zsmalloc/zram: in...
2203
  	spin_unlock(&class->lock);
312fcae22   Minchan Kim   zsmalloc: support...
2204
2205
2206
2207
2208
  }
  
  unsigned long zs_compact(struct zs_pool *pool)
  {
  	int i;
312fcae22   Minchan Kim   zsmalloc: support...
2209
2210
2211
2212
2213
2214
2215
2216
  	struct size_class *class;
  
  	for (i = zs_size_classes - 1; i >= 0; i--) {
  		class = pool->size_class[i];
  		if (!class)
  			continue;
  		if (class->index != i)
  			continue;
7d3f39382   Sergey Senozhatsky   zsmalloc/zram: in...
2217
  		__zs_compact(pool, class);
312fcae22   Minchan Kim   zsmalloc: support...
2218
  	}
860c707dc   Sergey Senozhatsky   zsmalloc: account...
2219
  	return pool->stats.pages_compacted;
312fcae22   Minchan Kim   zsmalloc: support...
2220
2221
  }
  EXPORT_SYMBOL_GPL(zs_compact);
61989a80f   Nitin Gupta   staging: zsmalloc...
2222

7d3f39382   Sergey Senozhatsky   zsmalloc/zram: in...
2223
2224
2225
2226
2227
  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...
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
  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);
ab9d306d9   Sergey Senozhatsky   zsmalloc: use shr...
2254
2255
2256
2257
2258
2259
  	for (i = zs_size_classes - 1; i >= 0; i--) {
  		class = pool->size_class[i];
  		if (!class)
  			continue;
  		if (class->index != i)
  			continue;
ab9d306d9   Sergey Senozhatsky   zsmalloc: use shr...
2260
  		pages_to_free += zs_can_compact(class);
ab9d306d9   Sergey Senozhatsky   zsmalloc: use shr...
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
  	}
  
  	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...
2283
  /**
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2284
   * zs_create_pool - Creates an allocation pool to work from.
fd8544639   Ganesh Mahendran   mm/zsmalloc: keep...
2285
   * @name: pool name to be created
166cfda75   Seth Jennings   staging: zsmalloc...
2286
   *
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2287
2288
   * This function must be called before anything when using
   * the zsmalloc allocator.
166cfda75   Seth Jennings   staging: zsmalloc...
2289
   *
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2290
2291
   * On success, a pointer to the newly created pool is returned,
   * otherwise NULL.
396b7fd6f   Sara Bird   staging/zsmalloc:...
2292
   */
d0d8da2dc   Sergey Senozhatsky   zsmalloc: require...
2293
  struct zs_pool *zs_create_pool(const char *name)
61989a80f   Nitin Gupta   staging: zsmalloc...
2294
  {
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2295
2296
2297
  	int i;
  	struct zs_pool *pool;
  	struct size_class *prev_class = NULL;
61989a80f   Nitin Gupta   staging: zsmalloc...
2298

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2299
2300
2301
  	pool = kzalloc(sizeof(*pool), GFP_KERNEL);
  	if (!pool)
  		return NULL;
61989a80f   Nitin Gupta   staging: zsmalloc...
2302

48b4800a1   Minchan Kim   zsmalloc: page mi...
2303
  	init_deferred_free(pool);
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2304
2305
2306
2307
2308
2309
  	pool->size_class = kcalloc(zs_size_classes, sizeof(struct size_class *),
  			GFP_KERNEL);
  	if (!pool->size_class) {
  		kfree(pool);
  		return NULL;
  	}
61989a80f   Nitin Gupta   staging: zsmalloc...
2310

2e40e163a   Minchan Kim   zsmalloc: decoupl...
2311
2312
2313
  	pool->name = kstrdup(name, GFP_KERNEL);
  	if (!pool->name)
  		goto err;
3783689a1   Minchan Kim   zsmalloc: introdu...
2314
  	if (create_cache(pool))
2e40e163a   Minchan Kim   zsmalloc: decoupl...
2315
  		goto err;
c60369f01   Seth Jennings   staging: zsmalloc...
2316
  	/*
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2317
2318
  	 * Iterate reversly, because, size of size_class that we want to use
  	 * for merging should be larger or equal to current size.
c60369f01   Seth Jennings   staging: zsmalloc...
2319
  	 */
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2320
2321
2322
  	for (i = zs_size_classes - 1; i >= 0; i--) {
  		int size;
  		int pages_per_zspage;
64d90465f   Ganesh Mahendran   mm/zsmalloc: avoi...
2323
  		int objs_per_zspage;
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2324
  		struct size_class *class;
3783689a1   Minchan Kim   zsmalloc: introdu...
2325
  		int fullness = 0;
c60369f01   Seth Jennings   staging: zsmalloc...
2326

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2327
2328
2329
2330
  		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...
2331
  		objs_per_zspage = pages_per_zspage * PAGE_SIZE / size;
61989a80f   Nitin Gupta   staging: zsmalloc...
2332

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
  		/*
  		 * 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...
2343
  			if (can_merge(prev_class, pages_per_zspage, objs_per_zspage)) {
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
  				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...
2356
  		class->objs_per_zspage = objs_per_zspage;
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2357
2358
  		spin_lock_init(&class->lock);
  		pool->size_class[i] = class;
48b4800a1   Minchan Kim   zsmalloc: page mi...
2359
2360
  		for (fullness = ZS_EMPTY; fullness < NR_ZS_FULLNESS;
  							fullness++)
3783689a1   Minchan Kim   zsmalloc: introdu...
2361
  			INIT_LIST_HEAD(&class->fullness_list[fullness]);
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2362
2363
  
  		prev_class = class;
61989a80f   Nitin Gupta   staging: zsmalloc...
2364
  	}
d34f61572   Dan Streetman   mm/zsmalloc: don'...
2365
2366
  	/* debug only, don't abort if it fails */
  	zs_pool_stat_create(pool, name);
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2367

48b4800a1   Minchan Kim   zsmalloc: page mi...
2368
2369
  	if (zs_register_migration(pool))
  		goto err;
ab9d306d9   Sergey Senozhatsky   zsmalloc: use shr...
2370
2371
2372
2373
2374
2375
  	/*
  	 * 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...
2376
2377
2378
2379
2380
  	return pool;
  
  err:
  	zs_destroy_pool(pool);
  	return NULL;
61989a80f   Nitin Gupta   staging: zsmalloc...
2381
  }
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2382
  EXPORT_SYMBOL_GPL(zs_create_pool);
61989a80f   Nitin Gupta   staging: zsmalloc...
2383

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2384
  void zs_destroy_pool(struct zs_pool *pool)
61989a80f   Nitin Gupta   staging: zsmalloc...
2385
  {
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2386
  	int i;
61989a80f   Nitin Gupta   staging: zsmalloc...
2387

ab9d306d9   Sergey Senozhatsky   zsmalloc: use shr...
2388
  	zs_unregister_shrinker(pool);
48b4800a1   Minchan Kim   zsmalloc: page mi...
2389
  	zs_unregister_migration(pool);
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2390
  	zs_pool_stat_destroy(pool);
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2391
2392
2393
  	for (i = 0; i < zs_size_classes; i++) {
  		int fg;
  		struct size_class *class = pool->size_class[i];
61989a80f   Nitin Gupta   staging: zsmalloc...
2394

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2395
2396
  		if (!class)
  			continue;
61989a80f   Nitin Gupta   staging: zsmalloc...
2397

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

48b4800a1   Minchan Kim   zsmalloc: page mi...
2401
  		for (fg = ZS_EMPTY; fg < NR_ZS_FULLNESS; fg++) {
3783689a1   Minchan Kim   zsmalloc: introdu...
2402
  			if (!list_empty(&class->fullness_list[fg])) {
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2403
2404
2405
2406
2407
2408
2409
  				pr_info("Freeing non-empty class with size %db, fullness group %d
  ",
  					class->size, fg);
  			}
  		}
  		kfree(class);
  	}
f553646a6   Seth Jennings   staging: zsmalloc...
2410

3783689a1   Minchan Kim   zsmalloc: introdu...
2411
  	destroy_cache(pool);
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2412
  	kfree(pool->size_class);
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2413
  	kfree(pool->name);
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2414
2415
2416
  	kfree(pool);
  }
  EXPORT_SYMBOL_GPL(zs_destroy_pool);
b74185108   Seth Jennings   staging: zsmalloc...
2417

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2418
2419
  static int __init zs_init(void)
  {
48b4800a1   Minchan Kim   zsmalloc: page mi...
2420
2421
2422
2423
2424
2425
2426
  	int ret;
  
  	ret = zsmalloc_mount();
  	if (ret)
  		goto out;
  
  	ret = zs_register_cpu_notifier();
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2427

0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2428
2429
  	if (ret)
  		goto notifier_fail;
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2430
2431
2432
2433
2434
2435
  
  	init_zs_size_classes();
  
  #ifdef CONFIG_ZPOOL
  	zpool_register_driver(&zs_zpool_driver);
  #endif
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2436

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

0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2440
2441
  notifier_fail:
  	zs_unregister_cpu_notifier();
48b4800a1   Minchan Kim   zsmalloc: page mi...
2442
2443
  	zsmalloc_unmount();
  out:
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2444
  	return ret;
61989a80f   Nitin Gupta   staging: zsmalloc...
2445
  }
61989a80f   Nitin Gupta   staging: zsmalloc...
2446

66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2447
  static void __exit zs_exit(void)
61989a80f   Nitin Gupta   staging: zsmalloc...
2448
  {
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2449
2450
2451
  #ifdef CONFIG_ZPOOL
  	zpool_unregister_driver(&zs_zpool_driver);
  #endif
48b4800a1   Minchan Kim   zsmalloc: page mi...
2452
  	zsmalloc_unmount();
66cdef663   Ganesh Mahendran   mm/zsmalloc: adju...
2453
  	zs_unregister_cpu_notifier();
0f050d997   Ganesh Mahendran   mm/zsmalloc: add ...
2454
2455
  
  	zs_stat_exit();
61989a80f   Nitin Gupta   staging: zsmalloc...
2456
  }
069f101fa   Ben Hutchings   staging: zsmalloc...
2457
2458
2459
2460
2461
2462
  
  module_init(zs_init);
  module_exit(zs_exit);
  
  MODULE_LICENSE("Dual BSD/GPL");
  MODULE_AUTHOR("Nitin Gupta <ngupta@vflare.org>");