Merge 4.3-rc5 into staging-next
[firefly-linux-kernel-4.4.55.git] / mm / zsmalloc.c
index 27b9661c8fa67fa8f434ecd9fc5e92d08621c64e..f135b1b6fcdcab49aaf0845e078c6fc299b4b28b 100644 (file)
@@ -288,8 +288,7 @@ static int create_handle_cache(struct zs_pool *pool)
 
 static void destroy_handle_cache(struct zs_pool *pool)
 {
-       if (pool->handle_cachep)
-               kmem_cache_destroy(pool->handle_cachep);
+       kmem_cache_destroy(pool->handle_cachep);
 }
 
 static unsigned long alloc_handle(struct zs_pool *pool)
@@ -312,7 +311,8 @@ static void record_obj(unsigned long handle, unsigned long obj)
 
 #ifdef CONFIG_ZPOOL
 
-static void *zs_zpool_create(char *name, gfp_t gfp, struct zpool_ops *zpool_ops,
+static void *zs_zpool_create(char *name, gfp_t gfp,
+                            const struct zpool_ops *zpool_ops,
                             struct zpool *zpool)
 {
        return zs_create_pool(name, gfp);
@@ -643,13 +643,22 @@ static void insert_zspage(struct page *page, struct size_class *class,
        if (fullness >= _ZS_NR_FULLNESS_GROUPS)
                return;
 
-       head = &class->fullness_list[fullness];
-       if (*head)
-               list_add_tail(&page->lru, &(*head)->lru);
-
-       *head = page;
        zs_stat_inc(class, fullness == ZS_ALMOST_EMPTY ?
                        CLASS_ALMOST_EMPTY : CLASS_ALMOST_FULL, 1);
+
+       head = &class->fullness_list[fullness];
+       if (!*head) {
+               *head = page;
+               return;
+       }
+
+       /*
+        * We want to see more ZS_FULL pages and less almost
+        * empty/full. Put pages with higher ->inuse first.
+        */
+       list_add_tail(&page->lru, &(*head)->lru);
+       if (page->inuse >= (*head)->inuse)
+               *head = page;
 }
 
 /*
@@ -1682,11 +1691,17 @@ static enum fullness_group putback_zspage(struct zs_pool *pool,
 
 static struct page *isolate_source_page(struct size_class *class)
 {
-       struct page *page;
+       int i;
+       struct page *page = NULL;
 
-       page = class->fullness_list[ZS_ALMOST_EMPTY];
-       if (page)
-               remove_zspage(page, class, ZS_ALMOST_EMPTY);
+       for (i = ZS_ALMOST_EMPTY; i >= ZS_ALMOST_FULL; i--) {
+               page = class->fullness_list[i];
+               if (!page)
+                       continue;
+
+               remove_zspage(page, class, i);
+               break;
+       }
 
        return page;
 }
@@ -1695,23 +1710,18 @@ static struct page *isolate_source_page(struct size_class *class)
  *
  * Based on the number of unused allocated objects calculate
  * and return the number of pages that we can free.
- *
- * Should be called under class->lock.
  */
 static unsigned long zs_can_compact(struct size_class *class)
 {
        unsigned long obj_wasted;
 
-       if (!zs_stat_get(class, CLASS_ALMOST_EMPTY))
-               return 0;
-
        obj_wasted = zs_stat_get(class, OBJ_ALLOCATED) -
                zs_stat_get(class, OBJ_USED);
 
        obj_wasted /= get_maxobj_per_zspage(class->size,
                        class->pages_per_zspage);
 
-       return obj_wasted * get_pages_per_zspage(class->size);
+       return obj_wasted * class->pages_per_zspage;
 }
 
 static void __zs_compact(struct zs_pool *pool, struct size_class *class)
@@ -1749,8 +1759,7 @@ static void __zs_compact(struct zs_pool *pool, struct size_class *class)
 
                putback_zspage(pool, class, dst_page);
                if (putback_zspage(pool, class, src_page) == ZS_EMPTY)
-                       pool->stats.pages_compacted +=
-                               get_pages_per_zspage(class->size);
+                       pool->stats.pages_compacted += class->pages_per_zspage;
                spin_unlock(&class->lock);
                cond_resched();
                spin_lock(&class->lock);
@@ -1823,9 +1832,7 @@ static unsigned long zs_shrinker_count(struct shrinker *shrinker,
                if (class->index != i)
                        continue;
 
-               spin_lock(&class->lock);
                pages_to_free += zs_can_compact(class);
-               spin_unlock(&class->lock);
        }
 
        return pages_to_free;