akaros/kern/drivers/dev/pipe.c
<<
>>
Prefs
   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 <slab.h>
  30#include <kmalloc.h>
  31#include <kref.h>
  32#include <string.h>
  33#include <stdio.h>
  34#include <assert.h>
  35#include <error.h>
  36#include <cpio.h>
  37#include <pmap.h>
  38#include <smp.h>
  39#include <net/ip.h>
  40
  41struct dev pipedevtab;
  42
  43static char *devname(void)
  44{
  45        return pipedevtab.name;
  46}
  47
  48typedef struct Pipe Pipe;
  49struct Pipe {
  50        qlock_t qlock;
  51        Pipe *next;
  52        struct kref ref;
  53        uint32_t path;
  54        struct queue *q[2];
  55        int qref[2];
  56        struct dirtab *pipedir;
  57        char *user;
  58        struct fdtap_slist data_taps;
  59        spinlock_t tap_lock;
  60};
  61
  62static struct {
  63        spinlock_t lock;
  64        uint32_t path;
  65        int pipeqsize;
  66} pipealloc;
  67
  68enum {
  69        Qdir,
  70        Qctl,
  71        Qdata0,
  72        Qdata1,
  73};
  74
  75static
  76struct dirtab pipedir[] = {
  77        {".", {Qdir, 0, QTDIR}, 0, DMDIR | 0500},
  78        {"ctl", {Qctl}, 0, 0660},
  79        {"data", {Qdata0}, 0, 0660},
  80        {"data1", {Qdata1}, 0, 0660},
  81};
  82
  83static void freepipe(Pipe * p)
  84{
  85        if (p != NULL) {
  86                kfree(p->user);
  87                kfree(p->q[0]);
  88                kfree(p->q[1]);
  89                kfree(p->pipedir);
  90                kfree(p);
  91        }
  92}
  93
  94static void pipe_release(struct kref *kref)
  95{
  96        Pipe *pipe = container_of(kref, Pipe, ref);
  97        freepipe(pipe);
  98}
  99
 100static void pipeinit(void)
 101{
 102        pipealloc.pipeqsize = 32 * 1024;
 103}
 104
 105/*
 106 *  create a pipe, no streams are created until an open
 107 */
 108static struct chan *pipeattach(char *spec)
 109{
 110        ERRSTACK(2);
 111        Pipe *p;
 112        struct chan *c;
 113
 114        c = devattach(devname(), spec);
 115        p = kzmalloc(sizeof(Pipe), 0);
 116        if (p == 0)
 117                error(ENOMEM, ERROR_FIXME);
 118        if (waserror()) {
 119                freepipe(p);
 120                nexterror();
 121        }
 122        p->pipedir = kzmalloc(sizeof(pipedir), 0);
 123        if (p->pipedir == 0)
 124                error(ENOMEM, ERROR_FIXME);
 125        memmove(p->pipedir, pipedir, sizeof(pipedir));
 126        kstrdup(&p->user, current->user.name);
 127        kref_init(&p->ref, pipe_release, 1);
 128        qlock_init(&p->qlock);
 129
 130        p->q[0] = qopen(pipealloc.pipeqsize, Qcoalesce, 0, 0);
 131        if (p->q[0] == 0)
 132                error(ENOMEM, ERROR_FIXME);
 133        p->q[1] = qopen(pipealloc.pipeqsize, Qcoalesce, 0, 0);
 134        if (p->q[1] == 0)
 135                error(ENOMEM, ERROR_FIXME);
 136        poperror();
 137
 138        spin_lock(&(&pipealloc)->lock);
 139        p->path = ++pipealloc.path;
 140        spin_unlock(&(&pipealloc)->lock);
 141
 142        c->qid.path = NETQID(2 * p->path, Qdir);
 143        c->qid.vers = 0;
 144        c->qid.type = QTDIR;
 145        c->aux = p;
 146        c->dev = 0;
 147
 148        /* taps. */
 149        SLIST_INIT(&p->data_taps);      /* already = 0; set to be futureproof */
 150        spinlock_init(&p->tap_lock);
 151        return c;
 152}
 153
 154static int
 155pipegen(struct chan *c, char *unused,
 156                struct dirtab *tab, int ntab, int i, struct dir *dp)
 157{
 158        int id, len;
 159        struct qid qid;
 160        Pipe *p;
 161
 162        if (i == DEVDOTDOT) {
 163                devdir(c, c->qid, devname(), 0, eve.name, 0555, dp);
 164                return 1;
 165        }
 166        i++;    /* skip . */
 167        if (tab == 0 || i >= ntab)
 168                return -1;
 169        tab += i;
 170        p = c->aux;
 171        switch (NETTYPE(tab->qid.path)) {
 172                case Qdata0:
 173                        len = qlen(p->q[0]);
 174                        break;
 175                case Qdata1:
 176                        len = qlen(p->q[1]);
 177                        break;
 178                default:
 179                        len = tab->length;
 180                        break;
 181        }
 182        id = NETID(c->qid.path);
 183        qid.path = NETQID(id, tab->qid.path);
 184        qid.vers = 0;
 185        qid.type = QTFILE;
 186        devdir(c, qid, tab->name, len, eve.name, tab->perm, dp);
 187        return 1;
 188}
 189
 190static struct walkqid *pipewalk(struct chan *c, struct chan *nc, char **name,
 191                                unsigned int nname)
 192{
 193        struct walkqid *wq;
 194        Pipe *p;
 195
 196        p = c->aux;
 197        wq = devwalk(c, nc, name, nname, p->pipedir, ARRAY_SIZE(pipedir),
 198                     pipegen);
 199        if (wq != NULL && wq->clone != NULL && wq->clone != c) {
 200                qlock(&p->qlock);
 201                kref_get(&p->ref, 1);
 202                if (c->flag & COPEN) {
 203                        switch (NETTYPE(c->qid.path)) {
 204                                case Qdata0:
 205                                        p->qref[0]++;
 206                                        break;
 207                                case Qdata1:
 208                                        p->qref[1]++;
 209                                        break;
 210                        }
 211                }
 212                qunlock(&p->qlock);
 213        }
 214        return wq;
 215}
 216
 217static size_t pipestat(struct chan *c, uint8_t *db, size_t n)
 218{
 219        Pipe *p;
 220        struct dir dir;
 221        struct dirtab *tab;
 222        int perm;
 223        int type = NETTYPE(c->qid.path);
 224
 225        p = c->aux;
 226        tab = p->pipedir;
 227
 228        switch (type) {
 229        case Qdir:
 230        case Qctl:
 231                devdir(c, c->qid, tab[type].name, tab[type].length, eve.name,
 232                       tab[type].perm, &dir);
 233                break;
 234        case Qdata0:
 235                perm = tab[1].perm;
 236                perm |= qreadable(p->q[0]) ? DMREADABLE : 0;
 237                perm |= qwritable(p->q[1]) ? DMWRITABLE : 0;
 238                devdir(c, c->qid, tab[1].name, qlen(p->q[0]), eve.name, perm,
 239                       &dir);
 240                break;
 241        case Qdata1:
 242                perm = tab[2].perm;
 243                perm |= qreadable(p->q[1]) ? DMREADABLE : 0;
 244                perm |= qwritable(p->q[0]) ? DMWRITABLE : 0;
 245                devdir(c, c->qid, tab[2].name, qlen(p->q[1]), eve.name, perm,
 246                       &dir);
 247                break;
 248        default:
 249                panic("pipestat");
 250        }
 251        n = convD2M(&dir, db, n);
 252        if (n < BIT16SZ)
 253                error(ENODATA, ERROR_FIXME);
 254        return n;
 255}
 256
 257/*
 258 *  if the stream doesn't exist, create it
 259 */
 260static struct chan *pipeopen(struct chan *c, int omode)
 261{
 262        ERRSTACK(2);
 263        Pipe *p;
 264
 265        if (c->qid.type & QTDIR) {
 266                if (omode & O_WRITE)
 267                        error(EINVAL,
 268                              "Can only open directories O_READ, mode is %o oct",
 269                              omode);
 270                c->mode = openmode(omode);
 271                c->flag |= COPEN;
 272                c->offset = 0;
 273                return c;
 274        }
 275
 276        openmode(omode);        /* check it */
 277
 278        p = c->aux;
 279        qlock(&p->qlock);
 280        if (waserror()) {
 281                qunlock(&p->qlock);
 282                nexterror();
 283        }
 284        switch (NETTYPE(c->qid.path)) {
 285        case Qdata0:
 286                devpermcheck(p->user, p->pipedir[1].perm, omode);
 287                p->qref[0]++;
 288                break;
 289        case Qdata1:
 290                devpermcheck(p->user, p->pipedir[2].perm, omode);
 291                p->qref[1]++;
 292                break;
 293        }
 294        poperror();
 295        qunlock(&p->qlock);
 296
 297        c->mode = openmode(omode);
 298        c->flag |= COPEN;
 299        c->offset = 0;
 300        c->iounit = qiomaxatomic;
 301        return c;
 302}
 303
 304static void pipeclose(struct chan *c)
 305{
 306        Pipe *p;
 307
 308        p = c->aux;
 309        qlock(&p->qlock);
 310
 311        if (c->flag & COPEN) {
 312                /*
 313                 *  closing either side hangs up the stream
 314                 */
 315                switch (NETTYPE(c->qid.path)) {
 316                case Qdata0:
 317                        p->qref[0]--;
 318                        if (p->qref[0] == 0) {
 319                                qhangup(p->q[1], 0);
 320                                qclose(p->q[0]);
 321                        }
 322                        break;
 323                case Qdata1:
 324                        p->qref[1]--;
 325                        if (p->qref[1] == 0) {
 326                                qhangup(p->q[0], 0);
 327                                qclose(p->q[1]);
 328                        }
 329                        break;
 330                }
 331        }
 332
 333        /*
 334         *  if both sides are closed, they are reusable
 335         */
 336        if (p->qref[0] == 0 && p->qref[1] == 0) {
 337                qreopen(p->q[0]);
 338                qreopen(p->q[1]);
 339        }
 340
 341        qunlock(&p->qlock);
 342        /*
 343         *  free the structure on last close
 344         */
 345        kref_put(&p->ref);
 346}
 347
 348static size_t piperead(struct chan *c, void *va, size_t n, off64_t offset)
 349{
 350        Pipe *p;
 351
 352        p = c->aux;
 353
 354        switch (NETTYPE(c->qid.path)) {
 355        case Qdir:
 356                return devdirread(c, va, n, p->pipedir, ARRAY_SIZE(pipedir),
 357                                                  pipegen);
 358        case Qctl:
 359                return readnum(offset, va, n, p->path, NUMSIZE32);
 360        case Qdata0:
 361                if (c->flag & O_NONBLOCK)
 362                        return qread_nonblock(p->q[0], va, n);
 363                else
 364                        return qread(p->q[0], va, n);
 365        case Qdata1:
 366                if (c->flag & O_NONBLOCK)
 367                        return qread_nonblock(p->q[1], va, n);
 368                else
 369                        return qread(p->q[1], va, n);
 370        default:
 371                panic("piperead");
 372        }
 373        return -1;      /* not reached */
 374}
 375
 376static struct block *pipebread(struct chan *c, size_t n, off64_t offset)
 377{
 378        Pipe *p;
 379
 380        p = c->aux;
 381
 382        switch (NETTYPE(c->qid.path)) {
 383        case Qdata0:
 384                if (c->flag & O_NONBLOCK)
 385                        return qbread_nonblock(p->q[0], n);
 386                else
 387                        return qbread(p->q[0], n);
 388        case Qdata1:
 389                if (c->flag & O_NONBLOCK)
 390                        return qbread_nonblock(p->q[1], n);
 391                else
 392                        return qbread(p->q[1], n);
 393        }
 394
 395        return devbread(c, n, offset);
 396}
 397
 398/*
 399 *  A write to a closed pipe causes an EPIPE error to be thrown.
 400 */
 401static size_t pipewrite(struct chan *c, void *va, size_t n, off64_t ignored)
 402{
 403        ERRSTACK(1);
 404        Pipe *p;
 405        struct cmdbuf *cb;
 406
 407        p = c->aux;
 408
 409        switch (NETTYPE(c->qid.path)) {
 410        case Qctl:
 411                cb = parsecmd(va, n);
 412                if (waserror()) {
 413                        kfree(cb);
 414                        nexterror();
 415                }
 416                if (cb->nf < 1)
 417                        error(EFAIL, "short control request");
 418                if (strcmp(cb->f[0], "oneblock") == 0) {
 419                        q_toggle_qmsg(p->q[0], TRUE);
 420                        q_toggle_qcoalesce(p->q[0], TRUE);
 421                        q_toggle_qmsg(p->q[1], TRUE);
 422                        q_toggle_qcoalesce(p->q[1], TRUE);
 423                } else {
 424                        error(EFAIL, "unknown control request");
 425                }
 426                kfree(cb);
 427                poperror();
 428                break;
 429
 430        case Qdata0:
 431                if (c->flag & O_NONBLOCK)
 432                        n = qwrite_nonblock(p->q[1], va, n);
 433                else
 434                        n = qwrite(p->q[1], va, n);
 435                break;
 436
 437        case Qdata1:
 438                if (c->flag & O_NONBLOCK)
 439                        n = qwrite_nonblock(p->q[0], va, n);
 440                else
 441                        n = qwrite(p->q[0], va, n);
 442                break;
 443
 444        default:
 445                panic("pipewrite");
 446        }
 447
 448        return n;
 449}
 450
 451static size_t pipebwrite(struct chan *c, struct block *bp, off64_t offset)
 452{
 453        long n;
 454        Pipe *p;
 455        //Prog *r;
 456
 457        p = c->aux;
 458        switch (NETTYPE(c->qid.path)) {
 459        case Qctl:
 460                return devbwrite(c, bp, offset);
 461        case Qdata0:
 462                if (c->flag & O_NONBLOCK)
 463                        n = qbwrite_nonblock(p->q[1], bp);
 464                else
 465                        n = qbwrite(p->q[1], bp);
 466                break;
 467
 468        case Qdata1:
 469                if (c->flag & O_NONBLOCK)
 470                        n = qbwrite_nonblock(p->q[0], bp);
 471                else
 472                        n = qbwrite(p->q[0], bp);
 473                break;
 474
 475        default:
 476                n = 0;
 477                panic("pipebwrite");
 478        }
 479
 480        return n;
 481}
 482
 483static size_t pipewstat(struct chan *c, uint8_t *dp, size_t n)
 484{
 485        ERRSTACK(2);
 486        struct dir *d;
 487        Pipe *p;
 488        int d1;
 489
 490        if (c->qid.type & QTDIR)
 491                error(EPERM, ERROR_FIXME);
 492        p = c->aux;
 493        if (strcmp(current->user.name, p->user) != 0)
 494                error(EPERM, ERROR_FIXME);
 495        d = kzmalloc(sizeof(*d) + n, 0);
 496        if (waserror()) {
 497                kfree(d);
 498                nexterror();
 499        }
 500        n = convM2D(dp, n, d, (char *)&d[1]);
 501        if (n == 0)
 502                error(ENODATA, ERROR_FIXME);
 503        d1 = NETTYPE(c->qid.path) == Qdata1;
 504        if (!emptystr(d->name)) {
 505                validwstatname(d->name);
 506                if (strlen(d->name) >= KNAMELEN)
 507                        error(ENAMETOOLONG, ERROR_FIXME);
 508                if (strncmp(p->pipedir[1 + !d1].name, d->name, KNAMELEN) == 0)
 509                        error(EEXIST, ERROR_FIXME);
 510                strlcpy(p->pipedir[1 + d1].name, d->name, KNAMELEN);
 511        }
 512        if (d->mode != -1)
 513                p->pipedir[d1 + 1].perm = d->mode & 0777;
 514        poperror();
 515        kfree(d);
 516        return n;
 517}
 518
 519static char *pipechaninfo(struct chan *chan, char *ret, size_t ret_l)
 520{
 521        Pipe *p = chan->aux;
 522
 523        switch (NETTYPE(chan->qid.path)) {
 524        case Qdir:
 525                snprintf(ret, ret_l, "Qdir, ID %d", p->path);
 526                break;
 527        case Qctl:
 528                snprintf(ret, ret_l, "Qctl, ID %d", p->path);
 529                break;
 530        case Qdata0:
 531                snprintf(ret, ret_l,
 532                         "Qdata%d, ID %d, %s, rq len %d, wq len %d, total read %llu",
 533                         0, p->path,
 534                         SLIST_EMPTY(&p->data_taps) ? "untapped" : "tapped",
 535                         qlen(p->q[0]),
 536                         qlen(p->q[1]), q_bytes_read(p->q[0]));
 537                break;
 538        case Qdata1:
 539                snprintf(ret, ret_l,
 540                         "Qdata%d, ID %d, %s, rq len %d, wq len %d, total read %llu",
 541                         1, p->path,
 542                         SLIST_EMPTY(&p->data_taps) ? "untapped" : "tapped",
 543                         qlen(p->q[1]),
 544                         qlen(p->q[0]), q_bytes_read(p->q[1]));
 545                break;
 546        default:
 547                ret = "Unknown type";
 548                break;
 549        }
 550        return ret;
 551}
 552
 553/* We pass the pipe as data.  The pipe will outlive any potential qio callbacks.
 554 * Meaning, we don't need to worry about the pipe disappearing if we're in here.
 555 * If we're in here, then the q exists, which means the pipe exists.
 556 *
 557 * However, the chans do not necessarily exist.  The taps keep the chans around.
 558 * So we only know which chan we're firing when we look at an individual tap. */
 559static void pipe_wake_cb(struct queue *q, void *data, int filter)
 560{
 561        Pipe *p = (Pipe*)data;
 562        struct fd_tap *tap_i;
 563        struct chan *chan;
 564
 565        spin_lock(&p->tap_lock);
 566        SLIST_FOREACH(tap_i, &p->data_taps, link) {
 567                chan = tap_i->chan;
 568                /* Depending which chan did the tapping, we'll care about
 569                 * different filters on different qs.  For instance, if we
 570                 * tapped Qdata0, then we only care about readables on q[0],
 571                 * writables on q[1], and hangups on either.  More precisely, we
 572                 * don't care about writables on q[0] or readables on q[1].
 573                 *
 574                 * Note the *tap's* filter might differ from the CB's filter.
 575                 * The CB could be for read|write|hangup on q[1], with a Qdata0
 576                 * tap for just read.  We don't want to just pass the CB filt
 577                 * directly to fire_tap, since that would pass the CB's read on
 578                 * q[1] to the tap and fire.  The user would think q[0] was
 579                 * readable.  This is why I mask out the CB filter events that
 580                 * we know they don't want. */
 581                switch (NETTYPE(chan->qid.path)) {
 582                case Qdata0:
 583                        if (q == p->q[0])
 584                                filter &= ~FDTAP_FILT_WRITABLE;
 585                        else
 586                                filter &= ~FDTAP_FILT_READABLE;
 587                        break;
 588                case Qdata1:
 589                        if (q == p->q[1])
 590                                filter &= ~FDTAP_FILT_WRITABLE;
 591                        else
 592                                filter &= ~FDTAP_FILT_READABLE;
 593                        break;
 594                default:
 595                        panic("Shouldn't be able to tap pipe qid %p",
 596                              chan->qid.path);
 597                }
 598                fire_tap(tap_i, filter);
 599        }
 600        spin_unlock(&p->tap_lock);
 601}
 602
 603static int pipetapfd(struct chan *chan, struct fd_tap *tap, int cmd)
 604{
 605        int ret;
 606        Pipe *p;
 607
 608        p = chan->aux;
 609#define DEVPIPE_LEGAL_DATA_TAPS (FDTAP_FILT_READABLE | FDTAP_FILT_WRITABLE | \
 610                                 FDTAP_FILT_HANGUP | FDTAP_FILT_ERROR)
 611
 612        switch (NETTYPE(chan->qid.path)) {
 613        case Qdata0:
 614        case Qdata1:
 615                if (tap->filter & ~DEVPIPE_LEGAL_DATA_TAPS) {
 616                        set_errno(ENOSYS);
 617                        set_errstr("Unsupported #%s data tap %p, must be %p",
 618                                   devname(), tap->filter,
 619                                   DEVPIPE_LEGAL_DATA_TAPS);
 620                        return -1;
 621                }
 622                spin_lock(&p->tap_lock);
 623                switch (cmd) {
 624                case (FDTAP_CMD_ADD):
 625                        if (SLIST_EMPTY(&p->data_taps)) {
 626                                qio_set_wake_cb(p->q[0], pipe_wake_cb, p);
 627                                qio_set_wake_cb(p->q[1], pipe_wake_cb, p);
 628                        }
 629                        SLIST_INSERT_HEAD(&p->data_taps, tap, link);
 630                        ret = 0;
 631                        break;
 632                case (FDTAP_CMD_REM):
 633                        SLIST_REMOVE(&p->data_taps, tap, fd_tap, link);
 634                        if (SLIST_EMPTY(&p->data_taps)) {
 635                                qio_set_wake_cb(p->q[0], 0, p);
 636                                qio_set_wake_cb(p->q[1], 0, p);
 637                        }
 638                        ret = 0;
 639                        break;
 640                default:
 641                        set_errno(ENOSYS);
 642                        set_errstr("Unsupported #%s data tap command %p",
 643                                   devname(), cmd);
 644                        ret = -1;
 645                }
 646                spin_unlock(&p->tap_lock);
 647                return ret;
 648        default:
 649                set_errno(ENOSYS);
 650                set_errstr("Can't tap #%s file type %d", devname(),
 651                           NETTYPE(chan->qid.path));
 652                return -1;
 653        }
 654}
 655
 656static unsigned long pipe_chan_ctl(struct chan *c, int op, unsigned long a1,
 657                                   unsigned long a2, unsigned long a3,
 658                                   unsigned long a4)
 659{
 660        switch (op) {
 661        case CCTL_SET_FL:
 662                return 0;
 663        default:
 664                error(EINVAL, "%s does not support %d", __func__, op);
 665        }
 666}
 667
 668struct dev pipedevtab __devtab = {
 669        .name = "pipe",
 670
 671        .reset = devreset,
 672        .init = pipeinit,
 673        .shutdown = devshutdown,
 674        .attach = pipeattach,
 675        .walk = pipewalk,
 676        .stat = pipestat,
 677        .open = pipeopen,
 678        .create = devcreate,
 679        .close = pipeclose,
 680        .read = piperead,
 681        .bread = pipebread,
 682        .write = pipewrite,
 683        .bwrite = pipebwrite,
 684        .remove = devremove,
 685        .wstat = pipewstat,
 686        .power = devpower,
 687        .chaninfo = pipechaninfo,
 688        .tapfd = pipetapfd,
 689        .chan_ctl = pipe_chan_ctl,
 690};
 691