Merge from vendor branch GCC:
[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.5 2007/01/12 06:06:57 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),
261                                 count, &count, 0, UIO_SYSSPACE);
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                              UIO_SYSSPACE);
391             if (error)
392                 break;
393             if (count != aligned_reclen) {
394                 error = EIO;
395                 break;
396             }
397             slbuf->rindex += aligned_reclen;
398         }
399         if (error)
400             break;
401         tsleep(slbuf, 0, "fifowt", 0);
402     }
403     sldata->flags |= SLF_WDONE;
404     sldata_rels(sldata);
405 }
406
407 static
408 void
409 slbuf_alloc(struct slbuf *slbuf, int bytes)
410 {
411     bzero(slbuf, sizeof(*slbuf));
412     slbuf->buf = kmalloc(bytes, M_SYSLINK, M_WAITOK);
413     slbuf->bufsize = bytes;
414     slbuf->bufmask = bytes - 1;
415 }
416
417 static
418 void
419 slbuf_free(struct slbuf *slbuf)
420 {
421     kfree(slbuf->buf, M_SYSLINK);
422     slbuf->buf = NULL;
423 }
424
425 static
426 void
427 sldata_rels(struct sldata *sldata)
428 {
429     if (--sldata->refs == 0) {
430         slbuf_free(&sldata->rbuf);
431         slbuf_free(&sldata->wbuf);
432         kfree(sldata, M_SYSLINK);
433     }
434 }
435
436 /*
437  * fileops for an established syslink when the kernel is asked to create a
438  * descriptor (verses one being handed to it).  No threads are created in
439  * this case.
440  */
441
442 /*
443  * Transfer zero or more messages from the kernel to userland.  Only complete
444  * messages are returned.  If the uio has insufficient space then EMSGSIZE
445  * is returned.  The kernel feeds messages to wbuf so we use wlock (structures
446  * are relative to the kernel).
447  */
448 static
449 int
450 syslink_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags)
451 {
452     struct sldata *sldata = fp->f_data;
453     struct slbuf *slbuf = &sldata->wbuf;
454     struct syslink_msg *head;
455     int bytes;
456     int contig;
457     int error;
458     int nbio;
459
460     if (flags & O_FBLOCKING)
461         nbio = 0;
462     else if (flags & O_FNONBLOCKING)
463         nbio = 1;
464     else if (fp->f_flag & O_NONBLOCK)
465         nbio = 1;
466     else
467         nbio = 0;
468
469     lockmgr(&sldata->wlock, LK_EXCLUSIVE | LK_RETRY);
470
471     /*
472      * Calculate the number of bytes we can transfer in one shot.  Transfers
473      * do not wrap the FIFO.
474      */
475     contig = slbuf->bufsize - (slbuf->rindex & slbuf->bufmask);
476     for (;;) {
477         bytes = slbuf->windex - slbuf->rindex;
478         if (bytes)
479             break;
480         if (sldata->flags & SLF_RDONE) {
481             error = EIO;
482             break;
483         }
484         if (nbio) {
485             error = EAGAIN;
486             goto done;
487         }
488         tsleep(slbuf, 0, "fiford", 0);
489     }
490     if (bytes > contig)
491         bytes = contig;
492
493     /*
494      * The uio must be able to accomodate the transfer.
495      */
496     if (uio->uio_resid < bytes) {
497         error = ENOSPC;
498         goto done;
499     }
500
501     /*
502      * Copy the data to userland and update rindex.
503      */
504     head = (void *)(slbuf->buf + (slbuf->rindex & slbuf->bufmask));
505     error = uiomove((caddr_t)head, bytes, uio);
506     if (error == 0)
507         slbuf->rindex += bytes;
508
509     /*
510      * Cleanup
511      */
512 done:
513     lockmgr(&sldata->wlock, LK_RELEASE);
514     return (error);
515 }
516
517 /*
518  * Transfer zero or more messages from userland to the kernel.  Only complete
519  * messages may be written.  The kernel processes from rbuf so that is where
520  * we have to copy the messages.
521  */
522 static
523 int
524 syslink_write (struct file *fp, struct uio *uio, struct ucred *cred, int flags)
525 {
526     struct sldata *sldata = fp->f_data;
527     struct slbuf *slbuf = &sldata->rbuf;
528     struct syslink_msg *head;
529     int bytes;
530     int contig;
531     int nbio;
532     int error;
533
534     if (flags & O_FBLOCKING)
535         nbio = 0;
536     else if (flags & O_FNONBLOCKING)
537         nbio = 1;
538     else if (fp->f_flag & O_NONBLOCK)
539         nbio = 1;
540     else
541         nbio = 0;
542
543     lockmgr(&sldata->rlock, LK_EXCLUSIVE | LK_RETRY);
544
545     /* 
546      * Calculate the maximum number of contiguous bytes that may be available.
547      * Caller is required to not wrap our FIFO.
548      */
549     contig = slbuf->bufsize - (slbuf->windex & slbuf->bufmask);
550     if (uio->uio_resid > contig) {
551         error = ENOSPC;
552         goto done;
553     }
554
555     /*
556      * Truncate based on actual unused space available in the FIFO.  If
557      * the uio does not fit, block and loop.
558      */
559     for (;;) {
560         bytes = slbuf->bufsize - (slbuf->windex - slbuf->rindex);
561         if (bytes > contig)
562             bytes = contig;
563         if (uio->uio_resid <= bytes)
564             break;
565         if (sldata->flags & SLF_RDONE) {
566             error = EIO;
567             goto done;
568         }
569         if (nbio) {
570             error = EAGAIN;
571             goto done;
572         }
573         tsleep(slbuf, 0, "fifowr", 0);
574     }
575     bytes = uio->uio_resid;
576     head = (void *)(slbuf->buf + (slbuf->windex & slbuf->bufmask));
577     error = uiomove((caddr_t)head, bytes, uio);
578     if (error == 0)
579         error = syslink_validate(head, bytes);
580     if (error == 0) {
581         slbuf->windex += bytes;
582         wakeup(slbuf);
583     }
584 done:
585     lockmgr(&sldata->rlock, LK_RELEASE);
586     return(error);
587 }
588
589 static
590 int
591 syslink_close (struct file *fp)
592 {
593     struct sldata *sldata;
594
595     sldata = fp->f_data;
596     if ((sldata->flags & SLF_RQUIT) == 0) {
597         sldata->flags |= SLF_RQUIT;
598         wakeup(&sldata->rbuf);
599     }
600     if ((sldata->flags & SLF_WQUIT) == 0) {
601         sldata->flags |= SLF_WQUIT;
602         wakeup(&sldata->wbuf);
603     }
604     fp->f_data = NULL;
605     sldata_rels(sldata);
606     return(0);
607 }
608
609 static
610 int
611 syslink_stat (struct file *fp, struct stat *sb, struct ucred *cred)
612 {
613     return(EINVAL);
614 }
615
616 static
617 int
618 syslink_shutdown (struct file *fp, int how)
619 {
620     return(EINVAL);
621 }
622
623 static
624 int
625 syslink_ioctl (struct file *fp, u_long cmd, caddr_t data, struct ucred *cred)
626 {
627     return(EINVAL);
628 }
629
630 static
631 int
632 syslink_poll (struct file *fp, int events, struct ucred *cred)
633 {
634     return(0);
635 }
636
637 static
638 int
639 syslink_kqfilter(struct file *fp, struct knote *kn)
640 {
641     return(0);
642 }
643
644 /*
645  * Process a syslink message
646  */
647 static
648 int
649 process_syslink_msg(struct sldata *sldata, struct syslink_msg *head)
650 {
651     kprintf("process syslink msg %08x %04x\n", head->msgid, head->cid);
652     return(0);
653 }
654
655 /*
656  * Validate that the syslink message header(s) are correctly sized.
657  */
658 static
659 int
660 syslink_validate(struct syslink_msg *head, int bytes)
661 {
662     const int min_msg_size = offsetof(struct syslink_msg, src_sysid);
663     int aligned_reclen;
664
665     while (bytes) {
666         /*
667          * Message size and alignment
668          */
669         if (bytes < min_msg_size)
670             return (EINVAL);
671         if (bytes & SL_ALIGNMASK)
672             return (EINVAL);
673         if (head->msgid && bytes < sizeof(struct syslink_msg))
674             return (EINVAL);
675
676         /*
677          * Buffer must contain entire record
678          */
679         aligned_reclen = SLMSG_ALIGN(head->reclen);
680         if (bytes < aligned_reclen)
681             return (EINVAL);
682         bytes -= aligned_reclen;
683         head = (void *)((char *)head + aligned_reclen);
684     }
685     return(0);
686 }
687