This patch allows a zsmalloc user to define the page
allocation and free functions to be used when growing
or releasing parts of the memory pool.

The functions are passed in the struct zs_pool_ops parameter
of zs_create_pool() at pool creation time.  If this parameter
is NULL, zsmalloc uses alloc_page and __free_page() by default.

While there is no current user of this functionality, zcache
development plans to make use of it in the near future.

Patch applies to Greg's staging-next branch.

Signed-off-by: Seth Jennings <[email protected]>
---
 drivers/staging/zcache/zcache-main.c     |    2 +-
 drivers/staging/zram/zram_drv.c          |    3 +-
 drivers/staging/zsmalloc/zsmalloc-main.c |   39 +++++++++++++++++++++++-------
 drivers/staging/zsmalloc/zsmalloc.h      |    8 +++++-
 drivers/staging/zsmalloc/zsmalloc_int.h  |    2 +
 5 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/drivers/staging/zcache/zcache-main.c 
b/drivers/staging/zcache/zcache-main.c
index b698464..7ef5313 100644
--- a/drivers/staging/zcache/zcache-main.c
+++ b/drivers/staging/zcache/zcache-main.c
@@ -984,7 +984,7 @@ int zcache_new_client(uint16_t cli_id)
                goto out;
        cli->allocated = 1;
 #ifdef CONFIG_FRONTSWAP
-       cli->zspool = zs_create_pool("zcache", ZCACHE_GFP_MASK);
+       cli->zspool = zs_create_pool("zcache", ZCACHE_GFP_MASK, NULL);
        if (cli->zspool == NULL)
                goto out;
 #endif
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index 7f13819..278eb4d 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -663,7 +663,8 @@ int zram_init_device(struct zram *zram)
        /* zram devices sort of resembles non-rotational disks */
        queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
 
