Syslink API work - greatly simplify the syslink_msg structure. Reimplement
[dragonfly.git] / sys / kern / kern_syslink.c
1 /*
2  * Copyright (c) 2006-2007 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.11 2007/05/27 20:35:38 dillon Exp $
35  */
36 /*
37  * This module implements the core syslink() system call and provides
38  * glue for kernel syslink frontends and backends, creating a intra-host
39  * communications infrastructure and DMA transport abstraction.
40  */
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/endian.h>
46 #include <sys/malloc.h>
47 #include <sys/alist.h>
48 #include <sys/file.h>
49 #include <sys/proc.h>
50 #include <sys/lock.h>
51 #include <sys/uio.h>
52 #include <sys/objcache.h>
53 #include <sys/queue.h>
54 #include <sys/thread.h>
55 #include <sys/tree.h>
56 #include <sys/sysctl.h>
57 #include <sys/sysproto.h>
58 #include <sys/mbuf.h>
59 #include <sys/socket.h>
60 #include <sys/socketvar.h>
61 #include <sys/socketops.h>
62 #include <sys/sysref.h>
63 #include <sys/syslink.h>
64 #include <sys/syslink_msg.h>
65 #include <netinet/in.h>
66
67 #include <sys/thread2.h>
68 #include <sys/spinlock2.h>
69
70 #include "opt_syslink.h"
71
72 /*
73  * Syslink Connection abstraction
74  */
75 struct slcommon {
76         struct spinlock spin;
77         int     refs;
78 };
79
80 struct sldesc {
81         struct slmsgq   inq;
82         struct slmsg_rb_tree reply_rb_root; /* replies to requests */
83         struct spinlock spin;
84         struct sldesc   *peer;          /* peer syslink, if any */
85         struct file     *xfp;           /* external file pointer */
86         struct slcommon *common;
87         int     flags;
88         int     rwaiters;               /* number of threads waiting */
89         int     wblocked;               /* blocked waiting for us to drain */
90         size_t  cmdbytes;               /* unreplied commands pending */
91         size_t  repbytes;               /* undrained replies pending */
92         int     (*backend_wblocked)(struct sldesc *, int, sl_proto_t);
93         int     (*backend_write)(struct sldesc *, struct slmsg *);
94         void    (*backend_reply)(struct sldesc *,struct slmsg *,struct slmsg *);
95         void    (*backend_dispose)(struct sldesc *, struct slmsg *);
96 };
97
98 #define SLF_RSHUTDOWN   0x0001
99 #define SLF_WSHUTDOWN   0x0002
100
101 static int syslink_cmd_new(struct syslink_info_new *info, int *result);
102 static struct sldesc *allocsldesc(struct slcommon *common);
103 static void setsldescfp(struct sldesc *sl, struct file *fp);
104 static void shutdownsldesc(struct sldesc *sl, int how);
105 static void shutdownsldesc2(struct sldesc *sl, int how);
106 static void sldrop(struct sldesc *sl);
107 static int syslink_validate_msg(struct syslink_msg *msg, int bytes);
108 static int syslink_validate_elm(struct syslink_elm *elm, sl_reclen_t bytes,
109                                  int swapit, int depth);
110
111 static int backend_wblocked_user(struct sldesc *sl, int nbio, sl_proto_t proto);
112 static int backend_write_user(struct sldesc *sl, struct slmsg *slmsg);
113 static void backend_reply_user(struct sldesc *sl, struct slmsg *slcmd,
114                                struct slmsg *slrep);
115 static void backend_dispose_user(struct sldesc *sl, struct slmsg *slmsg);
116
117 static int backend_wblocked_kern(struct sldesc *sl, int nbio, sl_proto_t proto);
118 static int backend_write_kern(struct sldesc *sl, struct slmsg *slmsg);
119 static void backend_reply_kern(struct sldesc *sl, struct slmsg *slcmd,
120                                struct slmsg *slrep);
121 static void backend_dispose_kern(struct sldesc *sl, struct slmsg *slmsg);
122
123 /*
124  * Objcache memory backend
125  *
126  * All three object caches return slmsg structures but each is optimized
127  * for syslink message buffers of varying sizes.  We use the slightly
128  * more complex ctor/dtor API in order to provide ready-to-go slmsg's.
129  */
130
131 struct objcache *sl_objcache_big;
132 struct objcache *sl_objcache_small;
133 struct objcache *sl_objcache_none;
134
135 MALLOC_DEFINE(M_SYSLINK, "syslink", "syslink manager");
136
137 static boolean_t slmsg_ctor(void *data, void *private, int ocflags);
138 static void slmsg_dtor(void *data, void *private);
139
140 static
141 void
142 syslinkinit(void *dummy __unused)
143 {
144         size_t n = sizeof(struct slmsg);
145
146         sl_objcache_none = objcache_create_mbacked(M_SYSLINK, n, 0, 64,
147                                                    slmsg_ctor, slmsg_dtor,
148                                                    &sl_objcache_none);
149         sl_objcache_small= objcache_create_mbacked(M_SYSLINK, n, 0, 64,
150                                                    slmsg_ctor, slmsg_dtor,
151                                                    &sl_objcache_small);
152         sl_objcache_big  = objcache_create_mbacked(M_SYSLINK, n, 0, 16,
153                                                    slmsg_ctor, slmsg_dtor,
154                                                    &sl_objcache_big);
155 }
156
157 static
158 boolean_t
159 slmsg_ctor(void *data, void *private, int ocflags)
160 {
161         struct slmsg *slmsg = data;
162
163         bzero(slmsg, sizeof(*slmsg));
164
165         slmsg->oc = *(struct objcache **)private;
166         if (slmsg->oc == sl_objcache_none) {
167                 slmsg->maxsize = 0;
168         } else if (slmsg->oc == sl_objcache_small) {
169                 slmsg->maxsize = SLMSG_SMALL;
170         } else if (slmsg->oc == sl_objcache_big) {
171                 slmsg->maxsize = SLMSG_BIG;
172         } else {
173                 panic("slmsg_ctor: bad objcache?\n");
174         }
175         if (slmsg->maxsize) {
176                 slmsg->msg = kmalloc(slmsg->maxsize,
177                                      M_SYSLINK, M_WAITOK|M_ZERO);
178         }
179         return(TRUE);
180 }
181
182 static
183 void
184 slmsg_dtor(void *data, void *private)
185 {
186         struct slmsg *slmsg = data;
187
188         if (slmsg->maxsize && slmsg->msg) {
189                 kfree(slmsg->msg, M_SYSLINK);
190                 slmsg->msg = NULL;
191         }
192         slmsg->oc = NULL;
193 }
194
195 SYSINIT(syslink, SI_BOOT2_MACHDEP, SI_ORDER_ANY, syslinkinit, NULL)
196
197 static int rb_slmsg_compare(struct slmsg *msg1, struct slmsg *msg2);
198 RB_GENERATE2(slmsg_rb_tree, slmsg, rbnode, rb_slmsg_compare,
199              sysid_t, msg->sm_msgid);
200
201 /*
202  * Sysctl elements
203  */
204 static int syslink_enabled;
205 SYSCTL_NODE(_kern, OID_AUTO, syslink, CTLFLAG_RW, 0, "Pipe operation");
206 SYSCTL_INT(_kern_syslink, OID_AUTO, enabled,
207             CTLFLAG_RW, &syslink_enabled, 0, "Enable SYSLINK");
208 static size_t syslink_bufsize = 65536;
209 SYSCTL_UINT(_kern_syslink, OID_AUTO, bufsize,
210             CTLFLAG_RW, &syslink_bufsize, 0, "Maximum buffer size");
211
212 /*
213  * Fileops API - typically used to glue a userland frontend with a
214  *               kernel backend.
215  */
216
217 static int slfileop_read(struct file *fp, struct uio *uio,
218                         struct ucred *cred, int flags);
219 static int slfileop_write(struct file *fp, struct uio *uio,
220                          struct ucred *cred, int flags);
221 static int slfileop_close(struct file *fp);
222 static int slfileop_stat(struct file *fp, struct stat *sb, struct ucred *cred);
223 static int slfileop_shutdown(struct file *fp, int how);
224 static int slfileop_ioctl(struct file *fp, u_long cmd, caddr_t data,
225                          struct ucred *cred);
226 static int slfileop_poll(struct file *fp, int events, struct ucred *cred);
227 static int slfileop_kqfilter(struct file *fp, struct knote *kn);
228
229 static struct fileops syslinkops = {
230     .fo_read =          slfileop_read,
231     .fo_write =         slfileop_write,
232     .fo_ioctl =         slfileop_ioctl,
233     .fo_poll =          slfileop_poll,
234     .fo_kqfilter =      slfileop_kqfilter,
235     .fo_stat =          slfileop_stat,
236     .fo_close =         slfileop_close,
237     .fo_shutdown =      slfileop_shutdown
238 };
239
240 /************************************************************************
241  *                      PRIMARY SYSTEM CALL INTERFACE                   *
242  ************************************************************************
243  *
244  * syslink(int cmd, struct syslink_info *info, size_t bytes)
245  */
246 int
247 sys_syslink(struct syslink_args *uap)
248 {
249         union syslink_info_all info;
250         int error;
251
252         /*
253          * System call is under construction and disabled by default. 
254          * Superuser access is also required for now, but eventually
255          * will not be needed.
256          */
257         if (syslink_enabled == 0)
258                 return (EAUTH);
259         error = suser(curthread);
260         if (error)
261                 return (error);
262
263         /*
264          * Load and validate the info structure.  Unloaded bytes are zerod
265          * out.  The label field must always be 0-filled, even if not used
266          * for a command.
267          */
268         bzero(&info, sizeof(info));
269         if ((unsigned)uap->bytes <= sizeof(info)) {
270                 if (uap->bytes)
271                         error = copyin(uap->info, &info, uap->bytes);
272         } else {
273                 error = EINVAL;
274         }
275         if (error)
276                 return (error);
277
278         /*
279          * Process the command
280          */
281         switch(uap->cmd) {
282         case SYSLINK_CMD_NEW:
283                 error = syslink_cmd_new(&info.cmd_new, &uap->sysmsg_result);
284                 break;
285         default:
286                 error = EINVAL;
287                 break;
288         }
289         if (error == 0 && info.head.wbflag)
290                 copyout(&info, uap->info, uap->bytes);
291         return (error);
292 }
293
294 /*
295  * Create a linked pair of descriptors, like a pipe.
296  */
297 static
298 int
299 syslink_cmd_new(struct syslink_info_new *info, int *result)
300 {
301         struct proc *p = curproc;
302         struct file *fp1;
303         struct file *fp2;
304         struct sldesc *sl;
305         struct sldesc *slpeer;
306         int error;
307         int fd1, fd2;
308
309         error = falloc(p, &fp1, &fd1);
310         if (error)
311                 return(error);
312         error = falloc(p, &fp2, &fd2);
313         if (error) {
314                 fsetfd(p, NULL, fd1);
315                 fdrop(fp1);
316                 return(error);
317         }
318         slpeer = allocsldesc(NULL);
319         slpeer->backend_wblocked = backend_wblocked_user;
320         slpeer->backend_write = backend_write_user;
321         slpeer->backend_reply = backend_reply_user;
322         slpeer->backend_dispose = backend_dispose_user;
323         sl = allocsldesc(slpeer->common);
324         sl->peer = slpeer;
325         sl->backend_wblocked = backend_wblocked_user;
326         sl->backend_write = backend_write_user;
327         sl->backend_reply = backend_reply_user;
328         sl->backend_dispose = backend_dispose_user;
329         slpeer->peer = sl;
330
331         setsldescfp(sl, fp1);
332         setsldescfp(slpeer, fp2);
333
334         fsetfd(p, fp1, fd1);
335         fdrop(fp1);
336         fsetfd(p, fp2, fd2);
337         fdrop(fp2);
338
339         info->head.wbflag = 1;  /* write back */
340         info->fds[0] = fd1;
341         info->fds[1] = fd2;
342
343         return(0);
344 }
345
346 /************************************************************************
347  *                      LOW LEVEL SLDESC SUPPORT                        *
348  ************************************************************************
349  *
350  */
351
352 static
353 struct sldesc *
354 allocsldesc(struct slcommon *common)
355 {
356         struct sldesc *sl;
357
358         sl = kmalloc(sizeof(struct sldesc), M_SYSLINK, M_WAITOK|M_ZERO);
359         if (common == NULL)
360                 common = kmalloc(sizeof(*common), M_SYSLINK, M_WAITOK|M_ZERO);
361         TAILQ_INIT(&sl->inq);           /* incoming requests */
362         RB_INIT(&sl->reply_rb_root);    /* match incoming replies */
363         spin_init(&sl->spin);
364         sl->common = common;
365         ++common->refs;
366         return(sl);
367 }
368
369 static
370 void
371 setsldescfp(struct sldesc *sl, struct file *fp)
372 {
373         sl->xfp = fp;
374         fp->f_type = DTYPE_SYSLINK;
375         fp->f_flag = FREAD | FWRITE;
376         fp->f_ops = &syslinkops;
377         fp->f_data = sl;
378 }
379
380 /*
381  * Red-black tree compare function
382  */
383 static
384 int
385 rb_slmsg_compare(struct slmsg *msg1, struct slmsg *msg2)
386 {
387         if (msg1->msg->sm_msgid < msg2->msg->sm_msgid)
388                 return(-1);
389         if (msg1->msg->sm_msgid == msg2->msg->sm_msgid)
390                 return(0);
391         return(1);
392 }
393
394 static
395 void
396 shutdownsldesc(struct sldesc *sl, int how)
397 {
398         struct slmsg *slmsg;
399         int rhow;
400
401         shutdownsldesc2(sl, how);
402
403         /*
404          * Return unread and unreplied messages
405          */
406         spin_lock_wr(&sl->spin);
407         while ((slmsg = TAILQ_FIRST(&sl->inq)) != NULL) {
408                 TAILQ_REMOVE(&sl->inq, slmsg, tqnode);
409                 spin_unlock_wr(&sl->spin);
410                 if (slmsg->msg->sm_proto & SM_PROTO_REPLY) {
411                         sl->repbytes -= slmsg->maxsize;
412                         slmsg->flags &= ~SLMSGF_ONINQ;
413                         sl->peer->backend_dispose(sl->peer, slmsg);
414                 }
415                 /* leave ONINQ set for commands, it will cleared below */
416                 spin_lock_wr(&sl->spin);
417         }
418         while ((slmsg = RB_ROOT(&sl->reply_rb_root)) != NULL) {
419                 RB_REMOVE(slmsg_rb_tree, &sl->reply_rb_root, slmsg);
420                 sl->cmdbytes -= slmsg->maxsize;
421                 spin_unlock_wr(&sl->spin);
422                 slmsg->flags &= ~SLMSGF_ONINQ;
423                 sl->peer->backend_reply(sl->peer, slmsg, NULL);
424                 spin_lock_wr(&sl->spin);
425         }
426         spin_unlock_wr(&sl->spin);
427
428         /*
429          * Call shutdown on the peer with the opposite flags
430          */
431         rhow = 0;
432         if (how & SHUT_RD)
433                 rhow |= SHUT_WR;
434         if (how & SHUT_WR)
435                 rhow |= SHUT_RD;
436         shutdownsldesc2(sl->peer, rhow);
437 }
438
439 static
440 void
441 shutdownsldesc2(struct sldesc *sl, int how)
442 {
443         spin_lock_wr(&sl->spin);
444         if (how & SHUT_RD)
445                 sl->flags |= SLF_RSHUTDOWN;
446         if (how & SHUT_WR)
447                 sl->flags |= SLF_WSHUTDOWN;
448         spin_unlock_wr(&sl->spin);
449
450         /*
451          * Handle signaling on the user side
452          */
453         if (how & SHUT_RD) {
454                 if (sl->rwaiters)
455                         wakeup(&sl->rwaiters);
456         }
457         if (how & SHUT_WR) {
458                 if (sl->wblocked) {
459                         sl->wblocked = 0;       /* race ok */
460                         wakeup(&sl->wblocked);
461                 }
462         }
463 }
464
465 static
466 void
467 sldrop(struct sldesc *sl)
468 {
469         struct sldesc *slpeer;
470
471         spin_lock_wr(&sl->common->spin);
472         if (--sl->common->refs == 0) {
473                 spin_unlock_wr(&sl->common->spin);
474                 if ((slpeer = sl->peer) != NULL) {
475                         sl->peer = NULL;
476                         slpeer->peer = NULL;
477                         slpeer->common = NULL;
478                         KKASSERT(slpeer->xfp == NULL);
479                         KKASSERT(TAILQ_EMPTY(&slpeer->inq));
480                         KKASSERT(RB_EMPTY(&slpeer->reply_rb_root));
481                         kfree(slpeer, M_SYSLINK);
482                 }
483                 KKASSERT(sl->xfp == NULL);
484                 KKASSERT(TAILQ_EMPTY(&sl->inq));
485                 KKASSERT(RB_EMPTY(&sl->reply_rb_root));
486                 kfree(sl->common, M_SYSLINK);
487                 sl->common = NULL;
488                 kfree(sl, M_SYSLINK);
489         } else {
490                 spin_unlock_wr(&sl->common->spin);
491         }
492 }
493
494 /************************************************************************
495  *                              FILEOPS API                             *
496  ************************************************************************
497  *
498  * Implement userland fileops.
499  *
500  * MPSAFE ops
501  */
502 static
503 int
504 slfileop_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags)
505 {
506         struct sldesc *sl = fp->f_data;         /* fp refed on call */
507         struct slmsg *slmsg;
508         struct iovec *iov0;
509         int error;
510         int nbio;
511
512         /*
513          * Kinda messy.  Figure out the non-blocking state
514          */
515         if (flags & O_FBLOCKING)
516                 nbio = 0;
517         else if (flags & O_FNONBLOCKING)
518                 nbio = 1;
519         else if (fp->f_flag & O_NONBLOCK)
520                 nbio = 1;
521         else
522                 nbio = 0;
523
524         /*
525          * Validate the uio
526          */
527         if (uio->uio_iovcnt < 1) {
528                 error = 0;
529                 goto done2;
530         }
531         iov0 = &uio->uio_iov[0];
532
533         /*
534          * Get a message, blocking if necessary.
535          */
536         spin_lock_wr(&sl->spin);
537         while ((slmsg = TAILQ_FIRST(&sl->inq)) == NULL) {
538                 if (sl->flags & SLF_RSHUTDOWN) {
539                         error = 0;
540                         goto done1;
541                 }
542                 if (nbio) {
543                         error = EAGAIN;
544                         goto done1;
545                 }
546                 ++sl->rwaiters;
547                 error = msleep(&sl->rwaiters, &sl->spin, PCATCH, "slrmsg", 0);
548                 --sl->rwaiters;
549                 if (error)
550                         goto done1;
551         }
552
553         /*
554          * We have a message.  If there isn't enough space, return
555          * ENOSPC without dequeueing it.
556          */
557         if (slmsg->msgsize > iov0->iov_len) {
558                 error = ENOSPC;
559                 goto done1;
560         }
561
562         /*
563          * Dequeue the message.  Adjust repbytes immediately.  cmdbytes
564          * are adjusted when the command is replied to, not here.
565          */
566         TAILQ_REMOVE(&sl->inq, slmsg, tqnode);
567         if (slmsg->msg->sm_proto & SM_PROTO_REPLY)
568                 sl->repbytes -= slmsg->maxsize;
569         spin_unlock_wr(&sl->spin);
570
571         /*
572          * Load the message data into the user buffer and clean up.  We
573          * may have to wakeup blocked writers.
574          */
575         if ((error = uiomove((void *)slmsg->msg, slmsg->msgsize, uio)) == 0) {
576                 /* yip yip */
577         }
578
579         if (slmsg->msg->sm_proto & SM_PROTO_REPLY) {
580                 /*
581                  * Dispose of any received reply after we've copied it
582                  * to userland.  We don't need the slmsg any more.
583                  */
584                 slmsg->flags &= ~SLMSGF_ONINQ;
585                 sl->peer->backend_dispose(sl->peer, slmsg);
586                 if (sl->wblocked && sl->repbytes < syslink_bufsize) {
587                         sl->wblocked = 0;       /* MP race ok here */
588                         wakeup(&sl->wblocked);
589                 }
590         } else if (error) {
591                 /*
592                  * Reply to a command that we failed to copy to userspace.
593                  */
594                 spin_lock_wr(&sl->spin);
595                 RB_REMOVE(slmsg_rb_tree, &sl->reply_rb_root, slmsg);
596                 sl->cmdbytes -= slmsg->maxsize;
597                 spin_unlock_wr(&sl->spin);
598                 slmsg->flags &= ~SLMSGF_ONINQ;
599                 sl->peer->backend_reply(sl->peer, slmsg, NULL);
600                 if (sl->wblocked && sl->cmdbytes < syslink_bufsize) {
601                         sl->wblocked = 0;       /* MP race ok here */
602                         wakeup(&sl->wblocked);
603                 }
604         } else {
605                 /*
606                  * Leave the command in the RB tree but clear ONINQ now
607                  * that we have returned it to userland so userland can
608                  * reply to it.
609                  */
610                 slmsg->flags &= ~SLMSGF_ONINQ;
611         }
612         return(error);
613 done1:
614         spin_unlock_wr(&sl->spin);
615 done2:
616         return(error);
617 }
618
619 /*
620  * Userland writes syslink message
621  */
622 static
623 int
624 slfileop_write(struct file *fp, struct uio *uio, struct ucred *cred, int flags)
625 {
626         struct sldesc *sl = fp->f_data;
627         struct slmsg *slmsg;
628         struct slmsg *slcmd;
629         struct syslink_msg sltmp;
630         struct iovec *iov0;
631         sl_proto_t proto;
632         int nbio;
633         int error;
634
635         /*
636          * Kinda messy.  Figure out the non-blocking state
637          */
638         if (flags & O_FBLOCKING)
639                 nbio = 0;
640         else if (flags & O_FNONBLOCKING)
641                 nbio = 1;
642         else if (fp->f_flag & O_NONBLOCK)
643                 nbio = 1;
644         else
645                 nbio = 0;
646
647         /*
648          * Validate the uio
649          */
650         if (uio->uio_iovcnt < 1) {
651                 error = 0;
652                 goto done2;
653         }
654         iov0 = &uio->uio_iov[0];
655         if (iov0->iov_len > SLMSG_BIG) {
656                 error = EFBIG;
657                 goto done2;
658         }
659
660         /*
661          * Handle the buffer-full case.  slpeer cmdbytes is managed
662          * by the backend function, not us so if the callback just
663          * directly implements the message and never adjusts cmdbytes,
664          * we will never sleep here.
665          */
666         if (sl->flags & SLF_WSHUTDOWN) {
667                 error = EPIPE;
668                 goto done2;
669         }
670
671         /*
672          * Only commands can block the pipe, not replies.  Otherwise a
673          * deadlock is possible.
674          */
675         error = copyin(iov0->iov_base, &sltmp, sizeof(sltmp));
676         if (error)
677                 goto done2;
678         if ((proto = sltmp.sm_proto) & SM_PROTO_ENDIAN_REV)
679                 proto = bswap16(proto);
680         error = sl->peer->backend_wblocked(sl->peer, nbio, proto);
681         if (error)
682                 goto done2;
683
684         /*
685          * Allocate a slmsg and load the message.  Note that the bytes
686          * returned to userland only reflects the primary syslink message
687          * and does not include any DMA buffers.
688          */
689         if (iov0->iov_len <= SLMSG_SMALL)
690                 slmsg = objcache_get(sl_objcache_small, M_WAITOK);
691         else
692                 slmsg = objcache_get(sl_objcache_big, M_WAITOK);
693         slmsg->msgsize = iov0->iov_len;
694
695         error = uiomove((void *)slmsg->msg, iov0->iov_len, uio);
696         if (error)
697                 goto done1;
698         error = syslink_validate_msg(slmsg->msg, slmsg->msgsize);
699         if (error)
700                 goto done1;
701
702         /*
703          * Replies have to be matched up against received commands.
704          */
705         if (slmsg->msg->sm_proto & SM_PROTO_REPLY) {
706                 spin_lock_wr(&sl->spin);
707                 slcmd = slmsg_rb_tree_RB_LOOKUP(&sl->reply_rb_root,
708                                                 slmsg->msg->sm_msgid);
709                 if (slcmd == NULL || (slcmd->flags & SLMSGF_ONINQ)) {
710                         error = ENOENT;
711                         spin_unlock_wr(&sl->spin);
712                         goto done1;
713                 }
714                 RB_REMOVE(slmsg_rb_tree, &sl->reply_rb_root, slcmd);
715                 sl->cmdbytes -= slcmd->maxsize;
716                 spin_unlock_wr(&sl->spin);
717                 sl->peer->backend_reply(sl->peer, slcmd, slmsg);
718                 if (sl->wblocked && sl->cmdbytes < syslink_bufsize) {
719                         sl->wblocked = 0;       /* MP race ok here */
720                         wakeup(&sl->wblocked);
721                 }
722                 /* error is 0 */
723         } else {
724                 error = sl->peer->backend_write(sl->peer, slmsg);
725         }
726 done1:
727         if (error)
728                 objcache_put(slmsg->oc, slmsg);
729 done2:
730         return(error);
731 }
732
733 /*
734  * Close a syslink descriptor.
735  *
736  * Disassociate the syslink from the file descriptor and disconnect from
737  * any peer.
738  */
739 static
740 int
741 slfileop_close(struct file *fp)
742 {
743         struct sldesc *sl;
744
745         /*
746          * Disassociate the file pointer.  Take ownership of the ref on the
747          * sldesc.
748          */
749         sl = fp->f_data;
750         fp->f_data = NULL;
751         fp->f_ops = &badfileops;
752         sl->xfp = NULL;
753
754         /*
755          * Shutdown both directions.  The other side will not issue API
756          * calls to us after we've shutdown both directions.
757          */
758         shutdownsldesc(sl, SHUT_RD|SHUT_WR);
759
760         /*
761          * Cleanup
762          */
763         KKASSERT(sl->cmdbytes == 0);
764         KKASSERT(sl->repbytes == 0);
765         sldrop(sl);
766         return(0);
767 }
768
769 static
770 int
771 slfileop_stat (struct file *fp, struct stat *sb, struct ucred *cred)
772 {
773         return(EINVAL);
774 }
775
776 static
777 int
778 slfileop_shutdown (struct file *fp, int how)
779 {
780         shutdownsldesc((struct sldesc *)fp->f_data, how);
781         return(0);
782 }
783
784 static
785 int
786 slfileop_ioctl (struct file *fp, u_long cmd, caddr_t data, struct ucred *cred)
787 {
788         return(EINVAL);
789 }
790
791 static
792 int
793 slfileop_poll (struct file *fp, int events, struct ucred *cred)
794 {
795         return(0);
796 }
797
798 static
799 int
800 slfileop_kqfilter(struct file *fp, struct knote *kn)
801 {
802         return(0);
803 }
804
805 /************************************************************************
806  *                          MESSAGE VALIDATION                          *
807  ************************************************************************
808  *
809  * Validate that the syslink message.  Check that all headers and elements
810  * conform.  Correct the endian if necessary.
811  *
812  * NOTE: If reverse endian needs to be corrected, SE_CMDF_UNTRANSLATED
813  * is recursively flipped on all syslink_elm's in the message.  As the
814  * message traverses the mesh, multiple flips may occur.  It is
815  * up to the RPC protocol layer to correct opaque data payloads and
816  * SE_CMDF_UNTRANSLATED prevents the protocol layer from misinterpreting
817  * a command or reply element which has not been endian-corrected.
818  */
819 static
820 int
821 syslink_validate_msg(struct syslink_msg *msg, int bytes)
822 {
823         int aligned_reclen;
824         int swapit;
825         int error;
826
827         /*
828          * The raw message must be properly-aligned.
829          */
830         if (bytes & SL_ALIGNMASK)
831                 return (EINVAL);
832
833         while (bytes) {
834                 /*
835                  * The message must at least contain the msgid, bytes, and
836                  * protoid.
837                  */
838                 if (bytes < SL_MIN_PAD_SIZE)
839                         return (EINVAL);
840
841                 /*
842                  * Fix the endian if it is reversed.
843                  */
844                 if (msg->sm_proto & SM_PROTO_ENDIAN_REV) {
845                         msg->sm_msgid = bswap64(msg->sm_msgid);
846                         msg->sm_sessid = bswap64(msg->sm_sessid);
847                         msg->sm_bytes = bswap16(msg->sm_bytes);
848                         msg->sm_proto = bswap16(msg->sm_proto);
849                         msg->sm_rlabel = bswap32(msg->sm_rlabel);
850                         if (msg->sm_proto & SM_PROTO_ENDIAN_REV)
851                                 return (EINVAL);
852                         swapit = 1;
853                 } else {
854                         swapit = 0;
855                 }
856
857                 /*
858                  * Validate the contents.  For PADs, the entire payload is
859                  * ignored and the minimum message size can be as small as
860                  * 8 bytes.
861                  */
862                 if (msg->sm_proto == SMPROTO_PAD) {
863                         if (msg->sm_bytes < SL_MIN_PAD_SIZE ||
864                             msg->sm_bytes > bytes) {
865                                 return (EINVAL);
866                         }
867                         /* ignore the entire payload, it can be garbage */
868                 } else {
869                         if (msg->sm_bytes < SL_MIN_MSG_SIZE ||
870                             msg->sm_bytes > bytes) {
871                                 return (EINVAL);
872                         }
873                         error = syslink_validate_elm(
874                                     &msg->sm_head,
875                                     msg->sm_bytes - 
876                                         offsetof(struct syslink_msg,
877                                                  sm_head),
878                                     swapit, SL_MAXDEPTH);
879                         if (error)
880                                 return (error);
881                 }
882
883                 /*
884                  * The aligned payload size must be used to locate the
885                  * next syslink_msg in the buffer.
886                  */
887                 aligned_reclen = SL_MSG_ALIGN(msg->sm_bytes);
888                 bytes -= aligned_reclen;
889                 msg = (void *)((char *)msg + aligned_reclen);
890         }
891         return(0);
892 }
893
894 static
895 int
896 syslink_validate_elm(struct syslink_elm *elm, sl_reclen_t bytes,
897                      int swapit, int depth)
898 {
899         int aligned_reclen;
900
901         /*
902          * If the buffer isn't big enough to fit the header, stop now!
903          */
904         if (bytes < SL_MIN_ELM_SIZE)
905                 return (EINVAL);
906         /*
907          * All syslink_elm headers are recursively endian-adjusted.  Opaque
908          * data payloads are not.
909          */
910         if (swapit) {
911                 elm->se_cmd = bswap16(elm->se_cmd) ^ SE_CMDF_UNTRANSLATED;
912                 elm->se_bytes = bswap16(elm->se_bytes);
913                 elm->se_aux = bswap32(elm->se_aux);
914         }
915
916         /*
917          * Check element size requirements.
918          */
919         if (elm->se_bytes < SL_MIN_ELM_SIZE || elm->se_bytes > bytes)
920                 return (EINVAL);
921
922         /*
923          * Recursively check structured payloads.  A structured payload may
924          * contain as few as 0 recursive elements.
925          */
926         if (elm->se_cmd & SE_CMDF_STRUCTURED) {
927                 if (depth == 0)
928                         return (EINVAL);
929                 bytes -= SL_MIN_ELM_SIZE;
930                 ++elm;
931                 while (bytes > 0) {
932                         if (syslink_validate_elm(elm, bytes, swapit, depth - 1))
933                                 return (EINVAL);
934                         aligned_reclen = SL_MSG_ALIGN(elm->se_bytes);
935                         elm = (void *)((char *)elm + aligned_reclen);
936                         bytes -= aligned_reclen;
937                 }
938         }
939         return(0);
940 }
941
942 /************************************************************************
943  *                  BACKEND FUNCTIONS - USER DESCRIPTOR                 *
944  ************************************************************************
945  *
946  * Peer backend links are primarily used when userland creates a pair
947  * of linked descriptors.
948  */
949
950 /*
951  * Do any required blocking / nbio handling for attempts to write to
952  * a sldesc associated with a user descriptor.
953  */
954 static
955 int
956 backend_wblocked_user(struct sldesc *sl, int nbio, sl_proto_t proto)
957 {
958         int error = 0;
959         int *bytesp = (proto & SM_PROTO_REPLY) ? &sl->repbytes : &sl->cmdbytes;
960
961         /*
962          * Block until sufficient data is drained by the target.  It is
963          * ok to have a MP race against cmdbytes.
964          */
965         if (*bytesp >= syslink_bufsize) {
966                 spin_lock_wr(&sl->spin);
967                 while (*bytesp >= syslink_bufsize) {
968                         if (sl->flags & SLF_WSHUTDOWN) {
969                                 error = EPIPE;
970                                 break;
971                         }
972                         if (nbio) {
973                                 error = EAGAIN;
974                                 break;
975                         }
976                         ++sl->wblocked;
977                         error = msleep(&sl->wblocked, &sl->spin,
978                                        PCATCH, "slwmsg", 0);
979                         if (error)
980                                 break;
981                 }
982                 spin_unlock_wr(&sl->spin);
983         }
984         return (error);
985 }
986
987 /*
988  * Unconditionally write a syslink message to the sldesc associated with
989  * a user descriptor.  Command messages are also placed in a red-black
990  * tree so their DMA tag (if any) can be accessed and so they can be
991  * linked to any reply message.
992  */
993 static
994 int
995 backend_write_user(struct sldesc *sl, struct slmsg *slmsg)
996 {
997         int error;
998
999         spin_lock_wr(&sl->spin);
1000         if (sl->flags & SLF_RSHUTDOWN) {
1001                 /*
1002                  * Not accepting new messages
1003                  */
1004                 error = EPIPE;
1005         } else if (slmsg->msg->sm_proto & SM_PROTO_REPLY) {
1006                 /*
1007                  * Write a reply
1008                  */
1009                 TAILQ_INSERT_TAIL(&sl->inq, slmsg, tqnode);
1010                 sl->repbytes += slmsg->maxsize;
1011                 slmsg->flags |= SLMSGF_ONINQ;
1012                 error = 0;
1013         } else if (RB_INSERT(slmsg_rb_tree, &sl->reply_rb_root, slmsg)) {
1014                 /*
1015                  * Write a command, but there was a msgid collision when
1016                  * we tried to insert it into the RB tree.
1017                  */
1018                 error = EEXIST;
1019         } else {
1020                 /*
1021                  * Write a command, successful insertion into the RB tree.
1022                  */
1023                 TAILQ_INSERT_TAIL(&sl->inq, slmsg, tqnode);
1024                 sl->cmdbytes += slmsg->maxsize;
1025                 slmsg->flags |= SLMSGF_ONINQ;
1026                 error = 0;
1027         }
1028         spin_unlock_wr(&sl->spin);
1029         if (sl->rwaiters)
1030                 wakeup(&sl->rwaiters);
1031         return(error);
1032 }
1033
1034 /*
1035  * Our peer is replying a command we previously sent it back to us, along
1036  * with the reply message (if not NULL).  We just queue the reply to
1037  * userland and free of the command.
1038  */
1039 static
1040 void
1041 backend_reply_user(struct sldesc *sl, struct slmsg *slcmd, struct slmsg *slrep)
1042 {
1043         int error;
1044
1045         objcache_put(slcmd->oc, slcmd);
1046         if (slrep) {
1047                 spin_lock_wr(&sl->spin);
1048                 if ((sl->flags & SLF_RSHUTDOWN) == 0) {
1049                         TAILQ_INSERT_TAIL(&sl->inq, slrep, tqnode);
1050                         sl->repbytes += slrep->maxsize;
1051                         error = 0;
1052                 } else {
1053                         error = EPIPE;
1054                 }
1055                 spin_unlock_wr(&sl->spin);
1056                 if (error)
1057                         sl->peer->backend_dispose(sl->peer, slrep);
1058                 else if (sl->rwaiters)
1059                         wakeup(&sl->rwaiters);
1060         }
1061 }
1062
1063 static
1064 void
1065 backend_dispose_user(struct sldesc *sl, struct slmsg *slmsg)
1066 {
1067         objcache_put(slmsg->oc, slmsg);
1068 }
1069
1070 /************************************************************************
1071  *                      KERNEL DRIVER OR FILESYSTEM API                 *
1072  ************************************************************************
1073  *
1074  */
1075
1076 /*
1077  * Create a user<->kernel link, returning the user descriptor in *fdp
1078  * and the kernel descriptor in *kslp.  0 is returned on success, and an
1079  * error code is returned on failure.
1080  */
1081 int
1082 syslink_ukbackend(int *fdp, struct sldesc **kslp)
1083 {
1084         struct proc *p = curproc;
1085         struct file *fp;
1086         struct sldesc *usl;
1087         struct sldesc *ksl;
1088         int error;
1089         int fd;
1090
1091         *fdp = -1;
1092         *kslp = NULL;
1093
1094         error = falloc(p, &fp, &fd);
1095         if (error)
1096                 return(error);
1097         usl = allocsldesc(NULL);
1098         usl->backend_wblocked = backend_wblocked_user;
1099         usl->backend_write = backend_write_user;
1100         usl->backend_reply = backend_reply_user;
1101         usl->backend_dispose = backend_dispose_user;
1102
1103         ksl = allocsldesc(usl->common);
1104         ksl->peer = usl;
1105         ksl->backend_wblocked = backend_wblocked_kern;
1106         ksl->backend_write = backend_write_kern;
1107         ksl->backend_reply = backend_reply_kern;
1108         ksl->backend_dispose = backend_dispose_kern;
1109
1110         usl->peer = ksl;
1111
1112         setsldescfp(usl, fp);
1113         fsetfd(p, fp, fd);
1114         fdrop(fp);
1115
1116         *fdp = fd;
1117         *kslp = ksl;
1118         return(0);
1119 }
1120
1121 /*
1122  * Assign a unique message id, issue a syslink message to userland,
1123  * and wait for a reply.
1124  */
1125 int
1126 syslink_kdomsg(struct sldesc *ksl, struct syslink_msg *msg,
1127                struct bio *bio, int flags)
1128 {
1129         struct slmsg slmsg;
1130         int error;
1131
1132         /*
1133          * Finish initializing slmsg and post it to the red-black tree for
1134          * reply matching.  If the message id is already in use we return
1135          * EEXIST, giving the originator the chance to roll a new msgid.
1136          */
1137         bzero(&slmsg, sizeof(slmsg));
1138         slmsg.msg = msg;
1139         slmsg.msgsize = msg->sm_bytes;
1140         slmsg.bio = bio;
1141         if ((error = syslink_validate_msg(slmsg.msg, slmsg.msgsize)) != 0)
1142                 return (error);
1143         msg->sm_msgid = allocsysid();
1144
1145         /*
1146          * Issue the request and wait for a matching reply or failure,
1147          * then remove the message from the matching tree and return.
1148          */
1149         error = ksl->peer->backend_write(ksl->peer, &slmsg);
1150         spin_lock_wr(&ksl->spin);
1151         if (error == 0) {
1152                 while (slmsg.rep == NULL) {
1153                         error = msleep(&slmsg, &ksl->spin, flags, "kwtmsg", 0);
1154                         /* XXX ignore error for now */
1155                 }
1156                 if (slmsg.rep == (struct slmsg *)-1) {
1157                         error = EIO;
1158                 } else {
1159                         error = slmsg.rep->msg->sm_head.se_aux;
1160                         kprintf("reply with error %d\n", error);
1161                         ksl->peer->backend_dispose(ksl->peer, slmsg.rep);
1162                 }
1163         }
1164         spin_unlock_wr(&ksl->spin);
1165         return(error);
1166 }
1167
1168 void
1169 syslink_kshutdown(struct sldesc *ksl, int how)
1170 {
1171         shutdownsldesc(ksl, how);
1172 }
1173
1174 void
1175 syslink_kclose(struct sldesc *ksl)
1176 {
1177         shutdownsldesc(ksl, SHUT_RD|SHUT_WR);
1178         sldrop(ksl);
1179 }
1180
1181 /************************************************************************
1182  *                  BACKEND FUNCTIONS FOR KERNEL API                    *
1183  ************************************************************************
1184  *
1185  * These are the backend functions for a sldesc associated with a kernel
1186  * API.
1187  */
1188
1189 /*
1190  * Our peer wants to write a syslink message to us and is asking us to
1191  * block if our input queue is full.  We don't implement command reception
1192  * so don't block right now.
1193  */
1194 static
1195 int
1196 backend_wblocked_kern(struct sldesc *ksl, int nbio, sl_proto_t proto)
1197 {
1198         /* never blocks */
1199         return(0);
1200 }
1201
1202 /*
1203  * Our peer is writing a request to the kernel.  At the moment we do not
1204  * accept commands.
1205  */
1206 static
1207 int
1208 backend_write_kern(struct sldesc *ksl, struct slmsg *slmsg)
1209 {
1210         return(EOPNOTSUPP);
1211 }
1212
1213 /*
1214  * Our peer wants to reply to a syslink message we sent it earlier.  The
1215  * original command (that we passed to our peer), and the peer's reply
1216  * is specified.  If the peer has failed slrep will be NULL.
1217  */
1218 static
1219 void
1220 backend_reply_kern(struct sldesc *ksl, struct slmsg *slcmd, struct slmsg *slrep)
1221 {
1222         spin_lock_wr(&ksl->spin);
1223         if (slrep == NULL) {
1224                 slcmd->rep = (struct slmsg *)-1;
1225         } else {
1226                 slcmd->rep = slrep;
1227         }
1228         spin_unlock_wr(&ksl->spin);
1229         wakeup(slcmd);
1230 }
1231
1232 /*
1233  * Any reply messages we sent to our peer are returned to us for disposal.
1234  * Since we do not currently accept commands from our peer, there will not
1235  * be any replies returned to the peer to dispose of.
1236  */
1237 static
1238 void
1239 backend_dispose_kern(struct sldesc *ksl, struct slmsg *slmsg)
1240 {
1241         panic("backend_dispose_kern: kernel can't accept commands so it "
1242               "certainly did not reply to one!");
1243 }
1244