Merge from vendor branch FILE:
[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.3 2006/09/05 00:55:45 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 = kmalloc(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                 fsetfd(curproc, fp, uap->fd);
186                 fdrop(fp);
187                 uap->sysmsg_result = uap->fd;
188             }
189         } else {
190             sldata->xfp = holdfp(curproc->p_fd, uap->fd, -1);
191             if (sldata->xfp != NULL) {
192                 slbuf_alloc(&sldata->rbuf, SYSLINK_BUFSIZE);
193                 slbuf_alloc(&sldata->wbuf, SYSLINK_BUFSIZE);
194                 sldata->refs = 2;
195                 lwkt_create(syslink_rthread, sldata,
196                             &sldata->rthread, NULL,
197                             0, -1, "syslink_r");
198                 lwkt_create(syslink_wthread, sldata,
199                             &sldata->wthread, NULL,
200                             0, -1, "syslink_w");
201             } else {
202                 error = EBADF;
203             }
204         }
205         if (error)
206                 kfree(sldata, M_SYSLINK);
207         break;
208     case SYSLINK_GETSYSMASK:
209         error = copyout(&sl_mask, uap->mask, sizeof(sl_mask));
210         if (error == 0)
211                 error = copyout(&sl_match, uap->match, sizeof(sl_match));
212         break;
213     default:
214         error = ENOTSUP;
215         break;
216     }
217     return(error);
218 }
219
220 /*
221  * This thread reads from an external descriptor into rbuf, then parses and
222  * dispatches syslink messages from rbuf.
223  */
224 static
225 void
226 syslink_rthread(void *arg)
227 {
228     struct sldata *sldata = arg;
229     struct slbuf *slbuf = &sldata->rbuf;
230     struct syslink_msg *head;
231     const int min_msg_size = offsetof(struct syslink_msg, src_sysid);
232
233     while ((sldata->flags & SLF_RQUIT) == 0) {
234         int count;
235         int used;
236         int error;
237
238         /*
239          * Calculate contiguous space available to read and read as much
240          * as possible.
241          *
242          * If the entire buffer is used there's probably a format error
243          * of some sort and we terminate the link.
244          */
245         used = slbuf->windex - slbuf->rindex;
246         error = 0;
247
248         /*
249          * Read some data, terminate the link if an error occurs or if EOF
250          * is encountered.  xfp can be NULL, indicating that the data was
251          * injected by other means.
252          */
253         if (sldata->xfp) {
254                 count = slbuf->bufsize - (slbuf->windex & slbuf->bufmask);
255                 if (count > slbuf->bufsize - used)
256                     count = slbuf->bufsize - used;
257                 if (count == 0)
258                     break;
259                 error = fp_read(sldata->xfp,
260                                 slbuf->buf + (slbuf->windex & slbuf->bufmask), count,
261                                 &count, 0);
262                 if (error)
263                     break;
264                 if (count == 0)
265                     break;
266                 slbuf->windex += count;
267                 used += count;
268         } else {
269                 tsleep(slbuf, 0, "fiford", 0);
270         }
271
272         /*
273          * Process as many syslink messages as we can.  The record length
274          * must be at least a minimal PAD record (8 bytes).  A msgid of 0
275          * is PAD.
276          */
277         while (slbuf->windex - slbuf->rindex >= min_msg_size) {
278             int aligned_reclen;
279
280             head = (void *)(slbuf->buf + (slbuf->rindex & slbuf->bufmask));
281             if (head->reclen < min_msg_size) {
282                 error = EINVAL;
283                 break;
284             }
285             aligned_reclen = SLMSG_ALIGN(head->reclen);
286
287             /*
288              * Disallow wraps
289              */
290             if ((slbuf->rindex & slbuf->bufmask) >
291                 ((slbuf->rindex + aligned_reclen) & slbuf->bufmask)
292             ) {
293                 error = EINVAL;
294                 break;
295             }
296
297             /*
298              * Insufficient data read
299              */
300             if (slbuf->windex - slbuf->rindex < aligned_reclen)
301                 break;
302
303             /*
304              * Process non-pad messages.  Non-pad messages have to be at
305              * least the size of the syslink_msg structure.
306              */
307             if (head->msgid) {
308                 if (head->reclen < sizeof(struct syslink_msg)) {
309                     error = EINVAL;
310                     break;
311                 }
312                 error = process_syslink_msg(sldata, head);
313                 if (error)
314                     break;
315             }
316             cpu_sfence();
317             slbuf->rindex += aligned_reclen;
318         }
319         if (error)
320             break;
321     }
322
323     /*
324      * Mark us as done and deref sldata.  Tell the writer to terminate as
325      * well.
326      */
327     sldata->flags |= SLF_RDONE;
328     if ((sldata->flags & SLF_WDONE) == 0) {
329             sldata->flags |= SLF_WQUIT;
330             wakeup(&sldata->wbuf);
331     }
332     wakeup(&sldata->rbuf);
333     wakeup(&sldata->wbuf);
334     sldata_rels(sldata);
335 }
336
337 /*
338  * This thread takes outgoing syslink messages queued to wbuf and writes them
339  * to the descriptor.  PAD is stripped.  PAD is also added as required to
340  * conform to the outgoing descriptor's buffering requirements.
341  */
342 static
343 void
344 syslink_wthread(void *arg)
345 {
346     struct sldata *sldata = arg;
347     struct slbuf *slbuf = &sldata->wbuf;
348     struct syslink_msg *head;
349     int error;
350
351     while ((sldata->flags & SLF_WQUIT) == 0) {
352         error = 0;
353         for (;;) {
354             int aligned_reclen;
355             int used;
356             int count;
357
358             used = slbuf->windex - slbuf->rindex;
359             if (used < offsetof(struct syslink_msg, src_sysid))
360                 break;
361
362             head = (void *)(slbuf->buf + (slbuf->rindex & slbuf->bufmask));
363             if (head->reclen < offsetof(struct syslink_msg, src_sysid)) {
364                 error = EINVAL;
365                 break;
366             }
367             aligned_reclen = SLMSG_ALIGN(head->reclen);
368
369             /*
370              * Disallow wraps
371              */
372             if ((slbuf->rindex & slbuf->bufmask) >
373                 ((slbuf->rindex + aligned_reclen) & slbuf->bufmask)
374             ) {
375                 error = EINVAL;
376                 break;
377             }
378
379             /*
380              * Insufficient data read
381              */
382             if (used < aligned_reclen)
383                 break;
384
385             /*
386              * Write it out whether it is PAD or not.   XXX re-PAD for output
387              * here.
388              */
389             error = fp_write(sldata->xfp, head, aligned_reclen, &count);
390             if (error)
391                 break;
392             if (count != aligned_reclen) {
393                 error = EIO;
394                 break;
395             }
396             slbuf->rindex += aligned_reclen;
397         }
398         if (error)
399             break;
400         tsleep(slbuf, 0, "fifowt", 0);
401     }
402     sldata->flags |= SLF_WDONE;
403     sldata_rels(sldata);
404 }
405
406 static
407 void
408 slbuf_alloc(struct slbuf *slbuf, int bytes)
409 {
410     bzero(slbuf, sizeof(*slbuf));
411     slbuf->buf = kmalloc(bytes, M_SYSLINK, M_WAITOK);
412     slbuf->bufsize = bytes;
413     slbuf->bufmask = bytes - 1;
414 }
415
416 static
417 void
418 slbuf_free(struct slbuf *slbuf)
419 {
420     kfree(slbuf->buf, M_SYSLINK);
421     slbuf->buf = NULL;
422 }
423
424 static
425 void
426 sldata_rels(struct sldata *sldata)
427 {
428     if (--sldata->refs == 0) {
429         slbuf_free(&sldata->rbuf);
430         slbuf_free(&sldata->wbuf);
431         kfree(sldata, M_SYSLINK);
432     }
433 }
434
435 /*
436  * fileops for an established syslink when the kernel is asked to create a
437  * descriptor (verses one being handed to it).  No threads are created in
438  * this case.
439  */
440
441 /*
442  * Transfer zero or more messages from the kernel to userland.  Only complete
443  * messages are returned.  If the uio has insufficient space then EMSGSIZE
444  * is returned.  The kernel feeds messages to wbuf so we use wlock (structures
445  * are relative to the kernel).
446  */
447 static
448 int
449 syslink_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags)
450 {
451     struct sldata *sldata = fp->f_data;
452     struct slbuf *slbuf = &sldata->wbuf;
453     struct syslink_msg *head;
454     int bytes;
455     int contig;
456     int error;
457     int nbio;
458
459     if (flags & O_FBLOCKING)
460         nbio = 0;
461     else if (flags & O_FNONBLOCKING)
462         nbio = 1;
463     else if (fp->f_flag & O_NONBLOCK)
464         nbio = 1;
465     else
466         nbio = 0;
467
468     lockmgr(&sldata->wlock, LK_EXCLUSIVE | LK_RETRY);
469
470     /*
471      * Calculate the number of bytes we can transfer in one shot.  Transfers
472      * do not wrap the FIFO.
473      */
474     contig = slbuf->bufsize - (slbuf->rindex & slbuf->bufmask);
475     for (;;) {
476         bytes = slbuf->windex - slbuf->rindex;
477         if (bytes)
478             break;
479         if (sldata->flags & SLF_RDONE) {
480             error = EIO;
481             break;
482         }
483         if (nbio) {
484             error = EAGAIN;
485             goto done;
486         }
487         tsleep(slbuf, 0, "fiford", 0);
488     }
489     if (bytes > contig)
490         bytes = contig;
491
492     /*
493      * The uio must be able to accomodate the transfer.
494      */
495     if (uio->uio_resid < bytes) {
496         error = ENOSPC;
497         goto done;
498     }
499
500     /*
501      * Copy the data to userland and update rindex.
502      */
503     head = (void *)(slbuf->buf + (slbuf->rindex & slbuf->bufmask));
504     error = uiomove((caddr_t)head, bytes, uio);
505     if (error == 0)
506         slbuf->rindex += bytes;
507
508     /*
509      * Cleanup
510      */
511 done:
512     lockmgr(&sldata->wlock, LK_RELEASE);
513     return (error);
514 }
515
516 /*
517  * Transfer zero or more messages from userland to the kernel.  Only complete
518  * messages may be written.  The kernel processes from rbuf so that is where
519  * we have to copy the messages.
520  */
521 static
522 int
523 syslink_write (struct file *fp, struct uio *uio, struct ucred *cred, int flags)
524 {
525     struct sldata *sldata = fp->f_data;
526     struct slbuf *slbuf = &sldata->rbuf;
527     struct syslink_msg *head;
528     int bytes;
529     int contig;
530     int nbio;
531     int error;
532
533     if (flags & O_FBLOCKING)
534         nbio = 0;
535     else if (flags & O_FNONBLOCKING)
536         nbio = 1;
537     else if (fp->f_flag & O_NONBLOCK)
538         nbio = 1;
539     else
540         nbio = 0;
541
542     lockmgr(&sldata->rlock, LK_EXCLUSIVE | LK_RETRY);
543
544     /* 
545      * Calculate the maximum number of contiguous bytes that may be available.
546      * Caller is required to not wrap our FIFO.
547      */
548     contig = slbuf->bufsize - (slbuf->windex & slbuf->bufmask);
549     if (uio->uio_resid > contig) {
550         error = ENOSPC;
551         goto done;
552     }
553
554     /*
555      * Truncate based on actual unused space available in the FIFO.  If
556      * the uio does not fit, block and loop.
557      */
558     for (;;) {
559         bytes = slbuf->bufsize - (slbuf->windex - slbuf->rindex);
560         if (bytes > contig)
561             bytes = contig;
562         if (uio->uio_resid <= bytes)
563             break;
564         if (sldata->flags & SLF_RDONE) {
565             error = EIO;
566             goto done;
567         }
568         if (nbio) {
569             error = EAGAIN;
570             goto done;
571         }
572         tsleep(slbuf, 0, "fifowr", 0);
573     }
574     bytes = uio->uio_resid;
575     head = (void *)(slbuf->buf + (slbuf->windex & slbuf->bufmask));
576     error = uiomove((caddr_t)head, bytes, uio);
577     if (error == 0)
578         error = syslink_validate(head, bytes);
579     if (error == 0) {
580         slbuf->windex += bytes;
581         wakeup(slbuf);
582     }
583 done:
584     lockmgr(&sldata->rlock, LK_RELEASE);
585     return(error);
586 }
587
588 static
589 int
590 syslink_close (struct file *fp)
591 {
592     struct sldata *sldata;
593
594     sldata = fp->f_data;
595     if ((sldata->flags & SLF_RQUIT) == 0) {
596         sldata->flags |= SLF_RQUIT;
597         wakeup(&sldata->rbuf);
598     }
599     if ((sldata->flags & SLF_WQUIT) == 0) {
600         sldata->flags |= SLF_WQUIT;
601         wakeup(&sldata->wbuf);
602     }
603     fp->f_data = NULL;
604     sldata_rels(sldata);
605     return(0);
606 }
607
608 static
609 int
610 syslink_stat (struct file *fp, struct stat *sb, struct ucred *cred)
611 {
612     return(EINVAL);
613 }
614
615 static
616 int
617 syslink_shutdown (struct file *fp, int how)
618 {
619     return(EINVAL);
620 }
621
622 static
623 int
624 syslink_ioctl (struct file *fp, u_long cmd, caddr_t data, struct ucred *cred)
625 {
626     return(EINVAL);
627 }
628
629 static
630 int
631 syslink_poll (struct file *fp, int events, struct ucred *cred)
632 {
633     return(0);
634 }
635
636 static
637 int
638 syslink_kqfilter(struct file *fp, struct knote *kn)
639 {
640     return(0);
641 }
642
643 /*
644  * Process a syslink message
645  */
646 static
647 int
648 process_syslink_msg(struct sldata *sldata, struct syslink_msg *head)
649 {
650     printf("process syslink msg %08x %04x\n", head->msgid, head->cid);
651     return(0);
652 }
653
654 /*
655  * Validate that the syslink message header(s) are correctly sized.
656  */
657 static
658 int
659 syslink_validate(struct syslink_msg *head, int bytes)
660 {
661     const int min_msg_size = offsetof(struct syslink_msg, src_sysid);
662     int aligned_reclen;
663
664     while (bytes) {
665         /*
666          * Message size and alignment
667          */
668         if (bytes < min_msg_size)
669             return (EINVAL);
670         if (bytes & SL_ALIGNMASK)
671             return (EINVAL);
672         if (head->msgid && bytes < sizeof(struct syslink_msg))
673             return (EINVAL);
674
675         /*
676          * Buffer must contain entire record
677          */
678         aligned_reclen = SLMSG_ALIGN(head->reclen);
679         if (bytes < aligned_reclen)
680             return (EINVAL);
681         bytes -= aligned_reclen;
682         head = (void *)((char *)head + aligned_reclen);
683     }
684     return(0);
685 }
686