Probably the last change to the syslink() system call. Allow a generic
[dragonfly.git] / sys / kern / kern_syslink.c
blob4d3c86ae4bd670b39c36cdab22d19d9234174939
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:
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.
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.
34 * $DragonFly: src/sys/kern/kern_syslink.c,v 1.8 2007/04/16 17:40:13 dillon Exp $
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.
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #include <sys/alist.h>
47 #include <sys/file.h>
48 #include <sys/proc.h>
49 #include <sys/lock.h>
50 #include <sys/uio.h>
51 #include <sys/thread.h>
52 #include <sys/tree.h>
53 #include <sys/sysctl.h>
54 #include <sys/sysproto.h>
55 #include <sys/syslink.h>
56 #include <sys/syslink_msg.h>
58 #include <sys/thread2.h>
61 * Red-Black trees organizing the syslink 'router' nodes and connections
62 * to router nodes.
64 struct slrouter;
65 struct sldata;
67 RB_HEAD(slrouter_rb_tree, slrouter);
68 RB_HEAD(sldata_rb_tree, sldata);
69 RB_PROTOTYPE2(slrouter_rb_tree, slrouter, rbnode,
70 rb_slrouter_compare, sysid_t);
71 RB_PROTOTYPE2(sldata_rb_tree, sldata, rbnode,
72 rb_sldata_compare, int);
74 struct slrouter {
75 RB_ENTRY(slrouter) rbnode; /* list of routers */
76 struct sldata_rb_tree sldata_rb_root; /* connections to router */
77 sysid_t sysid; /* logical sysid of router */
78 int flags; /* flags passed on create */
79 int bits; /* accomodate connections */
80 int count; /* number of connections */
81 int refs;
82 alist_t bitmap;
83 char label[SYSLINK_LABEL_SIZE];
87 * fileops interface. slbuf and sldata are also used in conjunction with a
88 * normal file descriptor.
90 struct slbuf {
91 char *buf;
92 int bufsize; /* must be a power of 2 */
93 int bufmask; /* (bufsize - 1) */
94 int rindex; /* tail-chasing FIFO indices */
95 int windex;
98 struct sldata {
99 RB_ENTRY(sldata) rbnode;
100 struct slrouter *router; /* organizing router */
101 struct slbuf rbuf;
102 struct slbuf wbuf;
103 struct file *xfp; /* external file pointer */
104 struct lock rlock; /* synchronizing lock */
105 struct lock wlock; /* synchronizing lock */
106 struct thread *rthread; /* xfp -> rbuf & process */
107 struct thread *wthread; /* wbuf -> xfp */
108 int flags; /* connection flags */
109 int linkid;
110 int bits;
111 int refs;
112 char label[SYSLINK_LABEL_SIZE];
116 * syslink kernel thread support flags
118 #define SLF_RQUIT 0x0001
119 #define SLF_WQUIT 0x0002
120 #define SLF_RDONE 0x0004
121 #define SLF_WDONE 0x0008
122 #define SLF_DESTROYED 0x8000
124 #define SYSLINK_BUFSIZE (128*1024)
126 static int rb_slrouter_compare(struct slrouter *r1, struct slrouter *r2);
127 static int rb_sldata_compare(struct sldata *d1, struct sldata *d2);
129 static int syslink_destroy(struct slrouter *slrouter);
130 static int syslink_add(struct slrouter *slrouter, int fd,
131 struct syslink_info *info, int *result);
132 static int syslink_rem(struct slrouter *slrouter, struct sldata *sldata,
133 struct syslink_info *info);
135 static int syslink_read(struct file *fp, struct uio *uio,
136 struct ucred *cred, int flags);
137 static int syslink_write(struct file *fp, struct uio *uio,
138 struct ucred *cred, int flags);
139 static int syslink_close(struct file *fp);
140 static int syslink_stat(struct file *fp, struct stat *sb, struct ucred *cred);
141 static int syslink_shutdown(struct file *fp, int how);
142 static int syslink_ioctl(struct file *fp, u_long cmd, caddr_t data,
143 struct ucred *cred);
144 static int syslink_poll(struct file *fp, int events, struct ucred *cred);
145 static int syslink_kqfilter(struct file *fp, struct knote *kn);
147 static void syslink_rthread(void *arg);
148 static void syslink_wthread(void *arg);
149 static void slbuf_alloc(struct slbuf *buf, int bytes);
150 static void slbuf_free(struct slbuf *buf);
151 static void sldata_rels(struct sldata *sldata);
152 static void slrouter_rels(struct slrouter *slrouter);
153 static int process_syslink_msg(struct sldata *sldata, struct syslink_msg *head);
154 static int syslink_validate(struct syslink_msg *head, int bytes);
156 RB_GENERATE2(slrouter_rb_tree, slrouter, rbnode,
157 rb_slrouter_compare, sysid_t, sysid);
158 RB_GENERATE2(sldata_rb_tree, sldata, rbnode,
159 rb_sldata_compare, int, linkid);
161 static struct fileops syslinkops = {
162 .fo_read = syslink_read,
163 .fo_write = syslink_write,
164 .fo_ioctl = syslink_ioctl,
165 .fo_poll = syslink_poll,
166 .fo_kqfilter = syslink_kqfilter,
167 .fo_stat = syslink_stat,
168 .fo_close = syslink_close,
169 .fo_shutdown = syslink_shutdown
172 MALLOC_DEFINE(M_SYSLINK, "syslink", "syslink manager");
174 static int syslink_enabled;
175 SYSCTL_INT(_kern, OID_AUTO, syslink_enabled,
176 CTLFLAG_RW, &syslink_enabled, 0, "Enable SYSLINK");
179 * Support declarations and compare function for our RB trees
181 static struct slrouter_rb_tree slrouter_rb_root;
183 static int
184 rb_slrouter_compare(struct slrouter *r1, struct slrouter *r2)
186 if (r1->sysid < r2->sysid)
187 return(-1);
188 if (r1->sysid > r2->sysid)
189 return(1);
190 return(0);
193 static int
194 rb_sldata_compare(struct sldata *d1, struct sldata *d2)
196 if (d1->linkid < d2->linkid)
197 return(-1);
198 if (d1->linkid > d2->linkid)
199 return(1);
200 return(0);
204 * Compare and callback functions for first-sysid and first-linkid searches.
206 static int
207 syslink_cmd_locate_cmp(struct slrouter *slrouter, void *data)
209 struct syslink_info *info = data;
211 if (slrouter->sysid < info->sysid)
212 return(-1);
213 if (slrouter->sysid > info->sysid)
214 return(1);
215 return(0);
218 static int
219 syslink_cmd_locate_callback(struct slrouter *slrouter, void *data)
221 struct syslink_info *info = data;
223 info->flags = slrouter->flags; /* also clears SLIF_ERROR */
224 bcopy(slrouter->label, info->label, SYSLINK_LABEL_SIZE);
226 return(-1);
229 static int
230 syslink_cmd_find_cmp(struct sldata *sldata, void *data)
232 struct syslink_info *info = data;
234 if (sldata->linkid < info->linkid)
235 return(-1);
236 if (sldata->linkid > info->linkid)
237 return(1);
238 return(0);
241 static int
242 syslink_cmd_find_callback(struct sldata *sldata, void *data)
244 struct syslink_info *info = data;
246 info->linkid = sldata->linkid;
247 info->flags = sldata->flags; /* also clears SLIF_ERROR */
248 bcopy(sldata->label, info->label, SYSLINK_LABEL_SIZE);
250 return(-1);
254 * Primary system call interface - associate a full-duplex stream
255 * (typically a pipe or a connected socket) with a sysid namespace,
256 * or create a direct link.
258 * syslink(int fd, int cmd, void *info, size_t *infosize)
261 sys_syslink(struct syslink_args *uap)
263 struct syslink_info info;
264 struct slrouter *slrouter = NULL;
265 struct sldata *sldata = NULL;
266 int error;
267 int n;
270 * System call is under construction and disabled by default.
271 * Superuser access is also required.
273 if (syslink_enabled == 0)
274 return (EAUTH);
275 error = suser(curthread);
276 if (error)
277 return (error);
280 * Load and validate the info structure. Unloaded bytes are zerod out
282 bzero(&info, sizeof(info));
283 if ((unsigned)uap->bytes <= sizeof(info)) {
284 if (uap->bytes)
285 error = copyin(uap->info, &info, uap->bytes);
286 } else {
287 error = EINVAL;
289 if (error)
290 return (error);
292 if (info.label[sizeof(info.label)-1] != 0)
293 return (EINVAL);
296 * Process command
299 switch(uap->cmd) {
300 case SYSLINK_CMD_CREATE:
302 * Create a new syslink router node. Set refs to prevent the
303 * router node from being destroyed. One ref is our temporary
304 * reference while the other is the SLIF_DESTROYED-interlocked
305 * reference.
307 if (info.bits < 2 || info.bits > SYSLINK_ROUTER_MAXBITS)
308 return (EINVAL);
309 slrouter = kmalloc(sizeof(struct slrouter), M_SYSLINK,
310 M_WAITOK|M_ZERO);
311 if (slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root, info.sysid)) {
312 kfree(slrouter, M_SYSLINK);
313 slrouter = NULL;
314 return (EINVAL);
316 slrouter->sysid = info.sysid;
317 slrouter->refs = 2;
318 slrouter->bits = info.bits;
319 slrouter->flags = info.flags & SLIF_USERFLAGS;
320 slrouter->bitmap = alist_create(1 << info.bits, M_SYSLINK);
321 RB_INIT(&slrouter->sldata_rb_root);
322 RB_INSERT(slrouter_rb_tree, &slrouter_rb_root, slrouter);
323 break;
324 case SYSLINK_CMD_DESTROY:
326 * Destroy a syslink router node. The physical node is
327 * not freed until our temporary reference is removed.
329 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root,
330 info.sysid);
331 if (slrouter) {
332 ++slrouter->refs;
333 if ((slrouter->flags & SLIF_DESTROYED) == 0) {
334 slrouter->flags |= SLIF_DESTROYED;
335 /* SLIF_DESTROYED interlock */
336 slrouter_rels(slrouter);
337 error = syslink_destroy(slrouter);
338 /* still holding our private interlock */
341 break;
342 case SYSLINK_CMD_LOCATE:
344 * Locate the first syslink router node >= info.sysid
346 info.flags |= SLIF_ERROR;
347 n = slrouter_rb_tree_RB_SCAN(
348 &slrouter_rb_root,
349 syslink_cmd_locate_cmp, syslink_cmd_locate_callback,
350 &info);
351 if (info.flags & SLIF_ERROR)
352 error = ENOENT;
353 break;
354 case SYSLINK_CMD_ADD:
355 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root, info.sysid);
356 if (info.bits &&
357 (info.bits < 2 || info.bits > SYSLINK_ROUTER_MAXBITS)) {
358 error = EINVAL;
359 } else if (slrouter && (slrouter->flags & SLIF_DESTROYED)) {
361 * Someone is trying to destroy this route node,
362 * no new adds please!
364 error = EIO;
365 } else if (slrouter) {
366 ++slrouter->refs;
367 error = syslink_add(slrouter, uap->fd, &info,
368 &uap->sysmsg_result);
369 } else {
370 error = EINVAL;
372 break;
373 case SYSLINK_CMD_REM:
374 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root,
375 info.sysid);
376 if (slrouter) {
377 ++slrouter->refs;
378 sldata = sldata_rb_tree_RB_LOOKUP(&slrouter->sldata_rb_root, info.linkid);
379 if (sldata) {
380 ++sldata->refs;
381 error = syslink_rem(slrouter, sldata, &info);
382 } else {
383 error = ENOENT;
385 } else {
386 error = EINVAL;
388 break;
389 case SYSLINK_CMD_FIND:
390 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root, info.sysid);
391 info.flags |= SLIF_ERROR;
392 if (slrouter) {
393 ++slrouter->refs;
394 n = sldata_rb_tree_RB_SCAN(
395 &slrouter->sldata_rb_root,
396 syslink_cmd_find_cmp, syslink_cmd_find_callback,
397 &info);
398 if (info.flags & SLIF_ERROR)
399 error = ENOENT;
400 } else {
401 error = EINVAL;
403 break;
404 default:
405 error = EINVAL;
406 break;
410 * Cleanup
412 if (sldata)
413 sldata_rels(sldata);
414 if (slrouter)
415 slrouter_rels(slrouter);
416 return (error);
419 static
421 syslink_destroy_callback(struct sldata *sldata, void *data __unused)
423 ++sldata->refs;
424 if ((sldata->flags & SLF_RQUIT) == 0) {
425 sldata->flags |= SLF_RQUIT;
426 wakeup(&sldata->rbuf);
428 if ((sldata->flags & SLF_WQUIT) == 0) {
429 sldata->flags |= SLF_WQUIT;
430 wakeup(&sldata->wbuf);
432 sldata_rels(sldata);
433 return(0);
437 * Shutdown all the connections going into this syslink.
439 * Try to wait for completion, but return after 1 second
440 * regardless.
442 static
444 syslink_destroy(struct slrouter *slrouter)
446 int retries = 10;
448 while (!RB_EMPTY(&slrouter->sldata_rb_root) && retries) {
449 RB_SCAN(sldata_rb_tree, &slrouter->sldata_rb_root, NULL,
450 syslink_destroy_callback, slrouter);
451 --retries;
452 tsleep(&retries, 0, "syslnk", hz / 10);
454 if (RB_EMPTY(&slrouter->sldata_rb_root))
455 return(0);
456 else
457 return(EINPROGRESS);
460 static
462 syslink_add(struct slrouter *slrouter, int fd, struct syslink_info *info,
463 int *result)
465 struct sldata *sldata;
466 struct file *fp;
467 int maxphys;
468 int numphys;
469 int linkid;
470 int error;
472 error = 0;
473 maxphys = 1 << slrouter->bits;
474 numphys = info->bits ? (1 << info->bits) : 1;
477 * Create a connection to the route node and allocate a physical ID.
478 * Physical ID 0 is reserved for the route node itself, and an all-1's
479 * ID is reserved as a broadcast address.
481 sldata = kmalloc(sizeof(struct sldata), M_SYSLINK, M_WAITOK|M_ZERO);
483 linkid = alist_alloc(slrouter->bitmap, numphys);
484 if (linkid == ALIST_BLOCK_NONE) {
485 kfree(sldata, M_SYSLINK);
486 return (ENOSPC);
490 * Insert the node, initializing enough fields to prevent things from
491 * being ripped out from under us before we have a chance to complete
492 * the system call.
494 sldata->linkid = linkid;
495 sldata->refs = 1;
496 ++slrouter->count;
497 if (sldata_rb_tree_RB_LOOKUP(&slrouter->sldata_rb_root, linkid))
498 panic("syslink_add: free linkid wasn't free!");
499 RB_INSERT(sldata_rb_tree, &slrouter->sldata_rb_root, sldata);
502 * Complete initialization of the physical route node. Setting
503 * sldata->router activates the node.
505 lockinit(&sldata->rlock, "slread", 0, 0);
506 lockinit(&sldata->wlock, "slwrite", 0, 0);
508 if (fd < 0) {
510 * We create a direct syslink descriptor. Only the
511 * reader thread is needed.
513 error = falloc(curproc, &fp, &fd);
514 if (error == 0) {
515 fp->f_type = DTYPE_SYSLINK;
516 fp->f_flag = FREAD | FWRITE;
517 fp->f_ops = &syslinkops;
518 fp->f_data = sldata;
519 slbuf_alloc(&sldata->rbuf, SYSLINK_BUFSIZE);
520 slbuf_alloc(&sldata->wbuf, SYSLINK_BUFSIZE);
521 /* two refs: reader thread and fp descriptor */
522 sldata->refs += 2;
523 sldata->flags = SLF_WQUIT | SLF_WDONE;
524 lwkt_create(syslink_rthread, sldata,
525 &sldata->rthread, NULL,
526 0, -1, "syslink_r");
527 fsetfd(curproc, fp, fd);
528 fdrop(fp);
529 *result = fd;
531 } else {
532 sldata->xfp = holdfp(curproc->p_fd, fd, -1);
533 if (sldata->xfp != NULL) {
534 slbuf_alloc(&sldata->rbuf, SYSLINK_BUFSIZE);
535 slbuf_alloc(&sldata->wbuf, SYSLINK_BUFSIZE);
536 /* two refs: reader thread and writer thread */
537 sldata->refs += 2;
538 lwkt_create(syslink_rthread, sldata,
539 &sldata->rthread, NULL,
540 0, -1, "syslink_r");
541 lwkt_create(syslink_wthread, sldata,
542 &sldata->wthread, NULL,
543 0, -1, "syslink_w");
544 } else {
545 error = EBADF;
548 sldata->router = slrouter;
549 sldata_rels(sldata);
550 return(error);
553 static
555 syslink_rem(struct slrouter *slrouter, struct sldata *sldata,
556 struct syslink_info *info)
558 int error = EINPROGRESS;
560 if ((sldata->flags & SLF_RQUIT) == 0) {
561 sldata->flags |= SLF_RQUIT;
562 wakeup(&sldata->rbuf);
563 error = 0;
565 if ((sldata->flags & SLF_WQUIT) == 0) {
566 sldata->flags |= SLF_WQUIT;
567 wakeup(&sldata->wbuf);
568 error = 0;
570 return(error);
574 * This thread reads from an external descriptor into rbuf, then parses and
575 * dispatches syslink messages from rbuf.
577 static
578 void
579 syslink_rthread(void *arg)
581 struct sldata *sldata = arg;
582 struct slbuf *slbuf = &sldata->rbuf;
583 struct syslink_msg *head;
584 const int min_msg_size = SL_MIN_MESSAGE_SIZE;
586 while ((sldata->flags & SLF_RQUIT) == 0) {
587 int count;
588 int used;
589 int error;
592 * Calculate contiguous space available to read and read as
593 * much as possible.
595 * If the entire buffer is used there's probably a format
596 * error of some sort and we terminate the link.
598 used = slbuf->windex - slbuf->rindex;
599 error = 0;
602 * Read some data, terminate the link if an error occurs or
603 * if EOF is encountered. xfp can be NULL, indicating that
604 * the data was injected by other means.
606 if (sldata->xfp) {
607 count = slbuf->bufsize -
608 (slbuf->windex & slbuf->bufmask);
609 if (count > slbuf->bufsize - used)
610 count = slbuf->bufsize - used;
611 if (count == 0)
612 break;
613 error = fp_read(sldata->xfp,
614 slbuf->buf +
615 (slbuf->windex & slbuf->bufmask),
616 count, &count, 0, UIO_SYSSPACE);
617 if (error)
618 break;
619 if (count == 0)
620 break;
621 slbuf->windex += count;
622 used += count;
623 } else {
624 tsleep(slbuf, 0, "fiford", 0);
628 * Process as many syslink messages as we can. The record
629 * length must be at least a minimal PAD record (8 bytes).
631 while (slbuf->windex - slbuf->rindex >= min_msg_size) {
632 int aligned_reclen;
634 head = (void *)(slbuf->buf +
635 (slbuf->rindex & slbuf->bufmask));
636 if (head->sm_bytes < min_msg_size) {
637 error = EINVAL;
638 break;
640 aligned_reclen = SLMSG_ALIGN(head->sm_bytes);
643 * Disallow wraps
645 if ((slbuf->rindex & slbuf->bufmask) >
646 ((slbuf->rindex + aligned_reclen) & slbuf->bufmask)
648 error = EINVAL;
649 break;
653 * Insufficient data read
655 if (slbuf->windex - slbuf->rindex < aligned_reclen)
656 break;
659 * Process non-pad messages. Non-pad messages have
660 * to be at least the size of the syslink_msg
661 * structure.
663 * A PAD message's sm_cmd field contains 0.
665 if (head->sm_cmd) {
666 if (head->sm_bytes < sizeof(*head)) {
667 error = EINVAL;
668 break;
670 error = process_syslink_msg(sldata, head);
671 if (error)
672 break;
674 cpu_sfence();
675 slbuf->rindex += aligned_reclen;
677 if (error)
678 break;
682 * Mark us as done and deref sldata. Tell the writer to terminate as
683 * well.
685 sldata->flags |= SLF_RDONE;
686 if ((sldata->flags & SLF_WDONE) == 0) {
687 sldata->flags |= SLF_WQUIT;
688 wakeup(&sldata->wbuf);
690 wakeup(&sldata->rbuf);
691 wakeup(&sldata->wbuf);
692 sldata_rels(sldata);
696 * This thread takes outgoing syslink messages queued to wbuf and writes them
697 * to the descriptor. PAD is stripped. PAD is also added as required to
698 * conform to the outgoing descriptor's buffering requirements.
700 static
701 void
702 syslink_wthread(void *arg)
704 struct sldata *sldata = arg;
705 struct slbuf *slbuf = &sldata->wbuf;
706 struct syslink_msg *head;
707 int error;
709 while ((sldata->flags & SLF_WQUIT) == 0) {
710 error = 0;
711 for (;;) {
712 int aligned_reclen;
713 int used;
714 int count;
716 used = slbuf->windex - slbuf->rindex;
717 if (used < SL_MIN_MESSAGE_SIZE)
718 break;
720 head = (void *)(slbuf->buf +
721 (slbuf->rindex & slbuf->bufmask));
722 if (head->sm_bytes < SL_MIN_MESSAGE_SIZE) {
723 error = EINVAL;
724 break;
726 aligned_reclen = SLMSG_ALIGN(head->sm_bytes);
729 * Disallow wraps
731 if ((slbuf->rindex & slbuf->bufmask) >
732 ((slbuf->rindex + aligned_reclen) & slbuf->bufmask)
734 error = EINVAL;
735 break;
739 * Insufficient data read
741 if (used < aligned_reclen)
742 break;
745 * Write it out whether it is PAD or not.
746 * XXX re-PAD for output here.
748 error = fp_write(sldata->xfp, head,
749 aligned_reclen,
750 &count,
751 UIO_SYSSPACE);
752 if (error && error != ENOBUFS)
753 break;
754 if (count != aligned_reclen) {
755 error = EIO;
756 break;
758 slbuf->rindex += aligned_reclen;
760 if (error)
761 break;
762 tsleep(slbuf, 0, "fifowt", 0);
764 sldata->flags |= SLF_WDONE;
765 sldata_rels(sldata);
768 static
769 void
770 slbuf_alloc(struct slbuf *slbuf, int bytes)
772 bzero(slbuf, sizeof(*slbuf));
773 slbuf->buf = kmalloc(bytes, M_SYSLINK, M_WAITOK);
774 slbuf->bufsize = bytes;
775 slbuf->bufmask = bytes - 1;
778 static
779 void
780 slbuf_free(struct slbuf *slbuf)
782 kfree(slbuf->buf, M_SYSLINK);
783 slbuf->buf = NULL;
786 static
787 void
788 sldata_rels(struct sldata *sldata)
790 struct slrouter *slrouter;
792 if (--sldata->refs == 0) {
793 slrouter = sldata->router;
794 KKASSERT(slrouter != NULL);
795 ++slrouter->refs;
796 RB_REMOVE(sldata_rb_tree,
797 &sldata->router->sldata_rb_root, sldata);
798 sldata->router = NULL;
799 slbuf_free(&sldata->rbuf);
800 slbuf_free(&sldata->wbuf);
801 kfree(sldata, M_SYSLINK);
802 slrouter_rels(slrouter);
806 static
807 void
808 slrouter_rels(struct slrouter *slrouter)
810 if (--slrouter->refs == 0 && RB_EMPTY(&slrouter->sldata_rb_root)) {
811 KKASSERT(slrouter->flags & SLIF_DESTROYED);
812 RB_REMOVE(slrouter_rb_tree, &slrouter_rb_root, slrouter);
813 alist_destroy(slrouter->bitmap, M_SYSLINK);
814 slrouter->bitmap = NULL;
815 kfree(slrouter, M_SYSLINK);
820 * fileops for an established syslink when the kernel is asked to create a
821 * descriptor (verses one being handed to it). No threads are created in
822 * this case.
826 * Transfer zero or more messages from the kernel to userland. Only complete
827 * messages are returned. If the uio has insufficient space then EMSGSIZE
828 * is returned. The kernel feeds messages to wbuf so we use wlock (structures
829 * are relative to the kernel).
831 static
833 syslink_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags)
835 struct sldata *sldata = fp->f_data;
836 struct slbuf *slbuf = &sldata->wbuf;
837 struct syslink_msg *head;
838 int bytes;
839 int contig;
840 int error;
841 int nbio;
843 if (flags & O_FBLOCKING)
844 nbio = 0;
845 else if (flags & O_FNONBLOCKING)
846 nbio = 1;
847 else if (fp->f_flag & O_NONBLOCK)
848 nbio = 1;
849 else
850 nbio = 0;
852 lockmgr(&sldata->wlock, LK_EXCLUSIVE | LK_RETRY);
855 * Calculate the number of bytes we can transfer in one shot. Transfers
856 * do not wrap the FIFO.
858 contig = slbuf->bufsize - (slbuf->rindex & slbuf->bufmask);
859 for (;;) {
860 bytes = slbuf->windex - slbuf->rindex;
861 if (bytes)
862 break;
863 if (sldata->flags & SLF_RDONE) {
864 error = EIO;
865 break;
867 if (nbio) {
868 error = EAGAIN;
869 goto done;
871 tsleep(slbuf, 0, "fiford", 0);
873 if (bytes > contig)
874 bytes = contig;
877 * The uio must be able to accomodate the transfer.
879 if (uio->uio_resid < bytes) {
880 error = ENOSPC;
881 goto done;
885 * Copy the data to userland and update rindex.
887 head = (void *)(slbuf->buf + (slbuf->rindex & slbuf->bufmask));
888 error = uiomove((caddr_t)head, bytes, uio);
889 if (error == 0)
890 slbuf->rindex += bytes;
893 * Cleanup
895 done:
896 lockmgr(&sldata->wlock, LK_RELEASE);
897 return (error);
901 * Transfer zero or more messages from userland to the kernel. Only complete
902 * messages may be written. The kernel processes from rbuf so that is where
903 * we have to copy the messages.
905 static
907 syslink_write (struct file *fp, struct uio *uio, struct ucred *cred, int flags)
909 struct sldata *sldata = fp->f_data;
910 struct slbuf *slbuf = &sldata->rbuf;
911 struct syslink_msg *head;
912 int bytes;
913 int contig;
914 int nbio;
915 int error;
917 if (flags & O_FBLOCKING)
918 nbio = 0;
919 else if (flags & O_FNONBLOCKING)
920 nbio = 1;
921 else if (fp->f_flag & O_NONBLOCK)
922 nbio = 1;
923 else
924 nbio = 0;
926 lockmgr(&sldata->rlock, LK_EXCLUSIVE | LK_RETRY);
929 * Calculate the maximum number of contiguous bytes that may be
930 * available. Caller is required to not wrap our FIFO.
932 contig = slbuf->bufsize - (slbuf->windex & slbuf->bufmask);
933 if (uio->uio_resid > contig) {
934 error = ENOSPC;
935 goto done;
939 * Truncate based on actual unused space available in the FIFO. If
940 * the uio does not fit, block and loop.
942 for (;;) {
943 bytes = slbuf->bufsize - (slbuf->windex - slbuf->rindex);
944 if (bytes > contig)
945 bytes = contig;
946 if (uio->uio_resid <= bytes)
947 break;
948 if (sldata->flags & SLF_RDONE) {
949 error = EIO;
950 goto done;
952 if (nbio) {
953 error = EAGAIN;
954 goto done;
956 tsleep(slbuf, 0, "fifowr", 0);
958 bytes = uio->uio_resid;
959 head = (void *)(slbuf->buf + (slbuf->windex & slbuf->bufmask));
960 error = uiomove((caddr_t)head, bytes, uio);
961 if (error == 0)
962 error = syslink_validate(head, bytes);
963 if (error == 0) {
964 slbuf->windex += bytes;
965 wakeup(slbuf);
967 done:
968 lockmgr(&sldata->rlock, LK_RELEASE);
969 return(error);
972 static
974 syslink_close (struct file *fp)
976 struct sldata *sldata;
978 sldata = fp->f_data;
979 if ((sldata->flags & SLF_RQUIT) == 0) {
980 sldata->flags |= SLF_RQUIT;
981 wakeup(&sldata->rbuf);
983 if ((sldata->flags & SLF_WQUIT) == 0) {
984 sldata->flags |= SLF_WQUIT;
985 wakeup(&sldata->wbuf);
987 fp->f_data = NULL;
988 sldata_rels(sldata);
989 return(0);
992 static
994 syslink_stat (struct file *fp, struct stat *sb, struct ucred *cred)
996 return(EINVAL);
999 static
1001 syslink_shutdown (struct file *fp, int how)
1003 return(EINVAL);
1006 static
1008 syslink_ioctl (struct file *fp, u_long cmd, caddr_t data, struct ucred *cred)
1010 return(EINVAL);
1013 static
1015 syslink_poll (struct file *fp, int events, struct ucred *cred)
1017 return(0);
1020 static
1022 syslink_kqfilter(struct file *fp, struct knote *kn)
1024 return(0);
1028 * This routine is called from a route node's reader thread to process a
1029 * syslink message once it has been completely read and its size validated.
1031 static
1033 process_syslink_msg(struct sldata *sldata, struct syslink_msg *head)
1035 kprintf("process syslink msg %08x\n", head->sm_cmd);
1036 return(0);
1040 * Validate that the syslink message header(s) are correctly sized.
1042 static
1044 syslink_validate(struct syslink_msg *head, int bytes)
1046 const int min_msg_size = SL_MIN_MESSAGE_SIZE;
1047 int aligned_reclen;
1049 while (bytes) {
1051 * Message size and alignment
1053 if (bytes < min_msg_size)
1054 return (EINVAL);
1055 if (bytes & SL_ALIGNMASK)
1056 return (EINVAL);
1057 if (head->sm_cmd && bytes < sizeof(struct syslink_msg))
1058 return (EINVAL);
1061 * Buffer must contain entire record
1063 aligned_reclen = SLMSG_ALIGN(head->sm_bytes);
1064 if (bytes < aligned_reclen)
1065 return (EINVAL);
1066 bytes -= aligned_reclen;
1067 head = (void *)((char *)head + aligned_reclen);
1069 return(0);