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