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