Merge Linus' tree to be be to apply submitted patches to newer code than
[cascardo/linux.git] / mm / zbud.c
index bf42404..ec71b37 100644 (file)
--- a/mm/zbud.c
+++ b/mm/zbud.c
@@ -51,6 +51,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/zbud.h>
+#include <linux/zpool.h>
 
 /*****************
  * Structures
  * NCHUNKS_ORDER determines the internal allocation granularity, effectively
  * adjusting internal fragmentation.  It also determines the number of
  * freelists maintained in each pool. NCHUNKS_ORDER of 6 means that the
- * allocation granularity will be in chunks of size PAGE_SIZE/64, and there
- * will be 64 freelists per pool.
+ * allocation granularity will be in chunks of size PAGE_SIZE/64. As one chunk
+ * in allocated page is occupied by zbud header, NCHUNKS will be calculated to
+ * 63 which shows the max number of free chunks in zbud page, also there will be
+ * 63 freelists per pool.
  */
 #define NCHUNKS_ORDER  6
 
 #define CHUNK_SHIFT    (PAGE_SHIFT - NCHUNKS_ORDER)
 #define CHUNK_SIZE     (1 << CHUNK_SHIFT)
-#define NCHUNKS                (PAGE_SIZE >> CHUNK_SHIFT)
 #define ZHDR_SIZE_ALIGNED CHUNK_SIZE
+#define NCHUNKS                ((PAGE_SIZE - ZHDR_SIZE_ALIGNED) >> CHUNK_SHIFT)
 
 /**
  * struct zbud_pool - stores metadata for each zbud pool
@@ -112,6 +115,91 @@ struct zbud_header {
        bool under_reclaim;
 };
 
+/*****************
+ * zpool
+ ****************/
+
+#ifdef CONFIG_ZPOOL
+
+static int zbud_zpool_evict(struct zbud_pool *pool, unsigned long handle)
+{
+       return zpool_evict(pool, handle);
+}
+
+static struct zbud_ops zbud_zpool_ops = {
+       .evict =        zbud_zpool_evict
+};
+
+static void *zbud_zpool_create(gfp_t gfp, struct zpool_ops *zpool_ops)
+{
+       return zbud_create_pool(gfp, &zbud_zpool_ops);
+}
+
+static void zbud_zpool_destroy(void *pool)
+{
+       zbud_destroy_pool(pool);
+}
+
+static int zbud_zpool_malloc(void *pool, size_t size, gfp_t gfp,
+                       unsigned long *handle)
+{
+       return zbud_alloc(pool, size, gfp, handle);
+}
+static void zbud_zpool_free(void *pool, unsigned long handle)
+{
+       zbud_free(pool, handle);
+}
+
+static int zbud_zpool_shrink(void *pool, unsigned int pages,
+                       unsigned int *reclaimed)
+{
+       unsigned int total = 0;
+       int ret = -EINVAL;
+
+       while (total < pages) {
+               ret = zbud_reclaim_page(pool, 8);
+               if (ret < 0)
+                       break;
+               total++;
+       }
+
+       if (reclaimed)
+               *reclaimed = total;
+
+       return ret;
+}
+
+static void *zbud_zpool_map(void *pool, unsigned long handle,
+                       enum zpool_mapmode mm)
+{
+       return zbud_map(pool, handle);
+}
+static void zbud_zpool_unmap(void *pool, unsigned long handle)
+{
+       zbud_unmap(pool, handle);
+}
+
+static u64 zbud_zpool_total_size(void *pool)
+{
+       return zbud_get_pool_size(pool) * PAGE_SIZE;
+}
+
+static struct zpool_driver zbud_zpool_driver = {
+       .type =         "zbud",
+       .owner =        THIS_MODULE,
+       .create =       zbud_zpool_create,
+       .destroy =      zbud_zpool_destroy,
+       .malloc =       zbud_zpool_malloc,
+       .free =         zbud_zpool_free,
+       .shrink =       zbud_zpool_shrink,
+       .map =          zbud_zpool_map,
+       .unmap =        zbud_zpool_unmap,
+       .total_size =   zbud_zpool_total_size,
+};
+
+MODULE_ALIAS("zpool-zbud");
+#endif /* CONFIG_ZPOOL */
+
 /*****************
  * Helpers
 *****************/
@@ -122,7 +210,7 @@ enum buddy {
 };
 
 /* Converts an allocation size in bytes to size in zbud chunks */
-static int size_to_chunks(int size)
+static int size_to_chunks(size_t size)
 {
        return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT;
 }
@@ -182,10 +270,9 @@ static int num_free_chunks(struct zbud_header *zhdr)
 {
        /*
         * Rather than branch for different situations, just use the fact that
-        * free buddies have a length of zero to simplify everything. -1 at the
-        * end for the zbud header.
+        * free buddies have a length of zero to simplify everything.
         */
-       return NCHUNKS - zhdr->first_chunks - zhdr->last_chunks - 1;
+       return NCHUNKS - zhdr->first_chunks - zhdr->last_chunks;
 }
 
 /*****************
@@ -247,7 +334,7 @@ void zbud_destroy_pool(struct zbud_pool *pool)
  * gfp arguments are invalid or -ENOMEM if the pool was unable to allocate
  * a new page.
  */
-int zbud_alloc(struct zbud_pool *pool, unsigned int size, gfp_t gfp,
+int zbud_alloc(struct zbud_pool *pool, size_t size, gfp_t gfp,
                        unsigned long *handle)
 {
        int chunks, i, freechunks;
@@ -511,11 +598,20 @@ static int __init init_zbud(void)
        /* Make sure the zbud header will fit in one chunk */
        BUILD_BUG_ON(sizeof(struct zbud_header) > ZHDR_SIZE_ALIGNED);
        pr_info("loaded\n");
+
+#ifdef CONFIG_ZPOOL
+       zpool_register_driver(&zbud_zpool_driver);
+#endif
+
        return 0;
 }
 
 static void __exit exit_zbud(void)
 {
+#ifdef CONFIG_ZPOOL
+       zpool_unregister_driver(&zbud_zpool_driver);
+#endif
+
        pr_info("unloaded\n");
 }