Encapsulate block metadata better
[akaros.git] / kern / src / ns / dev.c
index d819506..7012b5a 100644 (file)
@@ -1,4 +1,31 @@
-// INFERNO
+/* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+ * Portions Copyright © 1997-1999 Vita Nuova Limited
+ * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
+ *                                (www.vitanuova.com)
+ * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+ *
+ * Modified for the Akaros operating system:
+ * Copyright (c) 2013-2014 The Regents of the University of California
+ * Copyright (c) 2013-2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. */
+
 #include <vfs.h>
 #include <kfs.h>
 #include <slab.h>
 #include <cpio.h>
 #include <pmap.h>
 #include <smp.h>
-#include <ip.h>
+#include <net/ip.h>
 
 extern uint32_t kerndate;
-extern char *eve;
+extern struct username eve;
 
 void mkqid(struct qid *q, int64_t path, uint32_t vers, int type)
 {
@@ -53,33 +80,48 @@ devdir(struct chan *c, struct qid qid, char *n,
        db->mtime = kerndate;
        db->length = length;
        db->uid = user;
-       db->gid = eve;
+       db->gid = eve.name;
        db->muid = user;
 }
 
 /*
- * the zeroth element of the table MUST be the directory itself for ..
- * Any entry with qid vers of -1 will return 0, indicating that the value is
- * valid but there is nothing there continue walk.
- * TODO(gvdl): Update akaros devgen man page.
-*/
+ * The zeroth element of the table MUST be the directory itself, or '.' (dot),
+ * for processing '..' (dot-dot). Specifically, if i==DEVDOTDOT, we call devdir
+ * on the *directory* (that is, dot), as opposed to children of the directory.
+ * The rest of the system assumes that the first entry in the table refers to
+ * the directory, and by convention this is named '.' (dot). This is confusing.
+ *
+ * Any entry with qid verion of -1 will return 0, indicating that the value is
+ * valid but there is nothing there, so continue walking.
+ *
+ * TODO(cross): Document devgen and clean this mess up. Devgen should probably
+ * be removed and replaced with a smarter data structure.
+ *
+ * Keep in mind that the expected behavior of gen functions that interoperate
+ * with dev functions (e.g. devdirread()) is that files are directly genned, but
+ * not directories.  Directories will fail to gen, and devstat() just makes
+ * something up.  See also:
+ * https://github.com/brho/plan9/blob/89d43d2262ad43eb4b26c2a8d6a27cfeddb33828/nix/sys/src/nix/port/dev.c#L74
+ *
+ * The comment about genning a file's siblings needs a grain of salt too.  Look
+ * through ipgen().  I think it's what I call "direct genning." */
 int
-devgen(struct chan *c, char *unused_char_p_t, struct dirtab *tab, int ntab,
-          int i, struct dir *dp)
+devgen(struct chan *c, char *unused_name, struct dirtab *tab, int ntab,
+       int i, struct dir *dp)
 {
-       if (tab == 0)
+       if (tab == NULL)
                return -1;
        if (i != DEVDOTDOT) {
-               /* skip over the first element, that for . itself */
+               /* Skip over the first element, that for the directory itself. */
                i++;
-               if (i >= ntab)
+               if (i < 0 || ntab <= i)
                        return -1;
                tab += i;
        }
-       int ret = (tab->qid.vers == -1)? 0 : 1;
-       if (ret)
-               devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
-       return ret;
+       if (tab->qid.vers == -1)
+               return 0;
+       devdir(c, tab->qid, tab->name, tab->length, eve.name, tab->perm, dp);
+       return 1;
 }
 
 void devreset(void)
@@ -107,7 +149,7 @@ struct chan *devattach(const char *name, char *spec)
                spec = "";
        /* 1 for #, 1 for ., 1 for \0 */
        buflen = strlen(name) + strlen(spec) + 3;
-       buf = kzmalloc(buflen, KMALLOC_WAIT);
+       buf = kzmalloc(buflen, MEM_WAIT);
        snprintf(buf, sizeof(buf), "#%s.%s", name, spec);
        c->name = newcname(buf);
        kfree(buf);
@@ -164,7 +206,7 @@ struct walkqid *devwalk(struct chan *c,
 
        alloc = 0;
        wq = kzmalloc(sizeof(struct walkqid) + nname * sizeof(struct qid),
-                                 KMALLOC_WAIT);
+                                 MEM_WAIT);
        if (waserror()) {
                if (alloc && wq->clone != NULL)
                        cclose(wq->clone);
@@ -185,7 +227,7 @@ struct walkqid *devwalk(struct chan *c,
        for (j = 0; j < nname; j++) {
                if (!(nc->qid.type & QTDIR)) {
                        if (j == 0)
-                               error(ENOTDIR, NULL);
+                               error(ENOTDIR, ERROR_FIXME);
                        goto Done;
                }
                n = name[j];
@@ -217,8 +259,10 @@ Accept:
                                                   c->qid.path);
 Notfound:
                                        if (j == 0)
-                                               error(ENOENT, NULL);
-                                       set_error(ENOENT, NULL);
+                                               error(ENOENT, "could not find name %s, dev %s", n,
+                                                     c->type == -1 ? "no dev" : devtab[c->type].name);
+                                       /* TODO: I think we don't need to just set_error here */
+                                       set_error(ENOENT, "tell brho you saw this in an error");
                                        goto Done;
                                case 0:
                                        printd("DEVWALK continue, i was %d\n", i);
@@ -253,6 +297,18 @@ Done:
        return wq;
 }
 
+/* Helper, makes a stat in @dp, given @n bytes, from chan @c's contents in @dir.
+ * Throws on error, returns the size used on success. */
+size_t dev_make_stat(struct chan *c, struct dir *dir, uint8_t *dp, size_t n)
+{
+       if (c->flag & CMSG)
+               dir->mode |= DMMOUNT;
+       n = convD2M(dir, dp, n);
+       if (n == 0)
+               error(EINVAL, ERROR_FIXME);
+       return n;
+}
+
 int
 devstat(struct chan *c, uint8_t * db, int n,
                struct dirtab *tab, int ntab, Devgen * gen)
@@ -275,29 +331,23 @@ devstat(struct chan *c, uint8_t * db, int n,
                                                for (elem = p = c->name->s; *p; p++)
                                                        if (*p == '/')
                                                                elem = p + 1;
-                                       devdir(c, c->qid, elem, 0, eve, DMDIR | 0555, &dir);
+                                       devdir(c, c->qid, elem, 0, eve.name, DMDIR | 0555, &dir);
                                        n = convD2M(&dir, db, n);
                                        if (n == 0)
-                                               error(EINVAL, NULL);
+                                               error(EINVAL, ERROR_FIXME);
                                        return n;
                                }
                                printd("DEVSTAT fails:%s %llu\n", devtab[c->type].name,
                                           c->qid.path);
-                               error(ENOENT, NULL);
+                               error(ENOENT, ERROR_FIXME);
                        case 0:
                                printd("DEVSTAT got 0\n");
                                break;
                        case 1:
                                printd("DEVSTAT gen returns path %p name %s, want path %p\n",
                                           dir.qid.path, dir.name, c->qid.path);
-                               if (c->qid.path == dir.qid.path) {
-                                       if (c->flag & CMSG)
-                                               dir.mode |= DMMOUNT;
-                                       n = convD2M(&dir, db, n);
-                                       if (n == 0)
-                                               error(EINVAL, NULL);
-                                       return n;
-                               }
+                               if (c->qid.path == dir.qid.path)
+                                       return dev_make_stat(c, &dir, db, n);
                                break;
                }
 }
