Add structures and skeleton code for a new system call called syslink()
[dragonfly.git] / sys / kern / kern_syslink.c
1 /*
2  * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
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  * $DragonFly: src/sys/kern/kern_syslink.c,v 1.1 2006/08/06 18:56:44 dillon Exp $
35  */
36 /*
37  * This module implements the syslink() system call and protocol which
38  * is used to glue clusters together as well as to interface userland
39  * devices and filesystems to the kernel.
40  */
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #include <sys/file.h>
47 #include <sys/proc.h>
48 #include <sys/lock.h>
49 #include <sys/uio.h>
50 #include <sys/thread.h>
51 #include <sys/sysctl.h>
52 #include <sys/sysproto.h>
53 #include <sys/syslink.h>
54 #include <sys/syslink_msg.h>
55
56 #include <sys/thread2.h>
57
58 /*
59  * fileops interface.  slbuf and sldata are also used in conjunction with a
60  * normal file descriptor.
61  */
62
63 struct slbuf {
64     char        *buf;
65     int         bufsize;        /* must be a power of 2 */
66     int         bufmask;        /* (bufsize - 1) */
67     int         rindex;         /* tail-chasing FIFO indices */
68     int         windex;
69 };
70
71 struct sldata {
72     struct slbuf rbuf;
73     struct slbuf wbuf;
74     struct file *xfp;           /* external file pointer */
75     struct lock rlock;          /* synchronizing lock */
76     struct lock wlock;          /* synchronizing lock */
77     struct thread *rthread;     /* xfp -> rbuf & process */
78     struct thread *wthread;     /* wbuf -> xfp */
79     int flags;
80     int refs;
81 };
82
83 #define SLF_RQUIT       0x0001
84 #define SLF_WQUIT       0x0002
85 #define SLF_RDONE       0x0004
86 #define SLF_WDONE       0x0008
87
88 #define SYSLINK_BUFSIZE (128*1024)
89
90 static int syslink_read (struct file *fp, struct uio *uio,
91                          struct ucred *cred, int flags);
92 static int syslink_write (struct file *fp, struct uio *uio,
93                          struct ucred *cred, int flags);
94 static int syslink_close (struct file *fp);
95 static int syslink_stat (struct file *fp, struct stat *sb, struct ucred *cred);
96 static int syslink_shutdown (struct file *fp, int how);
97 static int syslink_ioctl (struct file *fp, u_long cmd, caddr_t data,
98                          struct ucred *cred);
99 static int syslink_poll (struct file *fp, int events, struct ucred *cred);
100 static int syslink_kqfilter(struct file *fp, struct knote *kn);
101
102 static void syslink_rthread(void *arg);
103 static void syslink_wthread(void *arg);
104 static void slbuf_alloc(struct slbuf *buf, int bytes);
105 static void slbuf_free(struct slbuf *buf);
106 static void sldata_rels(struct sldata *sldata);
107 static int process_syslink_msg(struct sldata *sldata, struct syslink_msg *head);
108 static int syslink_validate(struct syslink_msg *head, int bytes);
109
110 static struct fileops syslinkops = {
111     .fo_read =          syslink_read,
112     .fo_write =         syslink_write,
113     .fo_ioctl =         syslink_ioctl,
114     .fo_poll =          syslink_poll,
115     .fo_kqfilter =      syslink_kqfilter,
116     .fo_stat =          syslink_stat,
117     .fo_close =         syslink_close,
118     .fo_shutdown =      syslink_shutdown
119 };
120
121 MALLOC_DEFINE(M_SYSLINK, "syslink", "syslink manager");
122
123 static int syslink_enabled;
124 SYSCTL_INT(_kern, OID_AUTO, syslink_enabled,
125             CTLFLAG_RW, &syslink_enabled, 0, "Enable SYSLINK");
126
127 /*
128  * Kernel mask and match bits.  These may be modified during early boot,
129  * before any syslink services have been established, but must remain fixed
130  * after that.  Note that the match value is only used if a message leaves
131  * the machine's domain.  '0' is used for unmasked match bits to indicate
132  * transport within the machine.
133  */
134 static sysid_t sl_mask  = 0x00000000FFFFFFFFLL;
135 static sysid_t sl_match = 0x0000000100000000LL;
136
137 /*
138  * Primary system call interface - associate a full-duplex stream
139  * (typically a pipe or a connected socket) with a sysid namespace,
140  * or create a direct link.
141  *
142  * syslink(int fd, int cmd, sysid_t *mask, sysid_t *match)
143  */
144
145 int
146 sys_syslink(struct syslink_args *uap)
147 {
148     int error;
149     struct file *fp;
150     struct sldata *sldata;
151
152     /*
153      * System call is under construction and disabled by default
154      */
155     if (syslink_enabled == 0)
156         return (EAUTH);
157
158     switch(uap->cmd) {
159     case SYSLINK_ESTABLISH:
160         error = suser(curthread);
161         if (error)
162             break;
163         sldata = malloc(sizeof(struct sldata), M_SYSLINK, M_WAITOK|M_ZERO);
164         lockinit(&sldata->rlock, "slread", 0, 0);
165         lockinit(&sldata->wlock, "slwrite", 0, 0);
166
167         if (uap->fd < 0) {
168             /*
169              * We create a direct syslink descriptor.  Only the reader thread
170              * is needed.
171              */
172             error = falloc(curproc, &fp, &uap->fd);
173             if (error == 0) {
174                 fp->f_type = DTYPE_SYSLINK;
175                 fp->f_flag = FREAD | FWRITE;
176                 fp->f_ops = &syslinkops;
177                 fp->f_data = sldata;
178                 slbuf_alloc(&sldata->rbuf, SYSLINK_BUFSIZE);
179                 slbuf_alloc(&sldata->wbuf, SYSLINK_BUFSIZE);
180                 sldata->refs = 2;
181                 sldata->flags = SLF_WQUIT | SLF_WDONE;
182                 lwkt_create(syslink_rthread, sldata,
183                             &sldata->rthread, NULL,
184                             0, -1, "syslink_r");
185             }
186         } else {
187             sldata->xfp = holdfp(curproc->p_fd, uap->fd, -1);
188             if (sldata->xfp != NULL) {
189                 slbuf_alloc(&sldata->rbuf, SYSLINK_BUFSIZE);
190                 slbuf_alloc(&sldata->wbuf, SYSLINK_BUFSIZE);
191                 sldata->refs = 2;
192                 lwkt_create(syslink_rthread, sldata,
193                             &sldata->rthread, NULL,
194                             0, -1, "syslink_r");
195                 lwkt_create(syslink_wthread, sldata,
196                             &sldata->wthread, NULL,
197                             0, -1, "syslink_w");
198             } else {
199                 error = EBADF;
200             }
201         }
202         if (error)
203                 free(sldata, M_SYSLINK);
204         break;
205     case SYSLINK_GETSYSMASK:
206         error = copyout(&sl_mask, uap->mask, sizeof(sl_mask));
207         if (error == 0)
208                 error = copyout(&sl_match, uap->match, sizeof(sl_match));
209         break;
210     default:
211         error = ENOTSUP;
212         break;
213     }
214     return(error);
215 }
216
217 /*
218  * This thread reads from an external descriptor into rbuf, then parses and
219  * dispatches syslink messages from rbuf.
220  */
221 static
222 void
223 syslink_rthread(void *arg)
224 {
225     struct sldata *sldata = arg;
226     struct slbuf *slbuf = &sldata->rbuf;
227     struct syslink_msg *head;
228     const int min_msg_size = offsetof(struct syslink_msg, src_sysid);
229
230     while ((sldata->flags & SLF_RQUIT) == 0) {
231         int count;
232         int used;
233         int error;
234
235         /*
236          * Calculate contiguous space available to read and read as much
237          * as possible.
238          *
239          * If the entire buffer is used there's probably a format error
240          * of some sort and we terminate the link.
241          */
242         used = slbuf->windex - slbuf->rindex;
243         error = 0;
244
245         /*
246          * Read some data, terminate the link if an error occurs or if EOF
247          * is encountered.  xfp can be NULL, indicating that the data was
248          * injected by other means.
249          */
250         if (sldata->xfp) {
251                 count = slbuf->bufsize - (slbuf->windex & slbuf->bufmask);
252                 if (count > slbuf->bufsize - used)
253                     count = slbuf->bufsize - used;
254                 if (count == 0)
255                     break;
256                 error = fp_read(sldata->xfp,
257                                 slbuf->buf + (slbuf->windex & slbuf->bufmask), count,
258                                 &count, 0);
259                 if (error)
260                     break;
261                 if (count == 0)
262                     break;
263                 slbuf->windex += count;
264                 used += count;
265         } else {
266                 tsleep(slbuf, 0, "fiford", 0);
267         }
268
269         /*
270          * Process as many syslink messages as we can.  The record length
271          * must be at least a minimal PAD record (8 bytes).  A msgid of 0
272          * is PAD.
273          */
274         while (slbuf->windex - slbuf->rindex >= min_msg_size) {
275             int aligned_reclen;
276
277             head = (void *)(slbuf->buf + (slbuf->rindex & slbuf->bufmask));
278             if (head->reclen < min_msg_size) {
279                 error = EINVAL;
280                 break;
281             }
282             aligned_reclen = SLMSG_ALIGN(head->reclen);
283
284             /*
285              * Disallow wraps
286              */
287             if ((slbuf->rindex & slbuf->bufmask) >
288                 ((slbuf->rindex + aligned_reclen) & slbuf->bufmask)
289             ) {
290                 error = EINVAL;
291                 break;
292             }
293
294             /*
295              * Insufficient data read
296              */
297             if (slbuf->windex - slbuf->rindex < aligned_reclen)
298                 break;
299
300             /*
301              * Process non-pad messages.  Non-pad messages have to be at
302              * least the size of the syslink_msg structure.
303              */
304             if (head->msgid) {
305                 if (head->reclen < sizeof(struct syslink_msg)) {
306                     error = EINVAL;
307                     break;
308                 }
309                 error = process_syslink_msg(sldata, head);
310                 if (error)
311                     break;
312             }
313             cpu_sfence();
314             slbuf->rindex += aligned_reclen;
315         }
316         if (error)
317             break;
318     }
319
320     /*
321      * Mark us as done and deref sldata.  Tell the writer to terminate as
322      * well.
323      */
324     sldata->flags |= SLF_RDONE;
325     if ((sldata->flags & SLF_WDONE) == 0) {
326             sldata->flags |= SLF_WQUIT;
327             wakeup(&sldata->wbuf);
328     }
329     sldata_rels(sldata);
330 }
331
332 /*
333  * This thread takes outgoing syslink messages queued to wbuf and writes them
334  * to the descriptor.  PAD is stripped.  PAD is also added as required to
335  * conform to the outgoing descriptor's buffering requirements.
336  */
337 static
338 void
339 syslink_wthread(void *arg)
340 {
341     struct sldata *sldata = arg;
342     struct slbuf *slbuf = &sldata->wbuf;
343     struct syslink_msg *head;
344     int error;
345
346     while ((sldata->flags & SLF_WQUIT) == 0) {
347         error = 0;
348         for (;;) {
349             int aligned_reclen;
350             int used;
351             int count;
352
353             used = slbuf->windex - slbuf->rindex;
354             if (used < offsetof(struct syslink_msg, src_sysid))
355                 break;
356
357             head = (void *)(slbuf->buf + (slbuf->rindex & slbuf->bufmask));
358             if (head->reclen < offsetof(struct syslink_msg, src_sysid)) {
359                 error = EINVAL;
360                 break;
361             }
362             aligned_reclen = SLMSG_ALIGN(head->reclen);
363
364             /*
365              * Disallow wraps
366              */
367             if ((slbuf->rindex & slbuf->bufmask) >
368                 ((slbuf->rindex + aligned_reclen) & slbuf->bufmask)
369             ) {
370                 error = EINVAL;
371                 break;
372             }
373
374             /*
375              * Insufficient data read
376              */
377             if (used < aligned_reclen)
378                 break;
379
380             /*
381              * Write it out whether it is PAD or not.   XXX re-PAD for output
382              * here.
383              */
384             error = fp_write(sldata->xfp, head, aligned_reclen, &count);
385             if (error)
386                 break;
387             if (count != aligned_reclen) {
388                 error = EIO;
389                 break;
390             }
391             slbuf->rindex += aligned_reclen;
392         }
393         if (error)
394             break;
395         tsleep(slbuf, 0, "fifowt", 0);
396     }
397     sldata->flags |= SLF_WDONE;
398     sldata_rels(sldata);
399 }
400
401 static
402 void
403 slbuf_alloc(struct slbuf *slbuf, int bytes)
404 {
405     bzero(slbuf, sizeof(*slbuf));
406     slbuf->buf = malloc(bytes, M_SYSLINK, M_WAITOK);
407     slbuf->bufsize = bytes;
408     slbuf->bufmask = bytes - 1;
409 }
410
411 static
412 void
413 slbuf_free(struct slbuf *slbuf)
414 {
415     free(slbuf->buf, M_SYSLINK);
416     slbuf->buf = NULL;
417 }
418
419 static
420 void
421 sldata_rels(struct sldata *sldata)
422 {
423     if (--sldata->refs == 0) {
424         slbuf_free(&sldata->rbuf);
425         slbuf_free(&sldata->wbuf);
426         free(sldata, M_SYSLINK);
427     }
428 }
429
430 /*
431  * fileops for an established syslink when the kernel is asked to create a
432  * descriptor (verses one being handed to it).  No threads are created in
433  * this case.
434  */
435
436 /*
437  * Transfer zero or more messages from the kernel to userland.  Only complete
438  * messages are returned.  If the uio has insufficient space then EMSGSIZE
439  * is returned.  The kernel feeds messages to wbuf so we use wlock (structures
440  * are relative to the kernel).
441  */
442 static
443 int
444 syslink_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags)
445 {
446     struct sldata *sldata = fp->f_data;
447     struct slbuf *slbuf = &sldata->wbuf;
448     struct syslink_msg *head;
449     int bytes;
450     int contig;
451     int error;
452     int nbio;
453
454     if (flags & O_FBLOCKING)
455         nbio = 0;
456     else if (flags & O_FNONBLOCKING)
457         nbio = 1;
458     else if (fp->f_flag & O_NONBLOCK)
459         nbio = 1;
460     else
461         nbio = 0;
462
463     lockmgr(&sldata->wlock, LK_EXCLUSIVE | LK_RETRY);
464
465     /*
466      * Calculate the number of bytes we can transfer in one shot.  Transfers
467      * do not wrap the FIFO.
468      */
469     contig = slbuf->bufsize - (slbuf->rindex & slbuf->bufmask);
470     for (;;) {
471         bytes = slbuf->windex - slbuf->rindex;
472         if (bytes)
473             break;
474         if (nbio) {
475             error = EAGAIN;
476             goto done;
477         }
478         tsleep(slbuf, 0, "fiford", 0);
479     }
480     if (bytes > contig)
481         bytes = contig;
482
483     /*
484      * The uio must be able to accomodate the transfer.
485      */
486     if (uio->uio_resid < bytes) {
487         error = ENOSPC;
488         goto done;
489     }
490
491     /*
492      * Copy the data to userland and update rindex.
493      */
494     head = (void *)(slbuf->buf + (slbuf->rindex & slbuf->bufmask));
495     error = uiomove((caddr_t)head, bytes, uio);
496     if (error == 0)
497         slbuf->rindex += bytes;
498
499     /*
500      * Cleanup
501      */
502 done:
503     lockmgr(&sldata->wlock, LK_RELEASE);
504     return (error);
505 }
506
507 /*
508  * Transfer zero or more messages from userland to the kernel.  Only complete
509  * messages may be written.  The kernel processes from rbuf so that is where
510  * we have to copy the messages.
511  */
512 static
513 int
514 syslink_write (struct file *fp, struct uio *uio, struct ucred *cred, int flags)
515 {
516     struct sldata *sldata = fp->f_data;
517     struct slbuf *slbuf = &sldata->rbuf;
518     struct syslink_msg *head;
519     int bytes;
520     int contig;
521     int nbio;
522     int error;
523
524     if (flags & O_FBLOCKING)
525         nbio = 0;
526     else if (flags & O_FNONBLOCKING)
527         nbio = 1;
528     else if (fp->f_flag & O_NONBLOCK)
529         nbio = 1;
530     else
531         nbio = 0;
532
533     lockmgr(&sldata->rlock, LK_EXCLUSIVE | LK_RETRY);
534
535     /* 
536      * Calculate the maximum number of contiguous bytes that may be available.
537      * Caller is required to not wrap our FIFO.
538      */
539     contig = slbuf->bufsize - (slbuf->windex & slbuf->bufmask);
540     if (uio->uio_resid > contig) {
541         error = ENOSPC;
542         goto done;
543     }
544
545     /*
546      * Truncate based on actual unused space available in the FIFO.  If
547      * the uio does not fit, block and loop.
548      */
549     for (;;) {
550         bytes = slbuf->bufsize - (slbuf->windex - slbuf->rindex);
551         if (bytes > contig)
552             bytes = contig;
553         if (uio->uio_resid <= bytes)
554             break;
555         if (nbio) {
556             error = EAGAIN;
557             goto done;
558         }
559         tsleep(slbuf, 0, "fifowr", 0);
560     }
561     bytes = uio->uio_resid;
562     head = (void *)(slbuf->buf + (slbuf->windex & slbuf->bufmask));
563     error = uiomove((caddr_t)head, bytes, uio);
564     if (error == 0)
565         error = syslink_validate(head, bytes);
566     if (error == 0)
567         slbuf->windex += bytes;
568 done:
569     lockmgr(&sldata->rlock, LK_RELEASE);
570     return(error);
571 }
572
573 static
574 int
575 syslink_close (struct file *fp)
576 {
577     struct sldata *sldata;
578
579     sldata = fp->f_data;
580     fp->f_data = NULL;
581     sldata_rels(sldata);
582     return(0);
583 }
584
585 static
586 int
587 syslink_stat (struct file *fp, struct stat *sb, struct ucred *cred)
588 {
589     return(EINVAL);
590 }
591
592 static
593 int
594 syslink_shutdown (struct file *fp, int how)
595 {
596     return(EINVAL);
597 }
598
599 static
600 int
601 syslink_ioctl (struct file *fp, u_long cmd, caddr_t data, struct ucred *cred)
602 {
603     return(EINVAL);
604 }
605
606 static
607 int
608 syslink_poll (struct file *fp, int events, struct ucred *cred)
609 {
610     return(0);
611 }
612
613 static
614 int
615 syslink_kqfilter(struct file *fp, struct knote *kn)
616 {
617     return(0);
618 }
619
620 /*
621  * Process a syslink message
622  */
623 static
624 int
625 process_syslink_msg(struct sldata *sldata, struct syslink_msg *head)
626 {
627     printf("process syslink msg %08x %04x\n", head->msgid, head->cid);
628     return(0);
629 }
630
631 /*
632  * Validate that the syslink message header(s) are correctly sized.
633  */
634 static
635 int
636 syslink_validate(struct syslink_msg *head, int bytes)
637 {
638     const int min_msg_size = offsetof(struct syslink_msg, src_sysid);
639     int aligned_reclen;
640
641     while (bytes) {
642         /*
643          * Message size and alignment
644          */
645         if (bytes < min_msg_size)
646             return (EINVAL);
647         if (bytes & SL_ALIGNMASK)
648             return (EINVAL);
649         if (head->msgid && bytes < sizeof(struct syslink_msg))
650             return (EINVAL);
651
652         /*
653          * Buffer must contain entire record
654          */
655         aligned_reclen = SLMSG_ALIGN(head->reclen);
656         if (bytes < aligned_reclen)
657             return (EINVAL);
658         bytes -= aligned_reclen;
659         head = (void *)((char *)head + aligned_reclen);
660     }
661     return(0);
662 }
663