xseg_segdev driver: do not destroy old segment when allocating a new one
[archipelago] / xseg / drivers / kernel / xseg_segdev.c
1 /*
2  * Copyright 2012 GRNET S.A. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above
9  *      copyright notice, this list of conditions and the following
10  *      disclaimer.
11  *   2. Redistributions in binary form must reproduce the above
12  *      copyright notice, this list of conditions and the following
13  *      disclaimer in the documentation and/or other materials
14  *      provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * The views and conclusions contained in the software and
30  * documentation are those of the authors and should not be
31  * interpreted as representing official policies, either expressed
32  * or implied, of GRNET S.A.
33  */
34
35 /* xseg_segdev.c
36  *
37  */
38
39 #include <linux/module.h>
40 #include <linux/moduleparam.h>
41 #include <linux/init.h>
42 #include <linux/sched.h>
43 #include <linux/kernel.h>
44 #include <linux/slab.h>
45 #include <linux/fs.h>
46 #include <linux/errno.h>
47 #include <linux/timer.h>
48 #include <linux/types.h>
49 #include <linux/vmalloc.h>
50 #include <linux/genhd.h>
51 #include <linux/blkdev.h>
52 #include <linux/bio.h>
53 #include <linux/device.h>
54 #include <linux/completion.h>
55
56 #include <xseg/xseg.h>
57 #include <sys/kernel/segdev.h>
58 #include <sys/util.h>
59 #include <drivers/xseg_segdev.h>
60 #include <peers/kernel/xsegbd.h>
61 MODULE_DESCRIPTION("xseg_segdev");
62 MODULE_AUTHOR("XSEG");
63 MODULE_LICENSE("BSD");
64
65 /* FIXME */
66 static struct xseg *xsegments[65536];
67 static unsigned int nr_xsegments = 1;
68
69 struct segpriv {
70         unsigned int segno;
71 };
72
73 static void *segdev_malloc(uint64_t size)
74 {
75         return kmalloc((size_t)size, GFP_KERNEL);
76 }
77
78 static void *segdev_realloc(void *mem, uint64_t size)
79 {
80         return krealloc(mem, (size_t)size, GFP_KERNEL);
81 }
82
83 static void segdev_mfree(void *ptr)
84 {
85         return kfree(ptr);
86 }
87
88 static long segdev_allocate(const char *name, uint64_t size)
89 {
90         int r;
91         struct segdev *segdev = segdev_get(0);
92
93         r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
94         if (r) {
95                 XSEGLOG("cannot acquire segdev");
96                 goto out;
97         }
98
99         /*
100         if (segdev->segment) {
101                 XSEGLOG("destroying existing segdev segment");
102                 r = segdev_destroy_segment(segdev);
103                 if (r)
104                         goto out;
105         }
106         */
107
108         XSEGLOG("creating segdev segment size %llu", size);
109         r = segdev_create_segment(segdev, size, 1);
110         if (r)
111                 goto out;
112
113         segdev_put(segdev);
114         r = 0;
115 out:
116         return r;
117 }
118
119 static long segdev_deallocate(const char *name)
120 {
121         struct segdev *segdev = segdev_get(0);
122         int r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
123         if (r)
124                 return r;
125
126         clear_bit(SEGDEV_RESERVED, &segdev->flags);
127         XSEGLOG("destroying segment");
128         r = segdev_destroy_segment(segdev);
129         if (r)
130                 XSEGLOG("   ...failed");
131         segdev_put(segdev);
132         return r;
133 }
134
135 static void *segdev_map(const char *name, uint64_t size, struct xseg *seg)
136 {
137         struct xseg *xseg = NULL;
138         /* map() holds a reference to the segment */
139         struct segdev *dev = segdev_get(0);
140         struct segpriv *priv;
141         int r;
142         r = IS_ERR(dev) ? PTR_ERR(dev) : 0;
143         if (r)
144                 goto out;
145
146         if (!dev->segment)
147                 goto out;
148
149         if (size > dev->segsize)
150                 goto out;
151
152         priv = dev->priv;
153         if (priv->segno >= nr_xsegments)
154                 goto out;
155
156 //      if (seg)
157 //              xsegments[priv->segno] = seg;
158
159         xseg = (void *)dev->segment;
160 out:
161         return xseg;
162 }
163
164 static void segdev_unmap(void *ptr, uint64_t size)
165 {
166         struct segdev *segdev = segdev_get(0);
167         struct segpriv *priv;
168         int r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
169         if (r)
170                 return;
171
172         priv = segdev->priv;
173         if (priv->segno >= nr_xsegments)
174                 goto out;
175
176 //      xsegments[priv->segno] = NULL;
177
178 out:
179         /* unmap() releases the reference taken by map() */
180         segdev_put(segdev);
181
182         segdev_put(segdev);
183 }
184
185 static void segdev_callback(struct segdev *dev, xport portno)
186 {
187         struct xseg *xseg;
188         struct segpriv *priv = dev->priv;
189         struct xseg_private *xpriv;
190         struct xseg_port *port;
191         struct segdev_signal_desc *ssd;
192
193         xseg = xsegments[portno];
194         if (!xseg)
195                 return;
196         if (priv->segno >= nr_xsegments)
197                 return;
198
199         xpriv = xseg->priv;
200         port = xseg_get_port(xseg, portno);
201         if (!port)
202                 return;
203         ssd = xseg_get_signal_desc(xseg, port);
204         if (!ssd || !ssd->waitcue){
205                 return;
206         }
207
208         if (xpriv->wakeup) {
209                 xpriv->wakeup(portno);
210         }
211         return;
212 }
213
214 static struct xseg_type xseg_segdev = {
215         /* xseg operations */
216         {
217                 .allocate = segdev_allocate,
218                 .deallocate = segdev_deallocate,
219                 .map = segdev_map,
220                 .unmap = segdev_unmap
221         },
222         /* name */
223         "segdev"
224 };
225
226 static int segdev_remote_signal_init(void)
227 {
228         return 0;
229 }
230
231 static void segdev_remote_signal_quit(void)
232 {
233         return;
234 }
235
236 static int segdev_local_signal_init(struct xseg *xseg, xport portno)
237 {
238         //assert xsegments[portno] == NULL;
239         xsegments[portno] = xseg;
240         return 0;
241 }
242
243 static void segdev_local_signal_quit(struct xseg *xseg, xport portno)
244 {
245         //assert xsegments[portno] == xseg;
246         xsegments[portno] = NULL;
247         return;
248 }
249
250 static int segdev_prepare_wait(struct xseg *xseg, uint32_t portno)
251 {
252         struct segdev_signal_desc *ssd; 
253         struct xseg_port *port = xseg_get_port(xseg, portno);
254         if (!port)
255                 return -1;
256         ssd = xseg_get_signal_desc(xseg, port);
257         if (!ssd)
258                 return -1;
259         /* true/false value */
260         ssd->waitcue = 1;
261         return 0;
262 }
263
264 static int segdev_cancel_wait(struct xseg *xseg, uint32_t portno)
265 {
266         struct segdev_signal_desc *ssd; 
267         struct xseg_port *port = xseg_get_port(xseg, portno);
268         if (!port)
269                 return -1;
270         ssd = xseg_get_signal_desc(xseg, port);
271         if (!ssd)
272                 return -1;
273         /* true/false value */
274         ssd->waitcue = 0;
275         return -0;
276 }
277
278 static int segdev_wait_signal(struct xseg *xseg, uint32_t timeout)
279 {
280         return -1;
281 }
282
283 static int segdev_signal(struct xseg *xseg, uint32_t portno)
284 {
285         return -1;
286 }
287
288 static int segdev_init_signal_desc(struct xseg *xseg, void *sd)
289 {
290         struct segdev_signal_desc *ssd = sd;
291         if (!ssd)
292                 return -1;
293         ssd->waitcue = 0;
294         return 0;
295 }
296
297 static void segdev_quit_signal_desc(struct xseg *xseg, void *sd)
298 {
299         return;
300 }
301
302 static void *segdev_alloc_data(struct xseg *xseg)
303 {
304         struct xobject_h *sd_h = xseg_get_objh(xseg, MAGIC_SEGDEV_SD,
305                                 sizeof(struct segdev_signal_desc));
306         return sd_h;
307 }
308
309 static void segdev_free_data(struct xseg *xseg, void *data)
310 {
311         if (data)
312                 xseg_put_objh(xseg, (struct xobject_h *)data);
313 }
314
315 static void *segdev_alloc_signal_desc(struct xseg *xseg, void *data)
316 {
317         struct segdev_signal_desc *ssd;
318         struct xobject_h *sd_h = (struct xobject_h *) data;
319         if (!sd_h)
320                 return NULL;
321         ssd = xobj_get_obj(sd_h, X_ALLOC);
322         if (!ssd)
323                 return NULL;
324         ssd->waitcue = 0;
325         return ssd;
326 }
327
328 static void segdev_free_signal_desc(struct xseg *xseg, void *data, void *sd)
329 {
330         struct xobject_h *sd_h = (struct xobject_h *) data;
331         if (!sd_h)
332                 return;
333         if (sd)
334                 xobj_put_obj(sd_h, sd);
335         return;
336 }
337
338 static struct xseg_peer xseg_peer_segdev = {
339         /* xseg signal operations */
340         {
341                 .init_signal_desc   = segdev_init_signal_desc,
342                 .quit_signal_desc   = segdev_quit_signal_desc,
343                 .alloc_data         = segdev_alloc_data,
344                 .free_data          = segdev_free_data,
345                 .alloc_signal_desc  = segdev_alloc_signal_desc,
346                 .free_signal_desc   = segdev_free_signal_desc,
347                 .local_signal_init  = segdev_local_signal_init,
348                 .local_signal_quit  = segdev_local_signal_quit,
349                 .remote_signal_init = segdev_remote_signal_init,
350                 .remote_signal_quit = segdev_remote_signal_quit,
351                 .cancel_wait = segdev_cancel_wait,
352                 .prepare_wait = segdev_prepare_wait,
353                 .wait_signal = segdev_wait_signal,
354                 .signal = segdev_signal,
355                 .malloc = segdev_malloc,
356                 .realloc = segdev_realloc,
357                 .mfree = segdev_mfree
358         },
359         /* name */
360         "segdev"
361 };
362
363
364 /* ************************* */
365 /* ** XSEG Initialization ** */
366 /* ************************* */
367
368 static int segdev_init(void)
369 {
370         struct segdev *segdev;
371         struct segpriv *segpriv;
372         int r;
373
374         XSEGLOG("registering xseg types");
375         r = xseg_register_type(&xseg_segdev);
376         if (r)
377                 goto err0;
378
379         r = xseg_register_peer(&xseg_peer_segdev);
380         if (r)
381                 goto err1;
382         
383         segdev = segdev_get(0);
384         r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
385         if (r)
386                 goto err2;
387
388         r = -ENOMEM;
389         segpriv = kmalloc(sizeof(struct segpriv), GFP_KERNEL);
390         if (!segpriv)
391                 goto err3;
392
393         segpriv->segno = 0;
394         segdev->callback = segdev_callback;
395         segdev->priv = segpriv;
396
397         return 0;
398
399 err3:
400         segdev_put(segdev);
401 err2:
402         xseg_unregister_peer(xseg_peer_segdev.name);
403 err1:
404         xseg_unregister_type(xseg_segdev.name);
405 err0:
406         return r;
407 }
408
409 static int segdev_quit(void)
410 {
411         struct segdev *segdev = segdev_get(0);
412         int r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
413         if (!r){
414                 /* make sure to unmap the segment first */
415                 clear_bit(SEGDEV_RESERVED, &segdev->flags);
416                 segdev->callback = NULL;
417                 //FIXME what aboud segdev->priv?
418                 segdev_put(segdev);
419         }
420         xseg_unregister_peer(xseg_peer_segdev.name);
421         xseg_unregister_type(xseg_segdev.name);
422
423         return 0;
424 }
425
426 /* *************************** */
427 /* ** Module Initialization ** */
428 /* *************************** */
429
430 static int __init xseg_segdev_init(void)
431 {
432         int ret = -ENOSYS;
433
434         ret = segdev_init();
435         if (ret)
436                 goto out;
437
438         XSEGLOG("initialization complete");
439 out:
440         return ret;
441 }
442
443 static void __exit xseg_segdev_exit(void)
444 {
445         segdev_quit();
446 }
447
448 module_init(xseg_segdev_init);
449 module_exit(xseg_segdev_exit);
450