aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMinchan Kim <minchan@kernel.org>2015-04-15 19:15:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-15 19:35:21 -0400
commit7b60a68529b0d827d26ea3426c2addd071bff789 (patch)
tree5d812c66da45b12b2ae005b7db950596751e3ba5
parent4e3ba87845420e0bfa21e6c4f7f81897aed38f8c (diff)
zsmalloc: record handle in page->private for huge object
We store handle on header of each allocated object so it increases the size of each object by sizeof(unsigned long). If zram stores 4096 bytes to zsmalloc(ie, bad compression), zsmalloc needs 4104B-class to add handle. However, 4104B-class has 1-pages_per_zspage so wasted size by internal fragment is 8192 - 4104, which is terrible. So this patch records the handle in page->private on such huge object(ie, pages_per_zspage == 1 && maxobj_per_zspage == 1) instead of header of each object so we could use 4096B-class, not 4104B-class. Signed-off-by: Minchan Kim <minchan@kernel.org> Cc: Juneho Choi <juno.choi@lge.com> Cc: Gunho Lee <gunho.lee@lge.com> Cc: Luigi Semenzato <semenzato@google.com> Cc: Dan Streetman <ddstreet@ieee.org> Cc: Seth Jennings <sjennings@variantweb.net> Cc: Nitin Gupta <ngupta@vflare.org> Cc: Jerome Marchand <jmarchan@redhat.com> Cc: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Cc: Mel Gorman <mel@csn.ul.ie> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/zsmalloc.c54
1 files changed, 42 insertions, 12 deletions
diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
index 3bd8b0a16462..95771c75f2e9 100644
--- a/mm/zsmalloc.c
+++ b/mm/zsmalloc.c
@@ -57,6 +57,8 @@
57 * 57 *
58 * page->private (union with page->first_page): refers to the 58 * page->private (union with page->first_page): refers to the
59 * component page after the first page 59 * component page after the first page
60 * If the page is first_page for huge object, it stores handle.
61 * Look at size_class->huge.
60 * page->freelist: points to the first free object in zspage. 62 * page->freelist: points to the first free object in zspage.
61 * Free objects are linked together using in-place 63 * Free objects are linked together using in-place
62 * metadata. 64 * metadata.
@@ -163,7 +165,7 @@
163#define ZS_MIN_ALLOC_SIZE \ 165#define ZS_MIN_ALLOC_SIZE \
164 MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS)) 166 MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
165/* each chunk includes extra space to keep handle */ 167/* each chunk includes extra space to keep handle */
166#define ZS_MAX_ALLOC_SIZE (PAGE_SIZE + ZS_HANDLE_SIZE) 168#define ZS_MAX_ALLOC_SIZE PAGE_SIZE
167 169
168/* 170/*
169 * On systems with 4K page size, this gives 255 size classes! There is a 171 * On systems with 4K page size, this gives 255 size classes! There is a
@@ -239,6 +241,8 @@ struct size_class {
239 241
240 /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */ 242 /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
241 int pages_per_zspage; 243 int pages_per_zspage;
244 /* huge object: pages_per_zspage == 1 && maxobj_per_zspage == 1 */
245 bool huge;
242 246
243#ifdef CONFIG_ZSMALLOC_STAT 247#ifdef CONFIG_ZSMALLOC_STAT
244 struct zs_size_stat stats; 248 struct zs_size_stat stats;
@@ -300,6 +304,7 @@ struct mapping_area {
300#endif 304#endif
301 char *vm_addr; /* address of kmap_atomic()'ed pages */ 305 char *vm_addr; /* address of kmap_atomic()'ed pages */
302 enum zs_mapmode vm_mm; /* mapping mode */ 306 enum zs_mapmode vm_mm; /* mapping mode */
307 bool huge;
303}; 308};
304 309
305static int create_handle_cache(struct zs_pool *pool) 310static int create_handle_cache(struct zs_pool *pool)
@@ -457,7 +462,7 @@ static int get_size_class_index(int size)
457 idx = DIV_ROUND_UP(size - ZS_MIN_ALLOC_SIZE, 462 idx = DIV_ROUND_UP(size - ZS_MIN_ALLOC_SIZE,
458 ZS_SIZE_CLASS_DELTA); 463 ZS_SIZE_CLASS_DELTA);
459 464
460 return idx; 465 return min(zs_size_classes - 1, idx);
461} 466}
462 467
463/* 468/*
@@ -666,9 +671,14 @@ static unsigned long handle_to_obj(unsigned long handle)
666 return *(unsigned long *)handle; 671 return *(unsigned long *)handle;
667} 672}
668 673
669unsigned long obj_to_head(void *obj) 674static unsigned long obj_to_head(struct size_class *class, struct page *page,
675 void *obj)
670{ 676{
671 return *(unsigned long *)obj; 677 if (class->huge) {
678 VM_BUG_ON(!is_first_page(page));
679 return *(unsigned long *)page_private(page);
680 } else
681 return *(unsigned long *)obj;
672} 682}
673 683
674static unsigned long obj_idx_to_offset(struct page *page, 684static unsigned long obj_idx_to_offset(struct page *page,
@@ -954,9 +964,12 @@ static void __zs_unmap_object(struct mapping_area *area,
954 if (area->vm_mm == ZS_MM_RO) 964 if (area->vm_mm == ZS_MM_RO)
955 goto out; 965 goto out;
956 966
957 buf = area->vm_buf + ZS_HANDLE_SIZE; 967 buf = area->vm_buf;
958 size -= ZS_HANDLE_SIZE; 968 if (!area->huge) {
959 off += ZS_HANDLE_SIZE; 969 buf = buf + ZS_HANDLE_SIZE;
970 size -= ZS_HANDLE_SIZE;
971 off += ZS_HANDLE_SIZE;
972 }
960 973
961 sizes[0] = PAGE_SIZE - off; 974 sizes[0] = PAGE_SIZE - off;
962 sizes[1] = size - sizes[0]; 975 sizes[1] = size - sizes[0];
@@ -1295,7 +1308,10 @@ void *zs_map_object(struct zs_pool *pool, unsigned long handle,
1295 1308
1296 ret = __zs_map_object(area, pages, off, class->size); 1309 ret = __zs_map_object(area, pages, off, class->size);
1297out: 1310out:
1298 return ret + ZS_HANDLE_SIZE; 1311 if (!class->huge)
1312 ret += ZS_HANDLE_SIZE;
1313
1314 return ret;
1299} 1315}
1300EXPORT_SYMBOL_GPL(zs_map_object); 1316EXPORT_SYMBOL_GPL(zs_map_object);
1301 1317
@@ -1352,8 +1368,12 @@ static unsigned long obj_malloc(struct page *first_page,
1352 vaddr = kmap_atomic(m_page); 1368 vaddr = kmap_atomic(m_page);
1353 link = (struct link_free *)vaddr + m_offset / sizeof(*link); 1369 link = (struct link_free *)vaddr + m_offset / sizeof(*link);
1354 first_page->freelist = link->next; 1370 first_page->freelist = link->next;
1355 /* record handle in the header of allocated chunk */ 1371 if (!class->huge)
1356 link->handle = handle; 1372 /* record handle in the header of allocated chunk */
1373 link->handle = handle;
1374 else
1375 /* record handle in first_page->private */
1376 set_page_private(first_page, handle);
1357 kunmap_atomic(vaddr); 1377 kunmap_atomic(vaddr);
1358 first_page->inuse++; 1378 first_page->inuse++;
1359 zs_stat_inc(class, OBJ_USED, 1); 1379 zs_stat_inc(class, OBJ_USED, 1);
@@ -1377,7 +1397,7 @@ unsigned long zs_malloc(struct zs_pool *pool, size_t size)
1377 struct size_class *class; 1397 struct size_class *class;
1378 struct page *first_page; 1398 struct page *first_page;
1379 1399
1380 if (unlikely(!size || (size + ZS_HANDLE_SIZE) > ZS_MAX_ALLOC_SIZE)) 1400 if (unlikely(!size || size > ZS_MAX_ALLOC_SIZE))
1381 return 0; 1401 return 0;
1382 1402
1383 handle = alloc_handle(pool); 1403 handle = alloc_handle(pool);
@@ -1387,6 +1407,11 @@ unsigned long zs_malloc(struct zs_pool *pool, size_t size)
1387 /* extra space in chunk to keep the handle */ 1407 /* extra space in chunk to keep the handle */
1388 size += ZS_HANDLE_SIZE; 1408 size += ZS_HANDLE_SIZE;
1389 class = pool->size_class[get_size_class_index(size)]; 1409 class = pool->size_class[get_size_class_index(size)];
1410 /* In huge class size, we store the handle into first_page->private */
1411 if (class->huge) {
1412 size -= ZS_HANDLE_SIZE;
1413 class = pool->size_class[get_size_class_index(size)];
1414 }
1390 1415
1391 spin_lock(&class->lock); 1416 spin_lock(&class->lock);
1392 first_page = find_get_zspage(class); 1417 first_page = find_get_zspage(class);
@@ -1442,6 +1467,8 @@ static void obj_free(struct zs_pool *pool, struct size_class *class,
1442 /* Insert this object in containing zspage's freelist */ 1467 /* Insert this object in containing zspage's freelist */
1443 link = (struct link_free *)(vaddr + f_offset); 1468 link = (struct link_free *)(vaddr + f_offset);
1444 link->next = first_page->freelist; 1469 link->next = first_page->freelist;
1470 if (class->huge)
1471 set_page_private(first_page, 0);
1445 kunmap_atomic(vaddr); 1472 kunmap_atomic(vaddr);
1446 first_page->freelist = (void *)obj; 1473 first_page->freelist = (void *)obj;
1447 first_page->inuse--; 1474 first_page->inuse--;
@@ -1567,7 +1594,7 @@ static unsigned long find_alloced_obj(struct page *page, int index,
1567 offset += class->size * index; 1594 offset += class->size * index;
1568 1595
1569 while (offset < PAGE_SIZE) { 1596 while (offset < PAGE_SIZE) {
1570 head = obj_to_head(addr + offset); 1597 head = obj_to_head(class, page, addr + offset);
1571 if (head & OBJ_ALLOCATED_TAG) { 1598 if (head & OBJ_ALLOCATED_TAG) {
1572 handle = head & ~OBJ_ALLOCATED_TAG; 1599 handle = head & ~OBJ_ALLOCATED_TAG;
1573 if (trypin_tag(handle)) 1600 if (trypin_tag(handle))
@@ -1837,6 +1864,9 @@ struct zs_pool *zs_create_pool(char *name, gfp_t flags)
1837 class->size = size; 1864 class->size = size;
1838 class->index = i; 1865 class->index = i;
1839 class->pages_per_zspage = pages_per_zspage; 1866 class->pages_per_zspage = pages_per_zspage;
1867 if (pages_per_zspage == 1 &&
1868 get_maxobj_per_zspage(size, pages_per_zspage) == 1)
1869 class->huge = true;
1840 spin_lock_init(&class->lock); 1870 spin_lock_init(&class->lock);
1841 pool->size_class[i] = class; 1871 pool->size_class[i] = class;
1842 1872