-       zram->mem_pool = zs_create_pool("zram", GFP_NOIO | __GFP_HIGHMEM);
+       zram->mem_pool = zs_create_pool("zram", GFP_NOIO | __GFP_HIGHMEM,
+                                       NULL);
        if (!zram->mem_pool) {
                pr_err("Error creating memory pool\n");
                ret = -ENOMEM;
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c 
b/drivers/staging/zsmalloc/zsmalloc-main.c
index 09caa4f..c8bfb77 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -267,7 +267,7 @@ static unsigned long obj_idx_to_offset(struct page *page,
        return off + obj_idx * class_size;
 }
 
-static void free_zspage(struct page *first_page)
+static void free_zspage(struct zs_pool *pool, struct page *first_page)
 {
        struct page *nextp, *tmp;
 
@@ -282,7 +282,7 @@ static void free_zspage(struct page *first_page)
        first_page->mapping = NULL;
        first_page->freelist = NULL;
        reset_page_mapcount(first_page);
-       __free_page(first_page);
+       (*pool->ops->free_page)(first_page);
 
        /* zspage with only 1 system page */
        if (!nextp)
@@ -345,7 +345,7 @@ static void init_zspage(struct page *first_page, struct 
size_class *class)
 /*
  * Allocate a zspage for the given size class
  */
-static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
+static struct page *alloc_zspage(struct zs_pool *pool, struct size_class 
*class)
 {
        int i, error;
        struct page *first_page = NULL;
@@ -365,7 +365,7 @@ static struct page *alloc_zspage(struct size_class *class, 
gfp_t flags)
        for (i = 0; i < class->zspage_order; i++) {
                struct page *page, *prev_page;
 
-               page = alloc_page(flags);
+               page = (*pool->ops->alloc_page)(pool->flags);
                if (!page)
                        goto cleanup;
 
@@ -398,7 +398,7 @@ static struct page *alloc_zspage(struct size_class *class, 
gfp_t flags)
 
 cleanup:
        if (unlikely(error) && first_page) {
-               free_zspage(first_page);
+               free_zspage(pool, first_page);
                first_page = NULL;
        }
 
@@ -482,7 +482,24 @@ fail:
        return notifier_to_errno(ret);
 }
 
-struct zs_pool *zs_create_pool(const char *name, gfp_t flags)
+
+static inline struct page *zs_alloc_page(gfp_t flags)
+{
+       return alloc_page(flags);
+}
+
+static inline void zs_free_page(struct page *page)
+{
+       __free_page(page);
+}
+
+static struct zs_pool_ops default_ops = {
+       .alloc_page = zs_alloc_page,
+       .free_page = zs_free_page
+};
+
+struct zs_pool *zs_create_pool(const char *name, gfp_t flags,
+                       struct zs_pool_ops *ops)
 {
        int i, error, ovhd_size;
        struct zs_pool *pool;
@@ -492,7 +509,7 @@ struct zs_pool *zs_create_pool(const char *name, gfp_t 
flags)
 
        ovhd_size = roundup(sizeof(*pool), PAGE_SIZE);
        pool = kzalloc(ovhd_size, GFP_KERNEL);
-       if (!pool)
+       if (!pool || (ops && (!ops->alloc_page || !ops->free_page)))
                return NULL;
 
        for (i = 0; i < ZS_SIZE_CLASSES; i++) {
@@ -524,6 +541,10 @@ struct zs_pool *zs_create_pool(const char *name, gfp_t 
flags)
 
        pool->flags = flags;
        pool->name = name;
+       if (ops)
+               pool->ops = ops;
+       else
+               pool->ops = &default_ops;
 
        error = 0; /* Success */
 
@@ -592,7 +613,7 @@ void *zs_malloc(struct zs_pool *pool, size_t size)
 
        if (!first_page) {
                spin_unlock(&class->lock);
-               first_page = alloc_zspage(class, pool->flags);
+               first_page = alloc_zspage(pool, class);
                if (unlikely(!first_page))
                        return NULL;
 
@@ -658,7 +679,7 @@ void zs_free(struct zs_pool *pool, void *obj)
        spin_unlock(&class->lock);
 
        if (fullness == ZS_EMPTY)
-               free_zspage(first_page);
+               free_zspage(pool, first_page);
 }
 EXPORT_SYMBOL_GPL(zs_free);
 
diff --git a/drivers/staging/zsmalloc/zsmalloc.h 
b/drivers/staging/zsmalloc/zsmalloc.h
index 949384e..51fb32e 100644
--- a/drivers/staging/zsmalloc/zsmalloc.h
+++ b/drivers/staging/zsmalloc/zsmalloc.h
@@ -17,7 +17,13 @@
 
 struct zs_pool;
 
-struct zs_pool *zs_create_pool(const char *name, gfp_t flags);
+struct zs_pool_ops {
+       struct page * (*alloc_page)(gfp_t);
+       void (*free_page)(struct page *);
+};
+
+struct zs_pool *zs_create_pool(const char *name, gfp_t flags,
+                       struct zs_pool_ops *ops);
 void zs_destroy_pool(struct zs_pool *pool);
 
 void *zs_malloc(struct zs_pool *pool, size_t size);
diff --git a/drivers/staging/zsmalloc/zsmalloc_int.h 
b/drivers/staging/zsmalloc/zsmalloc_int.h
index 92eefc6..ade09c1 100644
--- a/drivers/staging/zsmalloc/zsmalloc_int.h
+++ b/drivers/staging/zsmalloc/zsmalloc_int.h
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
+#include "zsmalloc.h"
 
 /*
  * This must be power of 2 and greater than of equal to sizeof(link_free).
@@ -146,6 +147,7 @@ struct link_free {
 };
 
 struct zs_pool {
+       struct zs_pool_ops *ops;
        struct size_class size_class[ZS_SIZE_CLASSES];
 
        gfp_t flags;    /* allocation flags used when growing pool */
-- 
1.7.5.4

_______________________________________________
devel mailing list
[email protected]
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel

Reply via email to