the style(9) ... brrrr :-) 

On Fri, May 30, 2014 at 08:48:11PM -0500, strake...@gmail.com wrote:
> One can actually read a file now! Yay!
> 
> I have another patch to allocate each message buffer from a pool as needed 
> rather than share one among all requests, but I'm not sure that it makes 
> sense to do so, as all requests go thru the same channel anyhow.
> 
> diff --git a/sbin/mount_9p/mount_9p.c b/sbin/mount_9p/mount_9p.c
> new file mode 100644
> index 0000000..418f1f7
> --- /dev/null
> +++ b/sbin/mount_9p/mount_9p.c
> @@ -0,0 +1,18 @@
> +#include <sys/param.h>
> +#include <sys/mount.h>
> +#include <stdio.h>
> +#include <err.h>
> +
> +int
> +main (int argc, char *argu[])
> +{
> +     struct p9p_args args;
> +     int c;
> +
> +     if (argc < 3) errx (1, "usage: %s fd path", argu[0]);
> +     args.fd = strtol (argu[1], 0, 10);
> +     args.msize = 1 << 20;
> +     c = mount (MOUNT_P9P, argu[2], 0, &args);
> +     if (c) err (1, "failed to mount");
> +     return 0;
> +}
> diff --git a/sys/9p/9p.c b/sys/9p/9p.c
> new file mode 100644
> index 0000000..37c5ebd
> --- /dev/null
> +++ b/sys/9p/9p.c
> @@ -0,0 +1,251 @@
> +#include <sys/param.h>
> +#include <sys/malloc.h>
> +#include <sys/systm.h>
> +#include <sys/file.h>
> +#include "9p.h"
> +#include "util.h"
> +
> +int read9pmsg (struct file *fp, uint8_t *msg, size_t n) {
> +     ssize_t size;
> +     int c;
> +
> +     if (n < 7) return EMSGSIZE;
> +     c = read (fp, msg, 7);
> +     if (c) return c;
> +     LOAD32LE(size, msg);
> +     if (size < 7) return EIO;
> +     switch (msg[4] /* type */) {
> +     // Special case for TWrite and RRead, lest we copy huge data
> +     case RRead:
> +             size = 11;
> +             break;
> +     case TWrite:
> +             size = 23;
> +             break;
> +     }
> +     if (n < size) return EMSGSIZE;
> +     return read (fp, msg + 7, size - 7);
> +}
> +
> +int write9pmsg (struct file *fp, uint8_t *msg) {
> +     size_t size;
> +
> +     LOAD32LE(size, msg);
> +     switch (msg[4] /* type */) {
> +     case RRead:
> +             size = 11;
> +             break;
> +     case TWrite:
> +             size = 23;
> +             break;
> +     }
> +     return write (fp, msg, size);
> +}
> +
> +size_t loadQid (Qid *p_qid, uint8_t *msg) {
> +     p_qid -> type = msg[0];
> +     LOAD32LE(p_qid -> vers, msg + 1);
> +     LOAD64LE(p_qid -> path, msg + 5);
> +     return 13;
> +}
> +
> +size_t storQid (Qid *p_qid, uint8_t *msg) {
> +     msg[0] = p_qid -> type;
> +     STOR32LE(p_qid -> vers, msg + 1);
> +     STOR64LE(p_qid -> path, msg + 5);
> +     return 13;
> +}
> +
> +static size_t vsscan9p1 (uint8_t *msg, char fmt, void *p) {
> +     size_t l;
> +     switch (fmt) {
> +     case '0':
> +             *(uint8_t *)p = msg[0];
> +             return 1;
> +     case '1':
> +             LOAD16LE(*(uint16_t *)p, msg);
> +             return 2;
> +     case '2':
> +             LOAD32LE(*(uint32_t *)p, msg);
> +             return 4;
> +     case '3':
> +             LOAD64LE(*(uint64_t *)p, msg);
> +             return 8;
> +     case 'd':
> +             return loadDir (p, msg);
> +     case 'q':
> +             return loadQid (p, msg);
> +     case 's':
> +             LOAD16LE(l, msg);
> +             *(char **)p = malloc (l + 1, M_TEMP, M_WAITOK);
> +             strlcpy (*(char **)p, msg + 2, l + 1);
> +             return (2 + l);
> +     default:
> +             panic ("bad 9p message format spec");
> +     }
> +}
> +
> +static size_t vsprint9p1 (uint8_t *msg, char fmt, void *p) {
> +     size_t l;
> +     char *xs;
> +     switch (fmt) {
> +     case '0':
> +             if (msg) msg[0] = *(uint8_t *)p;
> +             return 1;
> +     case '1':
> +             if (msg) STOR16LE(*(uint16_t *)p, msg);
> +             return 2;
> +     case '2':
> +             if (msg) STOR32LE(*(uint32_t *)p, msg);
> +             return 4;
> +     case '3':
> +             if (msg) STOR64LE(*(uint64_t *)p, msg);
> +             return 8;
> +     case 'd':
> +             return storDir (p, msg);
> +     case 'q':
> +             return (msg ? storQid (p, msg) : 13);
> +     case 's':
> +             xs = *(char **)p;
> +             l = xs ? strlen (xs) : 0;
> +             if (msg) {
> +                     STOR16LE(l, msg);
> +                     if (xs) memcpy (msg + 2, xs, l);
> +             }
> +             return (2 + l);
> +     default:
> +             panic ("bad 9p message format spec");
> +     }
> +}
> +
> +#define ATOFFSET(t, p, r) (*(t *)((uint8_t *)(p) + r))
> +
> +static size_t vsscan9p (uint8_t *msg, char *fmt, void *p, size_t rs[]) {
> +     size_t n;
> +     uint8_t *q, *msg0;
> +     msg0 = msg;
> +     for (; fmt[0]; fmt++, rs++) switch (fmt[0]) {
> +     case 'l':
> +             msg += 2;
> +             rs--;
> +             break;
> +     case 'n':
> +             LOAD16LE(n, msg);
> +             msg += 2;
> +             ATOFFSET(uint16_t, p, rs[0]) = n;
> +             fmt++;
> +             rs++;
> +             q = malloc (sizeof (void *)*n, M_TEMP, M_WAITOK);
> +             ATOFFSET(void *, p, rs[0]) = q;
> +             for (size_t ii = 0; ii < n; ii++) {
> +                     size_t m = vsscan9p1 (msg, fmt[0], q);
> +                     msg += m;
> +                     q += fmt[0] == 's' ? sizeof (void *) : m;
> +             }
> +             break;
> +     default:
> +             msg += vsscan9p1 (msg, fmt[0], (uint8_t *)p + rs[0]);
> +     }
> +     return msg - msg0;
> +}
> +
> +static size_t vsprint9p (uint8_t *msg, char *fmt, void *p, size_t rs[]) {
> +     size_t n;
> +     uint8_t *q, *msg0;
> +     msg0 = msg;
> +     for (; fmt[0]; fmt++, rs++) switch (fmt[0]) {
> +     case 'l':
> +             n = vsprint9p (0, fmt + 1, p, rs);
> +             if (msg0) STOR16LE(n, msg);
> +             msg += 2;
> +             rs--;
> +             break;
> +     case 'n':
> +             n = ATOFFSET(uint16_t, p, rs[0]);
> +             if (msg0) STOR16LE(n, msg);
> +             msg += 2;
> +             fmt++;
> +             rs++;
> +             q = ATOFFSET(void *, p, rs[0]);
> +             for (size_t ii = 0; ii < n; ii++) {
> +                     size_t m = vsprint9p1 (msg0 ? msg : 0, fmt[0], q);
> +                     msg += m;
> +                     q += fmt[0] == 's' ? sizeof (void *) : m;
> +             }
> +             break;
> +     default:
> +             msg += vsprint9p1 (msg0 ? msg : 0, fmt[0], (uint8_t *)p + 
> rs[0]);
> +     }
> +     return msg - msg0;
> +}
> +
> +static void *fmts[][2] = {
> +     [TVersion]      = { "2s",       (size_t []){ offsetof (Fcall, msize), 
> offsetof (Fcall, version) } },
> +     [RVersion]      = { "2s",       (size_t []){ offsetof (Fcall, msize), 
> offsetof (Fcall, version) } },
> +     [TAuth]         = { "2ss",      (size_t []){ offsetof (Fcall, afid), 
> offsetof (Fcall, uname), offsetof (Fcall, aname) } },
> +     [RAuth]         = { "q",        (size_t []){ offsetof (Fcall, aqid) } },
> +     [TError]        = { 0 }, // invalid
> +     [RError]        = { "s",        (size_t []){ offsetof (Fcall, ename) } 
> },
> +     [TFlush]        = { "1",        (size_t []){ offsetof (Fcall, oldtag) } 
> },
> +     [RFlush]        = { "",         (size_t []){} },
> +     [TAttach]       = { "22ss",     (size_t []){ offsetof (Fcall, fid), 
> offsetof (Fcall, afid), offsetof (Fcall, uname), offsetof (Fcall, aname) } },
> +     [RAttach]       = { "q",        (size_t []){ offsetof (Fcall, qid) } },
> +     [TWalk]         = { "22ns",     (size_t []){ offsetof (Fcall, fid), 
> offsetof (Fcall, newfid), offsetof (Fcall, nwname), offsetof (Fcall, wname) } 
> },
> +     [RWalk]         = { "nq",       (size_t []){ offsetof (Fcall, nwqid), 
> offsetof (Fcall, wqid) } },
> +     [TOpen]         = { "20",       (size_t []){ offsetof (Fcall, fid), 
> offsetof (Fcall, mode) } },
> +     [ROpen]         = { "q2",       (size_t []){ offsetof (Fcall, qid), 
> offsetof (Fcall, iounit) } },
> +     [TCreate]       = { "2s20",     (size_t []){ offsetof (Fcall, fid), 
> offsetof (Fcall, name), offsetof (Fcall, perm), offsetof (Fcall, mode) } },
> +     [RCreate]       = { "q2",       (size_t []){ offsetof (Fcall, qid), 
> offsetof (Fcall, iounit) } },
> +     [TRead]         = { "232",      (size_t []){ offsetof (Fcall, fid), 
> offsetof (Fcall, offset), offsetof (Fcall, count) } },
> +     [RRead]         = { "2",        (size_t []){ offsetof (Fcall, count) } 
> },
> +     [TWrite]        = { "232",      (size_t []){ offsetof (Fcall, fid), 
> offsetof (Fcall, offset), offsetof (Fcall, count) } },
> +     [RWrite]        = { "2",        (size_t []){ offsetof (Fcall, count) } 
> },
> +     [TClunk]        = { "2",        (size_t []){ offsetof (Fcall, fid) } },
> +     [RClunk]        = { "",         (size_t []){} },
> +     [TRemove]       = { "2",        (size_t []){ offsetof (Fcall, fid) } },
> +     [RRemove]       = { "",         (size_t []){} },
> +     [TStat]         = { "2",        (size_t []){ offsetof (Fcall, fid) } },
> +     [RStat]         = { "ld",       (size_t []){ offsetof (Fcall, st) } },
> +     [TWStat]        = { "2ld",      (size_t []){ offsetof (Fcall, fid), 
> offsetof (Fcall, st) } },
> +     [RWStat]        = { "",         (size_t []){} },
> +};
> +
> +ssize_t loadFcall (Fcall *p_fcall, uint8_t *msg) {
> +     p_fcall -> type = msg[4];
> +     LOAD16LE(p_fcall -> tag, msg + 5);
> +     if (msg[4] < P9PMIN || msg[4] > P9PMAX || !fmts[msg[4]][1]) return (-1);
> +     return (vsscan9p (msg + 7, fmts[p_fcall -> type][0], p_fcall, 
> fmts[p_fcall -> type][1]) + 7);
> +}
> +
> +ssize_t storFcall (Fcall *p_fcall, uint8_t *msg) {
> +     size_t size;
> +     size = vsprint9p (msg ? msg + 7 : 0, fmts[p_fcall -> type][0], p_fcall, 
> fmts[p_fcall -> type][1]) + 7;
> +     if (msg) {
> +             msg[4] = p_fcall -> type;
> +             STOR16LE(p_fcall -> tag, msg + 5);
> +             STOR32LE(size + (msg[4] == RRead ? p_fcall -> count : 0), msg);
> +     }
> +     return size;
> +}
> +
> +static
> +size_t goDir (Dir *p_d, uint8_t *msg, int w) {
> +     size_t l = (w ? vsprint9p : vsscan9p) (msg ? msg + 2 : 0, 
> "12q2223ssss", p_d, (size_t []){ offsetof (Dir, type), offsetof (Dir, dev), 
> offsetof (Dir, qid), offsetof (Dir, mode), offsetof (Dir, atime), offsetof 
> (Dir, mtime), offsetof (Dir, length), offsetof (Dir, name), offsetof (Dir, 
> uid), offsetof (Dir, gid), offsetof (Dir, muid) }) + 2;
> +     if (msg) STOR16LE(l, msg);
> +     return l + 2;
> +}
> +
> +size_t loadDir (Dir *p_d, uint8_t *msg) {
> +     return goDir (p_d, msg, 0);
> +}
> +
> +size_t storDir (Dir *p_d, uint8_t *msg) {
> +     return goDir (p_d, msg, 1);
> +}
> +
> +void freeDir (Dir *p_d) {
> +     free (p_d -> name, M_TEMP);
> +     free (p_d -> uid,  M_TEMP);
> +     free (p_d -> gid,  M_TEMP);
> +     free (p_d -> muid, M_TEMP);
> +}
> diff --git a/sys/9p/9p.h b/sys/9p/9p.h
> new file mode 100644
> index 0000000..7e0978a
> --- /dev/null
> +++ b/sys/9p/9p.h
> @@ -0,0 +1,171 @@
> +/* Copyright ?2006-2010 Kris Maglione <maglione.k at Gmail>
> + * See LICENSE file for license details.
> + */
> +
> +/* 9P message types */
> +enum {
> +     P9PMIN          = 0x64,
> +     TVersion        = 0x64,
> +     RVersion,
> +     TAuth           = 0x66,
> +     RAuth,
> +     TAttach         = 0x68,
> +     RAttach,
> +     TError          = 0x6A, /* illegal */
> +     RError,
> +     TFlush          = 0x6C,
> +     RFlush,
> +     TWalk           = 0x6E,
> +     RWalk,
> +     TOpen           = 0x70,
> +     ROpen,
> +     TCreate         = 0x72,
> +     RCreate,
> +     TRead           = 0x74,
> +     RRead,
> +     TWrite          = 0x76,
> +     RWrite,
> +     TClunk          = 0x78,
> +     RClunk,
> +     TRemove         = 0x7A,
> +     RRemove,
> +     TStat           = 0x7C,
> +     RStat,
> +     TWStat          = 0x7E,
> +     RWStat,
> +     P9PMAX          = 0x7F,
> +};
> +
> +/* from libc.h */
> +enum {
> +     OREAD           = 0x0000,       /* open for read */
> +     OWRITE          = 0x0001,       /* write */
> +     ORDWR           = 0x0002,       /* read and write */
> +     OEXEC           = 0x0003,       /* execute, == read but check execute 
> permission */
> +     OTRUNC          = 0x0010,       /* or'ed in (except for exec), truncate 
> file first */
> +     OCEXEC          = 0x0020,       /* or'ed in, close on exec */
> +     ORCLOSE         = 0x0040,       /* or'ed in, remove on close */
> +     ODIRECT         = 0x0080,       /* or'ed in, direct access */
> +     ONONBLOCK       = 0x0100,       /* or'ed in, non-blocking call */
> +     OEXCL           = 0x1000,       /* or'ed in, exclusive use (create 
> only) */
> +     OLOCK           = 0x2000,       /* or'ed in, lock after opening */
> +     OAPPEND         = 0x4000        /* or'ed in, append only */
> +};
> +
> +/* bits in Qid.type */
> +enum {
> +     QTDIR           = 0x80, /* type bit for directories */
> +     QTAPPEND        = 0x40, /* type bit for append only files */
> +     QTEXCL          = 0x20, /* type bit for exclusive use files */
> +     QTMOUNT         = 0x10, /* type bit for mounted channel */
> +     QTAUTH          = 0x08, /* type bit for authentication file */
> +     QTTMP           = 0x04, /* type bit for non-backed-up file */
> +     QTSYMLINK       = 0x02, /* type bit for symbolic link */
> +     QTFILE          = 0x00  /* type bits for plain file */
> +};
> +
> +/* bits in Stat.mode */
> +enum {
> +     DMEXEC  = 0x1,          /* mode bit for execute permission */
> +     DMWRITE = 0x2,          /* mode bit for write permission */
> +     DMREAD  = 0x4,          /* mode bit for read permission */
> +
> +     DMDIR           = 0x80000000,   /* mode bit for directories */
> +     DMAPPEND        = 0x40000000,   /* mode bit for append only files */
> +     DMEXCL          = 0x20000000,   /* mode bit for exclusive use files */
> +     DMMOUNT         = 0x10000000,   /* mode bit for mounted channel */
> +     DMAUTH          = 0x08000000,   /* mode bit for authentication file */
> +     DMTMP           = 0x04000000,   /* mode bit for non-backed-up file */
> +     DMSYMLINK       = 0x02000000,   /* mode bit for symbolic link (Unix, 
> 9P2000.u) */
> +     DMDEVICE        = 0x00800000,   /* mode bit for device file (Unix, 
> 9P2000.u) */
> +     DMNAMEDPIPE     = 0x00200000,   /* mode bit for named pipe (Unix, 
> 9P2000.u) */
> +     DMSOCKET        = 0x00100000,   /* mode bit for socket (Unix, 9P2000.u) 
> */
> +     DMSETUID        = 0x00080000,   /* mode bit for setuid (Unix, 9P2000.u) 
> */
> +     DMSETGID        = 0x00040000,   /* mode bit for setgid (Unix, 9P2000.u) 
> */
> +};
> +
> +
> +typedef struct {
> +     uint8_t         type;
> +     uint32_t        vers;
> +     uint64_t        path;
> +} Qid;
> +
> +typedef struct {
> +     uint16_t        type;
> +     uint32_t        dev;
> +     Qid             qid;
> +     uint32_t        mode;
> +     uint32_t        atime;
> +     uint32_t        mtime;
> +     uint64_t        length;
> +     char*           name;
> +     char*           uid;
> +     char*           gid;
> +     char*           muid;
> +} Dir;
> +
> +/* from fcall(3) in plan9port */
> +typedef struct {
> +     uint8_t type;
> +     uint16_t tag;
> +     uint32_t fid;
> +
> +     union {
> +             struct { /* Tversion, Rversion */
> +                     uint32_t        msize;
> +                     char            *version;
> +             };
> +             struct { /* Tflush */
> +                     uint16_t        oldtag;
> +             };
> +             struct { /* Rerror */
> +                     char            *ename;
> +             };
> +             struct { /* Ropen, Rcreate */
> +                     Qid             qid;    /* +Rattach */
> +                     uint32_t        iounit;
> +             };
> +             struct { /* Rauth */
> +                     Qid             aqid;
> +             };
> +             struct { /* Tauth, Tattach */
> +                     uint32_t        afid;
> +                     char            *uname;
> +                     char            *aname;
> +             };
> +             struct { /* Tcreate */
> +                     uint32_t        perm;
> +                     char            *name;
> +                     uint8_t         mode;   /* +Topen */
> +             };
> +             struct { /* Rwalk */
> +                     uint32_t        newfid; /* +Twalk */
> +                     union {
> +                             uint16_t        nwname;
> +                             uint16_t        nwqid;
> +                     };
> +                     union {
> +                             char            **wname;
> +                             Qid             *wqid;
> +                     };
> +             };
> +             struct {
> +                     uint64_t        offset; /* Tread, Twrite */
> +                     uint32_t        count;  /* Tread, Twrite, Rread */
> +             };
> +             struct { /* Rstat, Twstat */
> +                     Dir             st;
> +             };
> +     };
> +} Fcall;
> +
> +int  read9pmsg (struct file *, uint8_t *, size_t);
> +int write9pmsg (struct file *, uint8_t *);
> +ssize_t loadFcall (Fcall *, uint8_t *);
> +ssize_t storFcall (Fcall *, uint8_t *);
> +size_t loadDir (Dir *, uint8_t *);
> +size_t storDir (Dir *, uint8_t *);
> +size_t loadQid (Qid *, uint8_t *);
> +size_t storQid (Qid *, uint8_t *);
> +void freeDir (Dir *);
> diff --git a/sys/9p/p9p.h b/sys/9p/p9p.h
> new file mode 100644
> index 0000000..568b776
> --- /dev/null
> +++ b/sys/9p/p9p.h
> @@ -0,0 +1,35 @@
> +typedef struct p9p_mount {
> +     struct file *fp;
> +     struct proc *recverp;
> +     size_t msize;
> +     struct rwlock tagLock, fidLock, tfpLock, msgLock, rmsgLock;
> +     Fcall **requs;
> +     uint32_t leastFreeFid;
> +     /* This could be allocated per message, but
> +      * that would impossibilize saving work if
> +      * no memory free.
> +      * We could keep a message buffer per vnode,
> +      * but that would be messy.
> +      */
> +     void *msg;
> +     /* Recv thread having own message buffer lets
> +      * it blockingly recv and not lock up buffer
> +      * for senders.
> +      */
> +     void *rmsg;
> +} p9p_mount_t;
> +
> +typedef struct p9p_node {
> +     uint32_t fid;
> +} p9p_node_t;
> +
> +uint16_t p9p_getTag (p9p_mount_t *, void *);
> +void p9p_putTag (p9p_mount_t *, uint16_t);
> +
> +uint32_t p9p_getFid (p9p_mount_t *);
> +void p9p_putFid (p9p_mount_t *, uint32_t); /* XXX unimpl */
> +
> +int p9p_require (p9p_mount_t *, Fcall *, struct uio *, struct ucred *);
> +
> +extern struct vops p9p_vops;
> +extern const struct vfsops p9p_vfsops;
> diff --git a/sys/9p/p9p_vfsops.c b/sys/9p/p9p_vfsops.c
> new file mode 100644
> index 0000000..c70f25d
> --- /dev/null
> +++ b/sys/9p/p9p_vfsops.c
> @@ -0,0 +1,290 @@
> +#include <sys/param.h>
> +#include <sys/systm.h>
> +#include <sys/malloc.h>
> +#include <sys/kthread.h>
> +#include <sys/mount.h>
> +#include <sys/vnode.h>
> +#include <sys/proc.h>
> +#include <sys/file.h>
> +#include <sys/filedesc.h>
> +#include <sys/signalvar.h>
> +#include "9p.h"
> +#include "p9p.h"
> +#include "util.h"
> +
> +static int
> +p9p_connect (p9p_mount_t *p9mp)
> +{
> +     Fcall fcall;
> +     fcall.type = TVersion;
> +     fcall.tag = ~0;
> +     fcall.msize = p9mp -> msize;
> +     fcall.version = "9P2000";
> +     int c;
> +
> +     rw_enter_write (&p9mp -> msgLock); /* no one else should be using this 
> now, but make sure */
> +     storFcall (&fcall, p9mp -> msg);
> +     rw_enter_write (&p9mp -> tfpLock); /* likewise */
> +     if (!((c = write9pmsg (p9mp -> fp, p9mp -> msg)) ||
> +              (c =  read9pmsg (p9mp -> fp, p9mp -> msg, p9mp -> msize)))) {
> +             if (loadFcall (&fcall, p9mp -> msg) < 0) c = EIO;
> +     }
> +     rw_exit (&p9mp -> tfpLock);
> +     rw_exit (&p9mp -> msgLock);
> +     if (c) return c;
> +     if (fcall.type != RVersion ||
> +         fcall.msize > p9mp -> msize ||
> +         strcmp (fcall.version, "9P2000") != 0) c = EIO;
> +     p9mp -> msize = fcall.msize;
> +     free (fcall.version, M_TEMP);
> +     return c;
> +}
> +
> +static int
> +p9p_disconnect (p9p_mount_t *p9mp)
> +{
> +     return 0;
> +}
> +
> +static void
> +p9p_recver_main (p9p_mount_t *p9mp)
> +{
> +     Fcall fcall, *fcallp;
> +     ssize_t l;
> +     int c;
> +
> +     for (;;) {
> +             rw_enter_write (&p9mp -> rmsgLock);
> +             c = read9pmsg (p9mp -> fp, p9mp -> rmsg, p9mp -> msize);
> +             if (c) kthread_exit (c);
> +             l = loadFcall (&fcall, p9mp -> rmsg);
> +             rw_exit (&p9mp -> rmsgLock);
> +             if (l < 0) {
> +                     fcall.type  = RError;
> +                     fcall.ename = "bad message type";
> +             }
> +             rw_enter_read (&p9mp -> tagLock);
> +             fcallp = p9mp -> requs[fcall.tag];
> +             rw_exit (&p9mp -> tagLock);
> +             if (fcallp) {
> +                     *fcallp = fcall;
> +                     wakeup (fcallp);
> +             }
> +             if (fcallp && fcall.type == RRead) tsleep (&p9mp -> fp, curproc 
> -> p_priority, "9p RRead", 0); /* not clobber read data */
> +     }
> +}
> +
> +static int
> +p9p_mount (struct mount *mp, const char *path, void *data, struct nameidata 
> *ndp, struct proc *p)
> +{
> +     struct p9p_args args;
> +     p9p_mount_t *p9mp;
> +     int c;
> +
> +     if (c = copyin (data, &args, sizeof (struct p9p_args))) return c;
> +
> +     if (mp -> mnt_flag & MNT_UPDATE) return EOPNOTSUPP;
> +
> +     p9mp = malloc (sizeof (p9p_mount_t), M_P9PMNT, M_WAITOK | M_CANFAIL | 
> M_ZERO);
> +     if (!p9mp) {
> +             c = ENOMEM;
> +             goto fail;
> +     }
> +     mp -> mnt_data = p9mp;
> +     p9mp -> msize = args.msize;
> +
> +     p9mp -> requs = malloc (sizeof (Fcall *) << 16, M_TEMP, M_WAITOK | 
> M_CANFAIL);
> +     p9mp -> msg   = malloc (p9mp -> msize,          M_TEMP, M_WAITOK | 
> M_CANFAIL);
> +     p9mp -> rmsg  = malloc (p9mp -> msize,          M_TEMP, M_WAITOK | 
> M_CANFAIL);
> +     if (!(p9mp -> requs && p9mp -> msg && p9mp -> rmsg)) {
> +             c = ENOMEM;
> +             goto fail;
> +     }
> +
> +     rw_init (&p9mp ->  tagLock, 0);
> +     rw_init (&p9mp ->  fidLock, 0);
> +     rw_init (&p9mp ->  tfpLock, 0);
> +     rw_init (&p9mp ->  msgLock, 0);
> +     rw_init (&p9mp -> rmsgLock, 0);
> +
> +     if (!(p9mp -> fp = fd_getfile (p -> p_fd, args.fd))) {
> +             c = EBADF;
> +             goto fail;
> +     }
> +     FREF(p9mp -> fp);
> +#if 0
> +     if ((c = fdrelease (p, args.fd))) goto fail;
> +#endif
> +
> +     vfs_getnewfsid (mp);
> +
> +     if ((c = p9p_connect (p9mp)) ||
> +            (c = kthread_create ((void (*) (void *))p9p_recver_main, p9mp, 
> &p9mp -> recverp, "9p recver"))) goto fail;
> +     return 0;
> +
> +fail:
> +     FRELE(p9mp -> fp, p);
> +     free (p9mp -> requs, M_TEMP);
> +     free (p9mp -> msg,   M_TEMP);
> +     free (p9mp -> rmsg,  M_TEMP);
> +     free (p9mp, M_P9PMNT);
> +     mp -> mnt_data = 0;
> +     return c;
> +}
> +
> +static int
> +p9p_unmount (struct mount *mp, int mntflags, struct proc *p)
> +{
> +     p9p_mount_t *p9mp;
> +     int c, flags = 0;
> +
> +     p9mp = mp -> mnt_data;
> +     KASSERT(p9mp);
> +
> +     if (mntflags & MNT_FORCE) flags |= FORCECLOSE;
> +
> +     if (c = vflush (mp, 0, flags)) return c;
> +
> +     psignal (p9mp -> recverp, SIGKILL);
> +
> +     c = p9p_disconnect (p9mp);
> +
> +     FRELE(p9mp -> fp, p);
> +     free (p9mp -> requs, M_TEMP);
> +     free (p9mp, M_MISCFSMNT);
> +     mp -> mnt_data = 0;
> +     return c;
> +}
> +
> +static int
> +p9p_root (struct mount *mp, struct vnode **vpp)
> +{
> +     Fcall fcall;
> +     p9p_mount_t *p9mp;
> +     p9p_node_t *p9np;
> +     int c;
> +
> +     p9mp = mp -> mnt_data;
> +     KASSERT(p9mp);
> +
> +     p9np = 0;
> +     *vpp = 0;
> +
> +     if (c = getnewvnode (VT_P9P, mp, &p9p_vops, vpp)) return c;
> +
> +     p9np = malloc (sizeof (p9p_node_t), M_P9PNODE, M_WAITOK | M_CANFAIL);
> +     if (!p9np) {
> +             c = ENOMEM;
> +             goto fail;
> +     }
> +     (*vpp) -> v_data = p9np;
> +     fcall.type = TAttach;
> +     fcall.fid = p9np -> fid = p9p_getFid (p9mp);
> +     fcall.afid = ~0;
> +     fcall.uname = "puffy";
> +     fcall.aname = "";
> +
> +     c = p9p_require (p9mp, &fcall, 0, 0);
> +     if (c) return c;
> +     (*vpp) -> v_flag |= VROOT;
> +     (*vpp) -> v_type  = fcall.qid.type & QTDIR ? VDIR : VREG;
> +     return 0;
> +
> +fail:
> +     if (*vpp) vrele (*vpp);
> +     free (p9np, M_P9PNODE);
> +     (*vpp) -> v_data = 0;
> +     return c;
> +}
> +
> +static int
> +p9p_sync (struct mount *mp, int waitfor, struct ucred *cred, struct proc *p)
> +{
> +     p9p_mount_t *p9mp;
> +     int c = 0;
> +
> +     p9mp = mp -> mnt_data;
> +     KASSERT(p9mp);
> +
> +     if (waitfor == MNT_WAIT) for (;;) {
> +             uint16_t tag;
> +             rw_enter_read (&p9mp -> tagLock);
> +             for (tag = 0; ~tag; tag++) if (tag) {
> +                     /* recver will wake us with thread that made request
> +                      * when it recvs response for this tag
> +                      */
> +                     c = tsleep (&p9mp -> requs[tag], p -> p_priority, 
> "sync", 0);
> +                     break;
> +             }
> +             rw_exit (&p9mp -> tagLock);
> +             if (c) return c;
> +             if (!~tag /* found no used tags */) break;
> +             c = 0;
> +     }
> +
> +     return 0;
> +}
> +
> +static int
> +p9p_start (struct mount *mp, int flags, struct proc *p)
> +{
> +     return 0;
> +}
> +
> +static int
> +p9p_quotactl (struct mount *mp, int cmds, uid_t uid, caddr_t arg, struct 
> proc *p)
> +{
> +     return EOPNOTSUPP;
> +}
> +
> +static int
> +p9p_statfs (struct mount *mp, struct statfs *sbp, struct proc *p)
> +{
> +     return EOPNOTSUPP;
> +}
> +
> +static int
> +p9p_vget (struct mount *mp, ino_t ino, struct vnode **vpp)
> +{
> +     return EOPNOTSUPP;
> +}
> +
> +static int
> +p9p_fhtovp (struct mount *mp, struct fid *fhp, struct vnode **vpp)
> +{
> +     return EOPNOTSUPP;
> +}
> +
> +static int
> +p9p_vptofh (struct vnode *vp, struct fid *fhp)
> +{
> +     return EOPNOTSUPP;
> +}
> +
> +static int
> +p9p_init (struct vfsconf *vfsconfp)
> +{
> +     return 0;
> +}
> +
> +static int
> +p9p_checkexp (struct mount *mp, struct mbuf *nam, int *extflagsp, struct 
> ucred **credanonp)
> +{
> +     return EOPNOTSUPP;
> +}
> +
> +const struct vfsops p9p_vfsops = {
> +     .vfs_mount      = p9p_mount,
> +     .vfs_unmount    = p9p_unmount,
> +     .vfs_start      = p9p_start,
> +     .vfs_root       = p9p_root,
> +     .vfs_quotactl   = p9p_quotactl,
> +     .vfs_statfs     = p9p_statfs,
> +     .vfs_sync       = p9p_sync,
> +     .vfs_vget       = p9p_vget,
> +     .vfs_fhtovp     = p9p_fhtovp,
> +     .vfs_vptofh     = p9p_vptofh,
> +     .vfs_init       = p9p_init,
> +     .vfs_sysctl     = 0,
> +     .vfs_checkexp   = p9p_checkexp,
> +};
> diff --git a/sys/9p/p9p_vnops.c b/sys/9p/p9p_vnops.c
> new file mode 100644
> index 0000000..11f7792
> --- /dev/null
> +++ b/sys/9p/p9p_vnops.c
> @@ -0,0 +1,454 @@
> +#include <lib/libkern/libkern.h>
> +#include <sys/param.h>
> +#include <sys/systm.h>
> +#include <sys/malloc.h>
> +#include <sys/rwlock.h>
> +#include <sys/mount.h>
> +#include <sys/vnode.h>
> +#include <sys/namei.h>
> +#include <sys/file.h>
> +#include <sys/stat.h>
> +#include <sys/proc.h>
> +#include <sys/dirent.h>
> +#include "9p.h"
> +#include "p9p.h"
> +
> +/* u9fs seems to limit size of read/written data at msize - 24 */
> +#define P9PHDRSIZE 24
> +
> +uint16_t
> +p9p_getTag (p9p_mount_t *p9mp, void *p)
> +{
> +     uint16_t tag;
> +     for (;;) {
> +             rw_enter_write (&p9mp -> tagLock);
> +             for (tag = 0; ~tag; tag++) if (!p9mp -> requs[tag]) {
> +                     p9mp -> requs[tag] = p;
> +                     break;
> +             }
> +             rw_exit (&p9mp -> tagLock);
> +             if (~tag) return tag;
> +             tsleep (&p9mp -> requs, curproc -> p_priority, "no free tag", 
> 0);
> +     }
> +}
> +
> +void
> +p9p_putTag (p9p_mount_t *p9mp, uint16_t tag)
> +{
> +     rw_enter_write (&p9mp -> tagLock);
> +     p9mp -> requs[tag] = 0;
> +     rw_exit (&p9mp -> tagLock);
> +     wakeup (&p9mp -> requs);
> +}
> +
> +uint32_t
> +p9p_getFid (p9p_mount_t *p9mp)
> +{
> +     uint32_t fid;
> +     for (;;) {
> +             rw_enter_write (&p9mp -> fidLock);
> +             fid = p9mp -> leastFreeFid++;
> +             if (!~fid /* oops! no free fid; rolled over */) p9mp -> 
> leastFreeFid--;
> +             rw_exit (&p9mp -> fidLock);
> +             if (~fid) return fid;
> +             else tsleep (&p9mp -> leastFreeFid, curproc -> p_priority, "no 
> free fid", 0);
> +     }
> +}
> +
> +void
> +p9p_putFid (p9p_mount_t *p9mp, uint32_t fid)
> +{
> +     rw_enter_write (&p9mp -> fidLock);
> +     if (fid + 1 == p9mp -> leastFreeFid) p9mp -> leastFreeFid--;
> +     /* XXX can't put other fid */
> +     rw_exit (&p9mp -> fidLock);
> +     wakeup (&p9mp -> leastFreeFid);
> +}
> +
> +static int
> +fo_rwSome (struct file *fp, off_t *offp, size_t n, struct uio *uiop, struct 
> ucred *credp)
> +{
> +     size_t resid0 = uiop -> uio_resid;
> +     int (*fo_op) (struct file *, off_t *, struct uio *, struct ucred *);
> +     int c = 0;
> +
> +     if (resid0 < n) n = resid0;
> +     uiop -> uio_resid = n;
> +
> +     switch (uiop -> uio_rw) {
> +     case UIO_READ:
> +             fo_op = fp -> f_ops -> fo_read;
> +             break;
> +     case UIO_WRITE:
> +             fo_op = fp -> f_ops -> fo_write;
> +             break;
> +     default:
> +             return EINVAL;
> +     }
> +     while (uiop -> uio_resid > 0) if (c = fo_op (fp, offp, uiop, credp)) 
> break;
> +     uiop -> uio_resid += resid0 - n;
> +     return c;
> +}
> +
> +/* tag, send, and await response; message should not be tagged when calling 
> this */
> +int
> +p9p_require (p9p_mount_t *p9mp, Fcall *fcallp, struct uio *uiop, struct 
> ucred *credp)
> +{
> +     uint16_t tag;
> +     uint8_t type0 = fcallp -> type;
> +     int c;
> +
> +     tag = p9p_getTag (p9mp, fcallp);
> +     fcallp -> tag = tag;
> +     rw_enter_write (&p9mp -> msgLock);
> +     storFcall (fcallp, p9mp -> msg);
> +     /* no sense to drop msgLock exclusion, as no one else wants to read our 
> message anyhow */
> +     rw_enter_write (&p9mp -> tfpLock);
> +     c = write9pmsg (p9mp -> fp, p9mp -> msg);
> +     rw_exit (&p9mp -> msgLock);
> +     if (!c) {
> +             if (fcallp -> type == TWrite || fcallp -> type == RRead) {
> +                     if (uiop -> uio_rw != UIO_WRITE) c = EINVAL;
> +                     else c = fo_rwSome (p9mp -> fp, 0, fcallp -> count, 
> uiop, credp);
> +             }
> +     }
> +     rw_exit (&p9mp -> tfpLock);
> +     if (c) goto end;
> +     if (c = tsleep (fcallp, curproc -> p_priority, "awaiting response", 0)) 
> goto end;
> +     if (fcallp -> tag != tag || fcallp -> type != type0 + 1) c = EIO;
> +end:
> +     p9p_putTag (p9mp, fcallp -> tag);
> +     return c;
> +}
> +
> +static inline uint8_t
> +p9pmode (int fmode)
> +{
> +     uint8_t mode = OFLAGS(fmode) & O_ACCMODE;
> +     if (fmode & O_TRUNC) mode |= 0x10;
> +     return mode;
> +}
> +
> +static inline uint32_t
> +p9pperm (mode_t fperm)
> +{
> +     uint32_t perm = fperm & 0x1F;
> +     if (S_ISDIR(fperm)) perm |= DMDIR;
> +     return perm;
> +}
> +
> +static inline mode_t
> +fperm (uint32_t p9pperm)
> +{
> +     mode_t perm = p9pperm & 0x1F;
> +     if (p9pperm & DMDIR) perm |= S_IFDIR;
> +     return perm;
> +}
> +
> +static int
> +p9p_lookup (struct vop_lookup_args *ap)
> +{
> +     p9p_mount_t *p9mp;
> +     p9p_node_t *p9np, *p9dnp;
> +     Fcall fcall;
> +     char *name;
> +     int c;
> +
> +     p9mp  = ap -> a_dvp -> v_mount -> mnt_data;
> +     p9dnp = ap -> a_dvp -> v_data;
> +     KASSERT(p9mp && p9dnp);
> +
> +     if (c = getnewvnode (VT_P9P, ap -> a_dvp -> v_mount, &p9p_vops, ap -> 
> a_vpp)) return c;
> +
> +     p9np = malloc (sizeof (p9p_node_t), M_P9PNODE, M_WAITOK | M_CANFAIL);
> +     if (!p9np) {
> +             c = ENOMEM;
> +             goto fail;
> +     }
> +
> +     name = malloc (sizeof (char)*(ap -> a_cnp -> cn_namelen + 1), M_TEMP, 
> M_WAITOK | M_CANFAIL);
> +     if (!name) {
> +             c = ENOMEM;
> +             goto fail;
> +     }
> +     strlcpy (name, ap -> a_cnp -> cn_nameptr, ap -> a_cnp -> cn_namelen + 
> 1);
> +
> +     fcall.type = TWalk;
> +     fcall.fid  = p9dnp -> fid;
> +     fcall.newfid = p9np -> fid = p9p_getFid (p9mp);
> +     fcall.nwname = 1;
> +     fcall.wname = &name;
> +     c = p9p_require (p9mp, &fcall, 0, 0);
> +     free (name, M_TEMP);
> +     name = 0;
> +     if (!c && fcall.nwqid == 0) c = EIO;
> +     if (c) goto fail;
> +     (*ap -> a_vpp) -> v_data = p9np;
> +     (*ap -> a_vpp) -> v_type = fcall.wqid[0].type & QTDIR ? VDIR : VREG;
> +     return 0;
> +fail:
> +     free (p9np, M_P9PNODE);
> +     (*ap -> a_vpp) -> v_data = 0;
> +     vrele (*ap -> a_vpp);
> +     *ap -> a_vpp = 0;
> +     return c;
> +}
> +
> +static int
> +p9p_create (struct vop_create_args *ap)
> +{
> +     p9p_mount_t *p9mp;
> +     p9p_node_t *p9np, *p9dnp;
> +     Fcall fcall;
> +     int c;
> +
> +     p9mp  = ap -> a_dvp -> v_mount -> mnt_data;
> +     p9dnp = ap -> a_dvp -> v_data;
> +     KASSERT(p9mp && p9dnp);
> +
> +     if (c = getnewvnode (VT_P9P, ap -> a_dvp -> v_mount, &p9p_vops, ap -> 
> a_vpp)) return c;
> +
> +     p9np = malloc (sizeof (p9p_node_t), M_P9PNODE, M_WAITOK | M_CANFAIL);
> +     if (!p9np) {
> +             c = ENOMEM;
> +             goto fail;
> +     }
> +
> +     fcall.type = TCreate;
> +     fcall.fid  = p9np -> fid = p9dnp -> fid;
> +     fcall.mode = 0;
> +     fcall.perm = p9pperm (ap -> a_vap -> va_mode);
> +     fcall.name = malloc (sizeof (char)*(ap -> a_cnp -> cn_namelen + 1), 
> M_TEMP, M_WAITOK | M_CANFAIL);
> +     if (!fcall.name) {
> +             c = ENOMEM;
> +             goto fail;
> +     }
> +     strlcpy (fcall.name, ap -> a_cnp -> cn_nameptr, ap -> a_cnp -> 
> cn_namelen + 1);
> +     c = p9p_require (p9mp, &fcall, 0, 0);
> +     free (fcall.name, M_TEMP);
> +     fcall.name = 0;
> +     if (c) goto fail;
> +     (*ap -> a_vpp) -> v_data = p9np;
> +     (*ap -> a_vpp) -> v_type = fcall.qid.type & QTDIR ? VDIR : VREG;
> +     free (p9dnp, M_P9PNODE);
> +     ap -> a_dvp -> v_data = 0;
> +     vput (ap -> a_dvp);
> +     return 0;
> +fail:
> +     free (p9np, M_P9PNODE);
> +     (*ap -> a_vpp) -> v_data = 0;
> +     vrele (*ap -> a_vpp);
> +     *ap -> a_vpp = 0;
> +     return c;
> +}
> +
> +static int
> +p9p_remove (struct vop_remove_args *ap)
> +{
> +     Fcall fcall;
> +
> +     fcall.type = TRemove;
> +     fcall.fid = ((p9p_node_t *)ap -> a_vp -> v_data) -> fid;
> +     return p9p_require (ap -> a_vp -> v_mount -> mnt_data, &fcall, 0, 0);
> +}
> +
> +static int
> +p9p_open (struct vop_open_args *ap)
> +{
> +     Fcall fcall;
> +
> +     if (ap -> a_mode & FNONBLOCK) return EWOULDBLOCK;
> +
> +     fcall.type = TOpen;
> +     fcall.fid  = ((p9p_node_t *)ap -> a_vp -> v_data) -> fid;
> +     fcall.mode = p9pmode (ap -> a_mode);
> +     return p9p_require (ap -> a_vp -> v_mount -> mnt_data, &fcall, 0, 0);
> +}
> +
> +static int
> +p9p_close (struct vop_close_args *ap)
> +{
> +     Fcall fcall;
> +
> +     fcall.type = TClunk;
> +     fcall.fid  = ((p9p_node_t *)ap -> a_vp -> v_data) -> fid;
> +     return p9p_require (ap -> a_vp -> v_mount -> mnt_data, &fcall, 0, 0);
> +}
> +
> +static int
> +p9p_rw (struct vop_read_args *ap)
> +{
> +     p9p_mount_t *p9mp;
> +     Fcall fcall;
> +     int c;
> +
> +     p9mp = ap -> a_vp -> v_mount -> mnt_data;
> +     KASSERT(p9mp);
> +
> +     if (ap -> a_ioflag & IO_NDELAY) return EWOULDBLOCK;
> +     if (ap -> a_ioflag & IO_UNIT)   return EOPNOTSUPP;
> +     if (ap -> a_ioflag & IO_APPEND) return EOPNOTSUPP; /* XXX */
> +
> +     switch (ap -> a_uio -> uio_rw) {
> +     case UIO_READ:
> +             fcall.type = TRead;
> +             break;
> +     case UIO_WRITE:
> +             fcall.type = TWrite;
> +             break;
> +     default:
> +             return EINVAL;
> +     }
> +     fcall.fid  = ((p9p_node_t *)ap -> a_vp -> v_data) -> fid;
> +     fcall.offset = ap -> a_uio -> uio_offset;
> +     fcall.count = MIN(ap -> a_uio -> uio_resid, p9mp -> msize - P9PHDRSIZE);
> +     if (c = p9p_require (p9mp, &fcall, ap -> a_uio, ap -> a_cred)) return c;
> +     if (fcall.type == RRead) {
> +             c = fo_rwSome (p9mp -> fp, 0, fcall.count, ap -> a_uio, ap -> 
> a_cred);
> +             wakeup (&p9mp -> fp);
> +     }
> +     return c;
> +}
> +
> +static int
> +p9p_readdir (struct vop_readdir_args *ap)
> +{
> +     p9p_mount_t *p9mp;
> +     Fcall fcall;
> +     struct iovec v;
> +     struct uio uio = {
> +             .uio_iov = 0,
> +             .uio_iovcnt = 0,
> +             .uio_segflg = UIO_SYSSPACE,
> +             .uio_rw = UIO_READ,
> +             .uio_offset = ap -> a_uio -> uio_offset,
> +             .uio_resid = 0,
> +             .uio_procp = curproc,
> +     };
> +     struct dirent dent = {
> +             .d_off = uio.uio_offset,
> +             .d_reclen = sizeof (struct dirent),
> +     };
> +     size_t l;
> +     char *msg;
> +     int c;
> +
> +     p9mp = ap -> a_vp -> v_mount -> mnt_data;
> +     KASSERT(p9mp);
> +
> +     fcall.type = TRead;
> +     fcall.fid  = ((p9p_node_t *)ap -> a_vp -> v_data) -> fid;
> +     fcall.offset = ap -> a_uio -> uio_offset;
> +     fcall.count = p9mp -> msize - P9PHDRSIZE;
> +     if (c = p9p_require (p9mp, &fcall, &uio, ap -> a_cred)) return c;
> +     v.iov_base = p9mp -> rmsg;
> +     v.iov_len  = fcall.count;
> +     uio.uio_iov = &v;
> +     uio.uio_resid = fcall.count;
> +     rw_enter_write (&p9mp -> rmsgLock);
> +     if (c = p9mp -> fp -> f_ops -> fo_read (p9mp -> fp, 0, ap -> a_uio, ap 
> -> a_cred)) goto end;
> +     for (msg = p9mp -> rmsg; msg - (char *)p9mp -> rmsg < fcall.count; msg 
> += l) {
> +             Dir dir;
> +
> +             l = loadDir (&dir, msg);
> +             dent.d_off += l;
> +             dent.d_fileno = dir.qid.path;
> +             dent.d_namlen = MIN(MAXNAMLEN, strlen (dir.name));
> +             if (dir.qid.type & QTDIR) dent.d_type = DT_DIR;
> +             else dent.d_type = DT_REG;
> +             /* could copy name out immediately, but this method simplifies 
> code */
> +             strlcpy (dent.d_name, dir.name, dent.d_namlen + 1);
> +             c = uiomove (&dent, sizeof (struct dirent), ap -> a_uio);
> +             freeDir (&dir);
> +             if (c) goto end;
> +     }
> +end:
> +     rw_exit (&p9mp -> rmsgLock);
> +     wakeup (&p9mp -> fp);
> +     return c;
> +}
> +
> +static int
> +p9p_getattr (struct vop_getattr_args *ap)
> +{
> +     Fcall fcall;
> +     int c;
> +
> +     fcall.type = TStat;
> +     fcall.fid  = ((p9p_node_t *)ap -> a_vp -> v_data) -> fid;
> +     if (c = p9p_require (ap -> a_vp -> v_mount -> mnt_data, &fcall, 0, 0)) 
> return c;
> +     *ap -> a_vap = (struct vattr){
> +             .va_type        = fcall.st.qid.type & QTDIR ? VDIR : VREG,
> +             .va_mode        = fperm (fcall.st.mode),
> +             .va_nlink       = 1,
> +             .va_uid         = 0,
> +             .va_gid         = 0,
> +             .va_fsid        = ap -> a_vp -> v_mount -> 
> mnt_stat.f_fsid.val[0],
> +             .va_fileid      = fcall.st.qid.path,
> +             .va_size        = fcall.st.length,
> +             .va_blocksize   = 0,
> +             .va_atime       = {
> +                     .tv_sec  = fcall.st.atime,
> +                     .tv_nsec = 0,
> +             },
> +             .va_mtime       = {
> +                     .tv_sec  = fcall.st.mtime,
> +                     .tv_nsec = 0,
> +             },
> +             .va_ctime       = { 0 },
> +             .va_gen         = 0,
> +             .va_flags       = 0,
> +             .va_rdev        = 0,
> +             .va_bytes       = 0,
> +             .va_filerev     = fcall.st.qid.vers,
> +             .va_vaflags     = 0,
> +     };
> +     return 0;
> +}
> +
> +static int
> +p9p_reclaim (struct vop_reclaim_args *ap)
> +{
> +     VOP_CLOSE(ap -> a_vp, 0, FSCRED, ap -> a_p);
> +     free (ap -> a_vp -> v_data, M_P9PNODE);
> +     p9p_putFid (ap -> a_vp -> v_mount -> mnt_data, ((p9p_node_t *) ap -> 
> a_vp -> v_data) -> fid);
> +     return 0;
> +}
> +
> +struct vops p9p_vops = {
> +     .vop_access     = nullop,
> +     .vop_lookup     = (int (*) (void *))p9p_lookup,
> +     .vop_create     = (int (*) (void *))p9p_create,
> +     .vop_remove     = (int (*) (void *))p9p_remove,
> +     .vop_rename     = eopnotsupp,
> +     .vop_link       = eopnotsupp,
> +     .vop_mkdir      = (int (*) (void *))p9p_create,
> +     .vop_rmdir      = (int (*) (void *))p9p_remove,
> +     .vop_readdir    = (int (*) (void *))p9p_readdir,
> +     .vop_open       = (int (*) (void *))p9p_open,
> +     .vop_close      = (int (*) (void *))p9p_close,
> +     .vop_read       = (int (*) (void *))p9p_rw,
> +     .vop_write      = (int (*) (void *))p9p_rw,
> +     .vop_getattr    = (int (*) (void *))p9p_getattr,
> +     .vop_setattr    = (int (*) (void *))eopnotsupp,
> +     .vop_fsync      = nullop,
> +     .vop_lock       = vop_generic_lock,
> +     .vop_unlock     = vop_generic_unlock,
> +     .vop_islocked   = vop_generic_islocked,
> +     .vop_revoke     = vop_generic_revoke,
> +     .vop_bmap       = vop_generic_bmap,
> +     .vop_bwrite     = vop_generic_bwrite,
> +     .vop_kqfilter   = vop_generic_kqfilter,
> +     .vop_abortop    = vop_generic_abortop,
> +     .vop_advlock    = eopnotsupp,
> +     .vop_poll       = eopnotsupp,
> +     .vop_ioctl      = eopnotsupp,
> +     .vop_mknod      = eopnotsupp,
> +     .vop_symlink    = eopnotsupp,
> +     .vop_readlink   = eopnotsupp,
> +     .vop_strategy   = eopnotsupp,
> +     .vop_inactive   = eopnotsupp,
> +     .vop_reclaim    = (int (*) (void *))p9p_reclaim,
> +     .vop_print      = eopnotsupp,
> +     .vop_pathconf   = eopnotsupp,
> +};
> diff --git a/sys/9p/util.h b/sys/9p/util.h
> new file mode 100644
> index 0000000..2a5a1bd
> --- /dev/null
> +++ b/sys/9p/util.h
> @@ -0,0 +1,61 @@
> +#ifndef _UTIL_H
> +#define _UTIL_H
> +
> +#define SWAP(x, y) { (x) ^= (y); (y) ^= (x); (x) ^= (y); }
> +
> +#define ABS(x) ((x)>=0?(x):(-(x)))
> +
> +#define ROL(x,n) ((x)<<(n)|(x)>>(8*sizeof(x) - (n)))
> +#define ROR(x,n) ((x)>>(n)|(x)<<(8*sizeof(x) - (n)))
> +
> +#define LOAD16LE(y, x) { (y) = (uint16_t)((x)[0]) << 0 | (uint16_t)((x)[1]) 
> << 8; }
> +#define LOAD32LE(y, x) { (y) = (uint32_t)((x)[0]) << 0 | (uint32_t)((x)[1]) 
> << 8 | (uint32_t)((x)[2]) << 16 | (uint32_t)((x)[3]) << 24; }
> +#define LOAD64LE(y, x) { (y) = (uint64_t)((x)[0]) << 0 | (uint64_t)((x)[1]) 
> << 8 | (uint64_t)((x)[2]) << 16 | (uint64_t)((x)[3]) << 24 | 
> (uint64_t)((x)[4]) << 32 | (uint64_t)((x)[5]) << 40 | (uint64_t)((x)[6]) << 
> 48 | (uint64_t)((x)[7]) << 56; }
> +
> +#define STOR16LE(x, y) { (y)[0] = (uint8_t)((x) >> 0); (y)[1] = 
> (uint8_t)((x) >> 8); }
> +#define STOR32LE(x, y) { (y)[0] = (uint8_t)((x) >> 0); (y)[1] = 
> (uint8_t)((x) >> 8); (y)[2] = (uint8_t)((x) >> 16); (y)[3] = (uint8_t)((x) >> 
> 24); }
> +#define STOR64LE(x, y) { (y)[0] = (uint8_t)((x) >> 0); (y)[1] = 
> (uint8_t)((x) >> 8); (y)[2] = (uint8_t)((x) >> 16); (y)[3] = (uint8_t)((x) >> 
> 24); (y)[4] = (uint8_t)((x) >> 32); (y)[5] = (uint8_t)((x) >> 40); (y)[6] = 
> (uint8_t)((x) >> 48); (y)[7] = (uint8_t)((x) >> 56); }
> +
> +#define LOAD16BE(y, x) { (y) =                                               
>                                                                               
>                                       (uint16_t)((x)[0]) << 8 | 
> (uint16_t)((x)[1]) << 0; }
> +#define LOAD32BE(y, x) { (y) =                                               
>                                                               
> (uint32_t)((x)[0]) << 24 | (uint32_t)((x)[1]) << 16 | (uint32_t)((x)[2]) << 8 
> | (uint32_t)((x)[3]) << 0; }
> +#define LOAD64BE(y, x) { (y) = (uint64_t)((x)[0]) << 56 | (uint64_t)((x)[1]) 
> << 48 | (uint64_t)((x)[2]) << 40 | (uint64_t)((x)[3]) << 32 | 
> (uint64_t)((x)[4]) << 24 | (uint64_t)((x)[5]) << 16 | (uint64_t)((x)[6]) << 8 
> | (uint64_t)((x)[7]) << 0; }
> +
> +#define STOR16BE(x, y) {                                                     
>                                                                               
>                                                         (y)[0] = 
> (uint8_t)((x) >> 8); (y)[1] = (uint8_t)((x) >> 0); }
> +#define STOR32BE(x, y) {                                                     
>                                                                         
> (y)[0] = (uint8_t)((x) >> 24); (y)[1] = (uint8_t)((x) >> 16); (y)[2] = 
> (uint8_t)((x) >> 8); (y)[3] = (uint8_t)((x) >> 0); }
> +#define STOR64BE(x, y) { (y)[0] = (uint8_t)((x) >> 56); (y)[1] = 
> (uint8_t)((x) >> 48); (y)[2] = (uint8_t)((x) >> 40); (y)[3] = (uint8_t)((x) 
> >> 32); (y)[4] = (uint8_t)((x) >> 24); (y)[5] = (uint8_t)((x) >> 16); (y)[6] 
> = (uint8_t)((x) >> 8); (y)[7] = (uint8_t)((x) >> 0); }
> +
> +#define LOADNLE(n, y, x) switch (n) { case 1: (y)[0] = (uint8_t)(x); break; 
> case 2: LOAD16LE(y, x); break; case 4: LOAD32LE(y, x); break; case 8: 
> LOAD64LE(y, x); break; }
> +
> +#define LOADNBE(n, y, x) switch (n) { case 1: (y)[0] = (uint8_t)(x); break; 
> case 2: LOAD16BE(y, x); break; case 4: LOAD32BE(y, x); break; case 8: 
> LOAD64BE(y, x); break; }
> +
> +static inline int read (struct file *fp, caddr_t x, size_t n) {
> +     struct iovec v = { .iov_base = x, .iov_len = n };
> +     struct uio uio = {
> +             .uio_iov = &v,
> +             .uio_iovcnt = 1,
> +             .uio_segflg = UIO_SYSSPACE,
> +             .uio_rw = UIO_READ,
> +             .uio_offset = 0,
> +             .uio_resid = n,
> +             .uio_procp = curproc,
> +     };
> +
> +     return fp -> f_ops -> fo_read (fp, 0, &uio, FSCRED);
> +}
> +
> +static inline int write (struct file *fp, caddr_t x, size_t n) {
> +     struct iovec v = { .iov_base = x, .iov_len = n };
> +     struct uio uio = {
> +             .uio_iov = &v,
> +             .uio_iovcnt = 1,
> +             .uio_segflg = UIO_SYSSPACE,
> +             .uio_rw = UIO_WRITE,
> +             .uio_offset = 0,
> +             .uio_resid = n,
> +             .uio_procp = curproc,
> +     };
> +
> +     return fp -> f_ops -> fo_write (fp, 0, &uio, FSCRED);
> +}
> +
> +#endif
> diff --git a/sys/conf/GENERIC b/sys/conf/GENERIC
> index cc98b98..183708f 100644
> --- a/sys/conf/GENERIC
> +++ b/sys/conf/GENERIC
> @@ -46,6 +46,7 @@ option              UDF             # UDF (DVD) file system
>  option               MSDOSFS         # MS-DOS file system
>  option               FIFO            # FIFOs; RECOMMENDED
>  option               TMPFS           # efficient memory file system
> +option               P9P             # Plan 9 remote filesystem protocol
>  option               FUSE            # FUSE
>  
>  option               SOCKET_SPLICE   # Socket Splicing for TCP and UDP
> diff --git a/sys/conf/files b/sys/conf/files
> index 80229a4..d783a95 100644
> --- a/sys/conf/files
> +++ b/sys/conf/files
> @@ -952,6 +952,9 @@ file ufs/ext2fs/ext2fs_readwrite.c        ext2fs
>  file ufs/ext2fs/ext2fs_subr.c                ext2fs
>  file ufs/ext2fs/ext2fs_vfsops.c              ext2fs
>  file ufs/ext2fs/ext2fs_vnops.c               ext2fs
> +file 9p/9p.c                         p9p
> +file 9p/p9p_vfsops.c                 p9p
> +file 9p/p9p_vnops.c                  p9p
>  file uvm/uvm_addr.c
>  file uvm/uvm_amap.c
>  file uvm/uvm_anon.c
> diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c
> index cd84da1..1898179 100644
> --- a/sys/kern/vfs_init.c
> +++ b/sys/kern/vfs_init.c
> @@ -94,6 +94,10 @@ extern const struct vfsops fusefs_vfsops;
>  extern  const struct vfsops tmpfs_vfsops;
>  #endif
>  
> +#ifdef P9P
> +extern const struct vfsops p9p_vfsops;
> +#endif
> +
>  /* Set up the filesystem operations for vnodes. */
>  static struct vfsconf vfsconflist[] = {
>  #ifdef FFS
> @@ -139,6 +143,10 @@ static struct vfsconf vfsconflist[] = {
>  #ifdef TMPFS
>       { &tmpfs_vfsops, MOUNT_TMPFS, 19, 0, MNT_LOCAL, NULL },
>  #endif
> +
> +#ifdef P9P
> +     { &p9p_vfsops, MOUNT_P9P, 20, 0, 0, NULL },
> +#endif
>  };
>  
>  
> diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h
> index 34bed05..641270a 100644
> --- a/sys/sys/malloc.h
> +++ b/sys/sys/malloc.h
> @@ -121,6 +121,8 @@
>  #define      M_EXEC          63      /* argument lists & other mem used by 
> exec */
>  #define      M_MISCFSMNT     64      /* miscfs mount structures */
>  #define      M_FUSEFS        65      /* fusefs mount structures */
> +#define M_P9PMNT     66      /* 9p mount structures */
> +#define M_P9PNODE    67      /* 9p nodes */
>  /* 66-73 - free */
>  #define      M_PFKEY         74      /* pfkey data */
>  #define      M_TDB           75      /* Transforms database */
> diff --git a/sys/sys/mount.h b/sys/sys/mount.h
> index d35b0cb..e73e166 100644
> --- a/sys/sys/mount.h
> +++ b/sys/sys/mount.h
> @@ -262,6 +262,14 @@ struct tmpfs_args {
>  };
>  
>  /*
> + * Arguments to mount 9p filesystems
> + */
> +struct p9p_args {
> +     int fd;
> +     size_t msize;
> +};
> +
> +/*
>   * Arguments to mount procfs filesystems
>   */
>  struct procfs_args {
> @@ -353,6 +361,7 @@ struct statfs {
>  #define      MOUNT_NTFS      "ntfs"          /* NTFS */
>  #define      MOUNT_UDF       "udf"           /* UDF */
>  #define      MOUNT_TMPFS     "tmpfs"         /* tmpfs */
> +#define      MOUNT_P9P       "9p"            /* 9p */
>  #define      MOUNT_FUSEFS    "fuse"          /* FUSE */
>  
>  /*
> diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
> index a8ea897..c22362a 100644
> --- a/sys/sys/vnode.h
> +++ b/sys/sys/vnode.h
> @@ -70,12 +70,14 @@ enum vtagtype     {
>       VT_NON, VT_UFS, VT_NFS, VT_MFS, VT_MSDOSFS,
>       VT_PORTAL, VT_PROCFS, VT_AFS, VT_ISOFS, VT_ADOSFS,
>       VT_EXT2FS, VT_VFS, VT_NTFS, VT_UDF, VT_FUSEFS, VT_TMPFS,
> +     VT_P9P,
>  };
>  
>  #define      VTAG_NAMES \
>      "NON", "UFS", "NFS", "MFS", "MSDOSFS",                   \
>      "PORTAL", "PROCFS", "AFS", "ISOFS", "ADOSFS",            \
> -    "EXT2FS", "VFS", "NTFS", "UDF", "FUSEFS", "TMPFS"
> +    "EXT2FS", "VFS", "NTFS", "UDF", "FUSEFS", "TMPFS",               \
> +    "9P"
>  
>  /*
>   * Each underlying filesystem allocates its own private area and hangs
> 

-- 
Gilles Chehade

https://www.poolp.org                                          @poolpOrg

Reply via email to