]> git.karo-electronics.de Git - karo-tx-linux.git/blob - mm/zpool.c
mm/zpool: implement common zpool api to zbud/zsmalloc
[karo-tx-linux.git] / mm / zpool.c
1 /*
2  * zpool memory storage api
3  *
4  * Copyright (C) 2014 Dan Streetman
5  *
6  * This is a common frontend for memory storage pool implementations.
7  * Typically, this is used to store compressed memory.
8  */
9
10 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
12 #include <linux/list.h>
13 #include <linux/types.h>
14 #include <linux/mm.h>
15 #include <linux/slab.h>
16 #include <linux/spinlock.h>
17 #include <linux/module.h>
18 #include <linux/zpool.h>
19
20 struct zpool {
21         char *type;
22
23         struct zpool_driver *driver;
24         void *pool;
25         struct zpool_ops *ops;
26
27         struct list_head list;
28 };
29
30 static LIST_HEAD(drivers_head);
31 static DEFINE_SPINLOCK(drivers_lock);
32
33 static LIST_HEAD(pools_head);
34 static DEFINE_SPINLOCK(pools_lock);
35
36 void zpool_register_driver(struct zpool_driver *driver)
37 {
38         spin_lock(&drivers_lock);
39         list_add(&driver->list, &drivers_head);
40         spin_unlock(&drivers_lock);
41 }
42 EXPORT_SYMBOL(zpool_register_driver);
43
44 void zpool_unregister_driver(struct zpool_driver *driver)
45 {
46         spin_lock(&drivers_lock);
47         list_del(&driver->list);
48         spin_unlock(&drivers_lock);
49 }
50 EXPORT_SYMBOL(zpool_unregister_driver);
51
52 int zpool_evict(void *pool, unsigned long handle)
53 {
54         struct zpool *zpool;
55
56         spin_lock(&pools_lock);
57         list_for_each_entry(zpool, &pools_head, list) {
58                 if (zpool->pool == pool) {
59                         spin_unlock(&pools_lock);
60                         if (!zpool->ops || !zpool->ops->evict)
61                                 return -EINVAL;
62                         return zpool->ops->evict(zpool, handle);
63                 }
64         }
65         spin_unlock(&pools_lock);
66
67         return -ENOENT;
68 }
69 EXPORT_SYMBOL(zpool_evict);
70
71 static struct zpool_driver *zpool_get_driver(char *type)
72 {
73         struct zpool_driver *driver;
74
75         assert_spin_locked(&drivers_lock);
76         list_for_each_entry(driver, &drivers_head, list) {
77                 if (!strcmp(driver->type, type))
78                         return driver;
79         }
80
81         return NULL;
82 }
83
84 struct zpool *zpool_create_pool(char *type, gfp_t flags,
85                         struct zpool_ops *ops)
86 {
87         struct zpool_driver *driver;
88         struct zpool *zpool;
89
90         pr_info("creating pool type %s\n", type);
91
92         spin_lock(&drivers_lock);
93         driver = zpool_get_driver(type);
94         spin_unlock(&drivers_lock);
95
96         if (!driver) {
97                 request_module(type);
98                 spin_lock(&drivers_lock);
99                 driver = zpool_get_driver(type);
100                 spin_unlock(&drivers_lock);
101         }
102
103         if (!driver) {
104                 pr_err("no driver for type %s\n", type);
105                 return NULL;
106         }
107
108         zpool = kmalloc(sizeof(*zpool), GFP_KERNEL);
109         if (!zpool) {
110                 pr_err("couldn't create zpool - out of memory\n");
111                 return NULL;
112         }
113
114         zpool->type = driver->type;
115         zpool->driver = driver;
116         zpool->pool = driver->create(flags, ops);
117         zpool->ops = ops;
118
119         if (!zpool->pool) {
120                 pr_err("couldn't create %s pool\n", type);
121                 kfree(zpool);
122                 return NULL;
123         }
124
125         pr_info("created %s pool\n", type);
126
127         spin_lock(&pools_lock);
128         list_add(&zpool->list, &pools_head);
129         spin_unlock(&pools_lock);
130
131         return zpool;
132 }
133
134 void zpool_destroy_pool(struct zpool *zpool)
135 {
136         pr_info("destroying pool type %s\n", zpool->type);
137
138         spin_lock(&pools_lock);
139         list_del(&zpool->list);
140         spin_unlock(&pools_lock);
141         zpool->driver->destroy(zpool->pool);
142         kfree(zpool);
143 }
144
145 char *zpool_get_type(struct zpool *zpool)
146 {
147         return zpool->type;
148 }
149
150 int zpool_malloc(struct zpool *zpool, size_t size, unsigned long *handle)
151 {
152         return zpool->driver->malloc(zpool->pool, size, handle);
153 }
154
155 void zpool_free(struct zpool *zpool, unsigned long handle)
156 {
157         zpool->driver->free(zpool->pool, handle);
158 }
159
160 int zpool_shrink(struct zpool *zpool, unsigned int pages,
161                         unsigned int *reclaimed)
162 {
163         return zpool->driver->shrink(zpool->pool, pages, reclaimed);
164 }
165
166 void *zpool_map_handle(struct zpool *zpool, unsigned long handle,
167                         enum zpool_mapmode mapmode)
168 {
169         return zpool->driver->map(zpool->pool, handle, mapmode);
170 }
171
172 void zpool_unmap_handle(struct zpool *zpool, unsigned long handle)
173 {
174         zpool->driver->unmap(zpool->pool, handle);
175 }
176
177 u64 zpool_get_total_size(struct zpool *zpool)
178 {
179         return zpool->driver->total_size(zpool->pool);
180 }
181
182 static int __init init_zpool(void)
183 {
184         pr_info("loaded\n");
185         return 0;
186 }
187
188 static void __exit exit_zpool(void)
189 {
190         pr_info("unloaded\n");
191 }
192
193 module_init(init_zpool);
194 module_exit(exit_zpool);
195
196 MODULE_LICENSE("GPL");
197 MODULE_AUTHOR("Dan Streetman <ddstreet@ieee.org>");
198 MODULE_DESCRIPTION("Common API for compressed memory storage");