hammer2 - dmsg blockdev work
[dragonfly.git] / sys / dev / disk / xdisk / xdisk.c
1 /*
2  * Copyright (c) 2012 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@dragonflybsd.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 /*
35  * This module allows disk devices to be created and associated with a
36  * communications pipe or socket.  You open the device and issue an
37  * ioctl() to install a new disk along with its communications descriptor.
38  *
39  * All further communication occurs via the descriptor using the DMSG
40  * LNK_CONN, LNK_SPAN, and BLOCK protocols.  The descriptor can be a
41  * direct connection to a remote machine's disk (in-kernenl), to a remote
42  * cluster controller, to the local cluster controller, etc.
43  *
44  * /dev/xdisk is the control device, issue ioctl()s to create the /dev/xa%d
45  * devices.  These devices look like raw disks to the system.
46  */
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/buf.h>
50 #include <sys/conf.h>
51 #include <sys/device.h>
52 #include <sys/devicestat.h>
53 #include <sys/disk.h>
54 #include <sys/kernel.h>
55 #include <sys/malloc.h>
56 #include <sys/sysctl.h>
57 #include <sys/proc.h>
58 #include <sys/queue.h>
59 #include <sys/udev.h>
60 #include <sys/uuid.h>
61 #include <sys/kern_syscall.h>
62
63 #include <sys/dmsg.h>
64 #include <sys/xdiskioctl.h>
65
66 #include <sys/buf2.h>
67 #include <sys/thread2.h>
68
69 static int xdisk_attach(struct xdisk_attach_ioctl *xaioc);
70 static void xa_exit(kdmsg_iocom_t *iocom);
71 static int xa_msg_conn_reply(kdmsg_state_t *state, kdmsg_msg_t *msg);
72 static int xa_msg_span_reply(kdmsg_state_t *state, kdmsg_msg_t *msg);
73 static int xa_lnk_rcvmsg(kdmsg_msg_t *msg);
74 static int xa_lnk_dbgmsg(kdmsg_msg_t *msg);
75 static int xa_adhoc_input(kdmsg_msg_t *msg);
76
77 MALLOC_DEFINE(M_XDISK, "Networked disk client", "Network Disks");
78
79 /*
80  * Control device, issue ioctls to create xa devices.
81  */
82 static d_open_t xdisk_open;
83 static d_close_t xdisk_close;
84 static d_ioctl_t xdisk_ioctl;
85
86 static struct dev_ops xdisk_ops = {
87         { "xdisk", 0, D_MPSAFE },
88         .d_open =       xdisk_open,
89         .d_close =      xdisk_close,
90         .d_ioctl =      xdisk_ioctl
91 };
92
93 /*
94  * XA disk devices
95  */
96 static d_open_t xa_open;
97 static d_close_t xa_close;
98 static d_ioctl_t xa_ioctl;
99 static d_strategy_t xa_strategy;
100 static d_psize_t xa_size;
101
102 static struct dev_ops xa_ops = {
103         { "xa", 0, D_DISK | D_CANFREE | D_MPSAFE },
104         .d_open =       xa_open,
105         .d_close =      xa_close,
106         .d_ioctl =      xa_ioctl,
107         .d_read =       physread,
108         .d_write =      physwrite,
109         .d_strategy =   xa_strategy,
110         .d_psize =      xa_size
111 };
112
113 struct xa_softc {
114         TAILQ_ENTRY(xa_softc) entry;
115         cdev_t          dev;
116         kdmsg_iocom_t   iocom;
117         struct xdisk_attach_ioctl xaioc;
118         struct disk_info info;
119         struct disk     disk;
120         uuid_t          pfs_fsid;
121         int             unit;
122         int             inprog;
123         int             connected;
124 };
125
126 static struct lwkt_token xdisk_token = LWKT_TOKEN_INITIALIZER(xdisk_token);
127 static int xdisk_opencount;
128 static cdev_t xdisk_dev;
129 static TAILQ_HEAD(, xa_softc) xa_queue;
130
131 /*
132  * Module initialization
133  */
134 static int
135 xdisk_modevent(module_t mod, int type, void *data)
136 {
137         switch (type) {
138         case MOD_LOAD:
139                 TAILQ_INIT(&xa_queue);
140                 xdisk_dev = make_dev(&xdisk_ops, 0,
141                                      UID_ROOT, GID_WHEEL, 0600, "xdisk");
142                 break;
143         case MOD_UNLOAD:
144         case MOD_SHUTDOWN:
145                 if (xdisk_opencount || TAILQ_FIRST(&xa_queue))
146                         return (EBUSY);
147                 if (xdisk_dev) {
148                         destroy_dev(xdisk_dev);
149                         xdisk_dev = NULL;
150                 }
151                 dev_ops_remove_all(&xdisk_ops);
152                 dev_ops_remove_all(&xa_ops);
153                 break;
154         default:
155                 break;
156         }
157         return 0;
158 }
159
160 DEV_MODULE(xdisk, xdisk_modevent, 0);
161
162 /*
163  * Control device
164  */
165 static int
166 xdisk_open(struct dev_open_args *ap)
167 {
168         lwkt_gettoken(&xdisk_token);
169         ++xdisk_opencount;
170         lwkt_reltoken(&xdisk_token);
171         return(0);
172 }
173
174 static int
175 xdisk_close(struct dev_close_args *ap)
176 {
177         lwkt_gettoken(&xdisk_token);
178         --xdisk_opencount;
179         lwkt_reltoken(&xdisk_token);
180         return(0);
181 }
182
183 static int
184 xdisk_ioctl(struct dev_ioctl_args *ap)
185 {
186         int error;
187
188         switch(ap->a_cmd) {
189         case XDISKIOCATTACH:
190                 error = xdisk_attach((void *)ap->a_data);
191                 break;
192         default:
193                 error = ENOTTY;
194                 break;
195         }
196         return error;
197 }
198
199 /************************************************************************
200  *                              DMSG INTERFACE                          *
201  ************************************************************************/
202
203 static int
204 xdisk_attach(struct xdisk_attach_ioctl *xaioc)
205 {
206         struct xa_softc *scan;
207         struct xa_softc *xa;
208         struct file *fp;
209         kdmsg_msg_t *msg;
210         int unit;
211         char devname[64];
212         cdev_t dev;
213
214         fp = holdfp(curproc->p_fd, xaioc->fd, -1);
215         if (fp == NULL)
216                 return EINVAL;
217
218         xa = kmalloc(sizeof(*xa), M_XDISK, M_WAITOK|M_ZERO);
219
220         /*
221          * Find unit
222          */
223         lwkt_gettoken(&xdisk_token);
224         unit = 0;
225         do {
226                 TAILQ_FOREACH(scan, &xa_queue, entry) {
227                         if (scan->unit == unit)
228                                 break;
229                 }
230         } while (scan != NULL);
231         xa->unit = unit;
232         xa->xaioc = *xaioc;
233         TAILQ_INSERT_TAIL(&xa_queue, xa, entry);
234         lwkt_reltoken(&xdisk_token);
235
236         /*
237          * Create device
238          */
239         dev = disk_create(unit, &xa->disk, &xa_ops);
240         dev->si_drv1 = xa;
241         xa->dev = dev;
242
243         xa->info.d_media_blksize = 512;
244         xa->info.d_media_blocks = xaioc->size / 512;
245         xa->info.d_dsflags = DSO_MBRQUIET | DSO_RAWPSIZE;
246         xa->info.d_secpertrack = 32;
247         xa->info.d_nheads = 64;
248         xa->info.d_secpercyl = xa->info.d_secpertrack * xa->info.d_nheads;
249         xa->info.d_ncylinders = 0;
250         disk_setdiskinfo_sync(&xa->disk, &xa->info);
251
252         /*
253          * Set up messaging connection
254          */
255         ksnprintf(devname, sizeof(devname), "xa%d", unit);
256         kdmsg_iocom_init(&xa->iocom, xa, M_XDISK,
257                          xa_lnk_rcvmsg,
258                          xa_lnk_dbgmsg,
259                          xa_adhoc_input);
260         xa->iocom.exit_func = xa_exit;
261         xa->inprog = 1;
262         kern_uuidgen(&xa->pfs_fsid, 1);
263         kdmsg_iocom_reconnect(&xa->iocom, fp, devname);
264
265         /*
266          * Issue DMSG_LNK_CONN for device.  This sets up filters so hopefully
267          * the only SPANs we receive are from servers providing the label
268          * being configured.  Hopefully that's just a single server(!)(!).
269          * (HAMMER peers might have multiple servers but block device peers
270          * currently only allow one).  There could still be multiple spans
271          * due to there being multiple paths available, however.
272          */
273
274         msg = kdmsg_msg_alloc(&xa->iocom.router, DMSG_LNK_CONN | DMSGF_CREATE,
275                               xa_msg_conn_reply, xa);
276         msg->any.lnk_conn.pfs_type = 0;
277         msg->any.lnk_conn.proto_version = DMSG_SPAN_PROTO_1;
278         msg->any.lnk_conn.peer_type = DMSG_PEER_BLOCK;
279         msg->any.lnk_conn.peer_mask = 1LLU << DMSG_PEER_BLOCK;
280         ksnprintf(msg->any.lnk_conn.cl_label,
281                   sizeof(msg->any.lnk_conn.cl_label),
282                   "%s", xaioc->cl_label);
283         msg->any.lnk_conn.pfs_fsid = xa->pfs_fsid;
284         xa->iocom.conn_state = msg->state;
285         kdmsg_msg_write(msg);
286
287         xa->inprog = 0;         /* unstall msg thread exit (if racing) */
288
289         return(0);
290 }
291
292 /*
293  * Handle reply to our LNK_CONN transaction (transaction remains open)
294  */
295 static
296 int
297 xa_msg_conn_reply(kdmsg_state_t *state, kdmsg_msg_t *msg)
298 {
299         struct xa_softc *xa = state->any.any;
300         kdmsg_msg_t *rmsg;
301
302         if (msg->any.head.cmd & DMSGF_CREATE) {
303                 kprintf("XA LNK_CONN received reply\n");
304                 rmsg = kdmsg_msg_alloc(&xa->iocom.router,
305                                        DMSG_LNK_SPAN | DMSGF_CREATE,
306                                        xa_msg_span_reply, xa);
307                 rmsg->any.lnk_span.pfs_type = 0;
308                 rmsg->any.lnk_span.proto_version = DMSG_SPAN_PROTO_1;
309                 rmsg->any.lnk_span.peer_type = DMSG_PEER_BLOCK;
310
311                 ksnprintf(rmsg->any.lnk_span.cl_label,
312                           sizeof(rmsg->any.lnk_span.cl_label),
313                           "%s", xa->xaioc.cl_label);
314                 kdmsg_msg_write(rmsg);
315         }
316         if ((state->txcmd & DMSGF_DELETE) == 0 &&
317             (msg->any.head.cmd & DMSGF_DELETE)) {
318                 kprintf("DISK LNK_CONN terminated by remote\n");
319                 xa->iocom.conn_state = NULL;
320                 kdmsg_msg_reply(msg, 0);
321         }
322         return(0);
323 }
324
325 static int
326 xa_msg_span_reply(kdmsg_state_t *state, kdmsg_msg_t *msg)
327 {
328         kprintf("SPAN REPLY - Our sent span was terminated by the "
329                 "remote %08x state %p\n", msg->any.head.cmd, state);
330         if ((state->txcmd & DMSGF_DELETE) == 0 &&
331             (msg->any.head.cmd & DMSGF_DELETE)) {
332                 kdmsg_msg_reply(msg, 0);
333         }
334         return (0);
335 }
336
337 /*
338  * Called from iocom core transmit thread upon disconnect.
339  */
340 static
341 void
342 xa_exit(kdmsg_iocom_t *iocom)
343 {
344         struct xa_softc *xa = iocom->handle;
345
346         kprintf("XA_EXIT UNIT %d\n", xa->unit);
347
348         kdmsg_iocom_uninit(iocom);
349
350         while (xa->inprog) {
351                 tsleep(xa, 0, "xarace", hz);
352         }
353
354         /*
355          * XXX allow reconnection, wait for users to terminate?
356          */
357
358         disk_destroy(&xa->disk);
359
360         lwkt_gettoken(&xdisk_token);
361         TAILQ_REMOVE(&xa_queue, xa, entry);
362         lwkt_reltoken(&xdisk_token);
363
364         kfree(xa, M_XDISK);
365 }
366
367 static int
368 xa_lnk_rcvmsg(kdmsg_msg_t *msg)
369 {
370         switch(msg->any.head.cmd & DMSGF_TRANSMASK) {
371         case DMSG_LNK_CONN | DMSGF_CREATE:
372                 /*
373                  * reply & leave trans open
374                  */
375                 kprintf("XA CONN RECEIVE - (just ignore it)\n");
376                 kdmsg_msg_result(msg, 0);
377                 break;
378         case DMSG_LNK_SPAN | DMSGF_CREATE:
379                 kprintf("XA SPAN RECEIVE - ADDED FROM CLUSTER\n");
380                 break;
381         case DMSG_LNK_SPAN | DMSGF_DELETE:
382                 kprintf("SPAN RECEIVE - DELETED FROM CLUSTER\n");
383                 break;
384         default:
385                 break;
386         }
387         return(0);
388 }
389
390 static int
391 xa_lnk_dbgmsg(kdmsg_msg_t *msg)
392 {
393         switch(msg->any.head.cmd & DMSGF_CMDSWMASK) {
394         case DMSG_DBG_SHELL:
395                 /*
396                  * Execute shell command (not supported atm)
397                  */
398                 kdmsg_msg_reply(msg, DMSG_ERR_NOSUPP);
399                 break;
400         case DMSG_DBG_SHELL | DMSGF_REPLY:
401                 if (msg->aux_data) {
402                         msg->aux_data[msg->aux_size - 1] = 0;
403                         kprintf("DEBUGMSG: %s\n", msg->aux_data);
404                 }
405                 break;
406         default:
407                 kdmsg_msg_reply(msg, DMSG_ERR_NOSUPP);
408                 break;
409         }
410         return(0);
411 }
412
413 static int
414 xa_adhoc_input(kdmsg_msg_t *msg)
415 {
416         kprintf("XA ADHOC INPUT MSG %08x\n", msg->any.head.cmd);
417         return(0);
418 }
419
420 /************************************************************************
421  *                         XA DEVICE INTERFACE                          *
422  ************************************************************************/
423
424 static int
425 xa_open(struct dev_open_args *ap)
426 {
427         cdev_t dev = ap->a_head.a_dev;
428         struct xa_softc *xa;
429
430         xa = dev->si_drv1;
431
432         dev->si_bsize_phys = 512;
433         dev->si_bsize_best = 32768;
434
435         /*
436          * Issue streaming open and wait for reply.
437          */
438
439         /* XXX check ap->a_oflags & FWRITE, EACCES if read-only */
440
441         return(0);
442 }
443
444 static int
445 xa_close(struct dev_close_args *ap)
446 {
447         cdev_t dev = ap->a_head.a_dev;
448 }
449
450 static int
451 xa_strategy(struct dev_strategy_args *ap)
452 {
453 }
454
455 static int
456 xa_ioctl(struct dev_ioctl_args *ap)
457 {
458         return (ENOTTY);
459 }
460
461 static int
462 xa_size(struct dev_psize_args *ap)
463 {
464         struct xa_softc *xa;
465
466         if ((xa = ap->a_head.a_dev->si_drv1) == NULL)
467                 return (ENXIO);
468         if (xa->inprog)
469                 return (ENXIO);
470         ap->a_result = xa->info.d_media_blocks;
471         return (0);
472 }