Add the Inferno license to files we got from Inferno
[akaros.git] / kern / drivers / dev / pipe.c
1 /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
2  * Portions Copyright © 1997-1999 Vita Nuova Limited
3  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
4  *                                (www.vitanuova.com)
5  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
6  *
7  * Modified for the Akaros operating system:
8  * Copyright (c) 2013-2014 The Regents of the University of California
9  * Copyright (c) 2013-2015 Google Inc.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE. */
28
29 #include <vfs.h>
30 #include <kfs.h>
31 #include <slab.h>
32 #include <kmalloc.h>
33 #include <kref.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <assert.h>
37 #include <error.h>
38 #include <cpio.h>
39 #include <pmap.h>
40 #include <smp.h>
41 #include <ip.h>
42
43 struct dev pipedevtab;
44
45 static char *devname(void)
46 {
47         return pipedevtab.name;
48 }
49
50 typedef struct Pipe Pipe;
51 struct Pipe {
52         qlock_t qlock;
53         Pipe *next;
54         struct kref ref;
55         uint32_t path;
56         struct queue *q[2];
57         int qref[2];
58         struct dirtab *pipedir;
59         char *user;
60 };
61
62 static struct {
63         spinlock_t lock;
64         uint32_t path;
65         int pipeqsize;
66 } pipealloc;
67
68 enum {
69         Qdir,
70         Qdata0,
71         Qdata1,
72 };
73
74 static
75 struct dirtab pipedir[] = {
76         {".", {Qdir, 0, QTDIR}, 0, DMDIR | 0500},
77         {"data", {Qdata0}, 0, 0660},
78         {"data1", {Qdata1}, 0, 0660},
79 };
80
81 static void freepipe(Pipe * p)
82 {
83         if (p != NULL) {
84                 kfree(p->user);
85                 kfree(p->q[0]);
86                 kfree(p->q[1]);
87                 kfree(p->pipedir);
88                 kfree(p);
89         }
90 }
91
92 static void pipe_release(struct kref *kref)
93 {
94         Pipe *pipe = container_of(kref, Pipe, ref);
95         freepipe(pipe);
96 }
97
98 static void pipeinit(void)
99 {
100         pipealloc.pipeqsize = 32 * 1024;
101 }
102
103 /*
104  *  create a pipe, no streams are created until an open
105  */
106 static struct chan *pipeattach(char *spec)
107 {
108         ERRSTACK(2);
109         Pipe *p;
110         struct chan *c;
111
112         c = devattach(devname(), spec);
113         p = kzmalloc(sizeof(Pipe), 0);
114         if (p == 0)
115                 error(ENOMEM, NULL);
116         if (waserror()) {
117                 freepipe(p);
118                 nexterror();
119         }
120         p->pipedir = kzmalloc(sizeof(pipedir), 0);
121         if (p->pipedir == 0)
122                 error(ENOMEM, NULL);
123         memmove(p->pipedir, pipedir, sizeof(pipedir));
124         kstrdup(&p->user, current->user);
125         kref_init(&p->ref, pipe_release, 1);
126         qlock_init(&p->qlock);
127
128         p->q[0] = qopen(pipealloc.pipeqsize, Qcoalesce, 0, 0);
129         if (p->q[0] == 0)
130                 error(ENOMEM, NULL);
131         p->q[1] = qopen(pipealloc.pipeqsize, Qcoalesce, 0, 0);
132         if (p->q[1] == 0)
133                 error(ENOMEM, NULL);
134         poperror();
135
136         spin_lock(&(&pipealloc)->lock);
137         p->path = ++pipealloc.path;
138         spin_unlock(&(&pipealloc)->lock);
139
140         c->qid.path = NETQID(2 * p->path, Qdir);
141         c->qid.vers = 0;
142         c->qid.type = QTDIR;
143         c->aux = p;
144         c->dev = 0;
145         return c;
146 }
147
148 static int
149 pipegen(struct chan *c, char *unused,
150                 struct dirtab *tab, int ntab, int i, struct dir *dp)
151 {
152         int id, len;
153         struct qid qid;
154         Pipe *p;
155
156         if (i == DEVDOTDOT) {
157                 devdir(c, c->qid, devname(), 0, eve, 0555, dp);
158                 return 1;
159         }
160         i++;    /* skip . */
161         if (tab == 0 || i >= ntab)
162                 return -1;
163         tab += i;
164         p = c->aux;
165         switch (NETTYPE(tab->qid.path)) {
166                 case Qdata0:
167                         len = qlen(p->q[0]);
168                         break;
169                 case Qdata1:
170                         len = qlen(p->q[1]);
171                         break;
172                 default:
173                         len = tab->length;
174                         break;
175         }
176         id = NETID(c->qid.path);
177         qid.path = NETQID(id, tab->qid.path);
178         qid.vers = 0;
179         qid.type = QTFILE;
180         devdir(c, qid, tab->name, len, eve, tab->perm, dp);
181         return 1;
182 }
183
184 static struct walkqid *pipewalk(struct chan *c, struct chan *nc, char **name,
185                                                                 int nname)
186 {
187         struct walkqid *wq;
188         Pipe *p;
189
190         p = c->aux;
191         wq = devwalk(c, nc, name, nname, p->pipedir, ARRAY_SIZE(pipedir), pipegen);
192         if (wq != NULL && wq->clone != NULL && wq->clone != c) {
193                 qlock(&p->qlock);
194                 kref_get(&p->ref, 1);
195                 if (c->flag & COPEN) {
196                         switch (NETTYPE(c->qid.path)) {
197                                 case Qdata0:
198                                         p->qref[0]++;
199                                         break;
200                                 case Qdata1:
201                                         p->qref[1]++;
202                                         break;
203                         }
204                 }
205                 qunlock(&p->qlock);
206         }
207         return wq;
208 }
209
210 static int pipestat(struct chan *c, uint8_t * db, int n)
211 {
212         Pipe *p;
213         struct dir dir;
214         struct dirtab *tab;
215
216         p = c->aux;
217         tab = p->pipedir;
218
219         switch (NETTYPE(c->qid.path)) {
220                 case Qdir:
221                         devdir(c, c->qid, ".", 0, eve, DMDIR | 0555, &dir);
222                         break;
223                 case Qdata0:
224                         devdir(c, c->qid, tab[1].name, qlen(p->q[0]), eve, tab[1].perm,
225                                    &dir);
226                         break;
227                 case Qdata1:
228                         devdir(c, c->qid, tab[2].name, qlen(p->q[1]), eve, tab[2].perm,
229                                    &dir);
230                         break;
231                 default:
232                         panic("pipestat");
233         }
234         n = convD2M(&dir, db, n);
235         if (n < BIT16SZ)
236                 error(ENODATA, NULL);
237         return n;
238 }
239
240 /*
241  *  if the stream doesn't exist, create it
242  */
243 static struct chan *pipeopen(struct chan *c, int omode)
244 {
245         ERRSTACK(2);
246         Pipe *p;
247
248         if (c->qid.type & QTDIR) {
249                 if (omode & O_WRITE)
250                         error(EINVAL, "Can only open directories O_READ, mode is %o oct",
251                                   omode);
252                 c->mode = openmode(omode);
253                 c->flag |= COPEN;
254                 c->offset = 0;
255                 return c;
256         }
257
258         openmode(omode);        /* check it */
259
260         p = c->aux;
261         qlock(&p->qlock);
262         if (waserror()) {
263                 qunlock(&p->qlock);
264                 nexterror();
265         }
266         switch (NETTYPE(c->qid.path)) {
267                 case Qdata0:
268                         devpermcheck(p->user, p->pipedir[1].perm, omode);
269                         p->qref[0]++;
270                         break;
271                 case Qdata1:
272                         devpermcheck(p->user, p->pipedir[2].perm, omode);
273                         p->qref[1]++;
274                         break;
275         }
276         poperror();
277         qunlock(&p->qlock);
278
279         c->mode = openmode(omode);
280         c->flag |= COPEN;
281         c->offset = 0;
282         c->iounit = qiomaxatomic;
283         return c;
284 }
285
286 static void pipeclose(struct chan *c)
287 {
288         Pipe *p;
289
290         p = c->aux;
291         qlock(&p->qlock);
292
293         if (c->flag & COPEN) {
294                 /*
295                  *  closing either side hangs up the stream
296                  */
297                 switch (NETTYPE(c->qid.path)) {
298                         case Qdata0:
299                                 p->qref[0]--;
300                                 if (p->qref[0] == 0) {
301                                         qhangup(p->q[1], 0);
302                                         qclose(p->q[0]);
303                                 }
304                                 break;
305                         case Qdata1:
306                                 p->qref[1]--;
307                                 if (p->qref[1] == 0) {
308                                         qhangup(p->q[0], 0);
309                                         qclose(p->q[1]);
310                                 }
311                                 break;
312                 }
313         }
314
315         /*
316          *  if both sides are closed, they are reusable
317          */
318         if (p->qref[0] == 0 && p->qref[1] == 0) {
319                 qreopen(p->q[0]);
320                 qreopen(p->q[1]);
321         }
322
323         qunlock(&p->qlock);
324         /*
325          *  free the structure on last close
326          */
327         kref_put(&p->ref);
328 }
329
330 static long piperead(struct chan *c, void *va, long n, int64_t ignored)
331 {
332         Pipe *p;
333
334         p = c->aux;
335
336         switch (NETTYPE(c->qid.path)) {
337                 case Qdir:
338                         return devdirread(c, va, n, p->pipedir, ARRAY_SIZE(pipedir),
339                                                           pipegen);
340                 case Qdata0:
341                         return qread(p->q[0], va, n);
342                 case Qdata1:
343                         return qread(p->q[1], va, n);
344                 default:
345                         panic("piperead");
346         }
347         return -1;      /* not reached */
348 }
349
350 static struct block *pipebread(struct chan *c, long n, uint32_t offset)
351 {
352         Pipe *p;
353
354         p = c->aux;
355
356         switch (NETTYPE(c->qid.path)) {
357                 case Qdata0:
358                         return qbread(p->q[0], n);
359                 case Qdata1:
360                         return qbread(p->q[1], n);
361         }
362
363         return devbread(c, n, offset);
364 }
365
366 /*
367  *  a write to a closed pipe causes an exception to be sent to
368  *  the prog.
369  */
370 static long pipewrite(struct chan *c, void *va, long n, int64_t ignored)
371 {
372         ERRSTACK(2);
373         Pipe *p;
374         //Prog *r;
375
376         if (waserror()) {
377                 /* avoid exceptions when pipe is a mounted queue */
378                 if ((c->flag & CMSG) == 0) {
379 /*
380                         r = up->iprog;
381                         if(r != NULL && r->kill == NULL)
382                                 r->kill = "write on closed pipe";
383 */
384                 }
385                 nexterror();
386         }
387
388         p = c->aux;
389
390         switch (NETTYPE(c->qid.path)) {
391                 case Qdata0:
392                         n = qwrite(p->q[1], va, n);
393                         break;
394
395                 case Qdata1:
396                         n = qwrite(p->q[0], va, n);
397                         break;
398
399                 default:
400                         panic("pipewrite");
401         }
402
403         poperror();
404         return n;
405 }
406
407 static long pipebwrite(struct chan *c, struct block *bp, uint32_t junk)
408 {
409         ERRSTACK(2);
410         long n;
411         Pipe *p;
412         //Prog *r;
413
414         if (waserror()) {
415                 /* avoid exceptions when pipe is a mounted queue */
416 /*
417                 if((c->flag & CMSG) == 0) {
418                         r = up->iprog;
419                         if(r != NULL && r->kill == NULL)
420                                 r->kill = "write on closed pipe";
421                 }
422 */
423                 nexterror();
424         }
425
426         p = c->aux;
427         switch (NETTYPE(c->qid.path)) {
428                 case Qdata0:
429                         n = qbwrite(p->q[1], bp);
430                         break;
431
432                 case Qdata1:
433                         n = qbwrite(p->q[0], bp);
434                         break;
435
436                 default:
437                         n = 0;
438                         panic("pipebwrite");
439         }
440
441         poperror();
442         return n;
443 }
444
445 static int pipewstat(struct chan *c, uint8_t * dp, int n)
446 {
447         ERRSTACK(2);
448         struct dir *d;
449         Pipe *p;
450         int d1;
451
452         if (c->qid.type & QTDIR)
453                 error(EPERM, NULL);
454         p = c->aux;
455         if (strcmp(current->user, p->user) != 0)
456                 error(EPERM, NULL);
457         d = kzmalloc(sizeof(*d) + n, 0);
458         if (waserror()) {
459                 kfree(d);
460                 nexterror();
461         }
462         n = convM2D(dp, n, d, (char *)&d[1]);
463         if (n == 0)
464                 error(ENODATA, NULL);
465         d1 = NETTYPE(c->qid.path) == Qdata1;
466         if (!emptystr(d->name)) {
467                 validwstatname(d->name);
468                 if (strlen(d->name) >= KNAMELEN)
469                         error(ENAMETOOLONG, NULL);
470                 if (strcmp(p->pipedir[1 + !d1].name, d->name) == 0)
471                         error(EEXIST, NULL);
472                 strncpy(p->pipedir[1 + d1].name, d->name,
473                                 MIN(KNAMELEN, sizeof(p->pipedir[1 + d1].name, d->name)));
474         }
475         if (d->mode != ~0UL)
476                 p->pipedir[d1 + 1].perm = d->mode & 0777;
477         poperror();
478         kfree(d);
479         return n;
480 }
481
482 struct dev pipedevtab __devtab = {
483         "pipe",
484
485         devreset,
486         pipeinit,
487         devshutdown,
488         pipeattach,
489         pipewalk,
490         pipestat,
491         pipeopen,
492         devcreate,
493         pipeclose,
494         piperead,
495         pipebread,
496         pipewrite,
497         pipebwrite,
498         devremove,
499         pipewstat,
500         devpower,
501         devchaninfo,
502 };