@@ -328,7 +378,7 @@ devdirread(struct chan *c, char *d, long n,
                                dsz = convD2M(&dir[0], (uint8_t *) d, n - m);
                                if (dsz <= BIT16SZ) {   /* <= not < because this isn't stat; read is stuck */
                                        if (m == 0)
-                                               error(ENODATA, NULL);
+                                               error(ENODATA, ERROR_FIXME);
                                        return m;
                                }
                                m += dsz;
@@ -341,16 +391,18 @@ devdirread(struct chan *c, char *d, long n,
 }
 
 /*
- * error(EPERM, NULL) if open permission not granted for up->env->user.
+ * error(EPERM, ERROR_FIXME) if open permission not granted for
+ * current->user.name
  */
 void devpermcheck(char *fileuid, uint32_t perm, int omode)
 {
        int rwx;
+
        /* select user, group, or other from the traditional rwxrwxrwx, shifting
         * into the upper-most position */
-       if (strcmp(current->user, fileuid) == 0)
+       if (strcmp(current->user.name, fileuid) == 0)
                perm <<= 0;
-       else if (strcmp(current->user, eve) == 0)
+       else if (iseve())
                perm <<= 3;
        else
                perm <<= 6;
@@ -395,7 +447,7 @@ Return:
 void
 devcreate(struct chan *c, char *unused_char_p_t, int unused_int, uint32_t u)
 {
-       error(EPERM, NULL);
+       error(EPERM, ERROR_FIXME);
 }
 
 struct block *devbread(struct chan *c, long n, uint32_t offset)
@@ -403,9 +455,9 @@ struct block *devbread(struct chan *c, long n, uint32_t offset)
        ERRSTACK(1);
        struct block *bp;
 
-       bp = allocb(n);
+       bp = block_alloc(n, MEM_WAIT);
        if (bp == 0)
-               error(ENOMEM, NULL);
+               error(ENOMEM, ERROR_FIXME);
        if (waserror()) {
                freeb(bp);
                nexterror();
@@ -433,24 +485,24 @@ long devbwrite(struct chan *c, struct block *bp, uint32_t offset)
 
 void devremove(struct chan *c)
 {
-       error(EPERM, NULL);
+       error(EPERM, ERROR_FIXME);
 }
 
 int devwstat(struct chan *c, uint8_t * unused_uint8_p_t, int i)
 {
-       error(EPERM, NULL);
+       error(EPERM, ERROR_FIXME);
        return 0;
 }
 
 void devpower(int i)
 {
-       error(EPERM, NULL);
+       error(EPERM, ERROR_FIXME);
 }
 
 #if 0
 int devconfig(int unused_int, char *c, DevConf *)
 {
-       error(EPERM, NULL);
+       error(EPERM, ERROR_FIXME);
        return 0;
 }
 #endif
@@ -469,7 +521,7 @@ void validwstatname(char *name)
 {
        validname(name, 0);
        if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
-               error(EINVAL, NULL);
+               error(EINVAL, ERROR_FIXME);
 }
 
 struct dev *devbyname(char *name)