qio: add a few block helpers
[akaros.git] / kern / include / ns.h
index 2861392..ddab4ae 100644 (file)
 #include <linker_func.h>
 #include <fdtap.h>
 #include <ros/fs.h>
 #include <linker_func.h>
 #include <fdtap.h>
 #include <ros/fs.h>
-#include <vfs.h>
+#include <bitmask.h>
+#include <mm.h>
+#include <sys/uio.h>
+#include <time.h>
 
 /*
  * functions (possibly) linked in, complete, from libc.
  */
 enum {
 
 /*
  * functions (possibly) linked in, complete, from libc.
  */
 enum {
-       UTFmax = 4,                                     /* maximum bytes per rune */
-       Runesync = 0x80,        /* cannot represent part of a UTF sequence (<) */
+       UTFmax = 4,             /* maximum bytes per rune */
+       Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
        Runeself = 0x80,        /* rune and UTF sequences are the same (<) */
        Runeerror = 0xFFFD,     /* decoding error in UTF */
        Runemax = 0x10FFFF,     /* 21-bit rune */
        Runemask = 0x1FFFFF,    /* bits used by runes (see grep) */
        Runeself = 0x80,        /* rune and UTF sequences are the same (<) */
        Runeerror = 0xFFFD,     /* decoding error in UTF */
        Runemax = 0x10FFFF,     /* 21-bit rune */
        Runemask = 0x1FFFFF,    /* bits used by runes (see grep) */
-       NUMSIZE32 = 10, /* max size of formatted 32 bit number (hex or decimal) */
-       NUMSIZE64 = 20, /* max size of formatted 64 bit number (hex or decimal) */
+       NUMSIZE32 = 10, /* max size of formatted 32 bit number (hex or deci) */
+       NUMSIZE64 = 20, /* max size of formatted 64 bit number (hex or deci) */
 };
 
 /*
 };
 
 /*
@@ -64,11 +67,6 @@ extern double pow10(int);
  * one-of-a-kind
  */
 extern char *cleanname(char *unused_char_p_t);
  * one-of-a-kind
  */
 extern char *cleanname(char *unused_char_p_t);
-//extern    uint32_t    getcallerpc(void*);
-static inline uint32_t getcallerpc(void *v)
-{
-       return 0;
-}
 
 extern int getfields(char *unused_char_p_t, char **unused_char_pp_t,
                                         int unused_int, int, char *);
 
 extern int getfields(char *unused_char_p_t, char **unused_char_pp_t,
                                         int unused_int, int, char *);
@@ -103,8 +101,8 @@ extern int parseether(uint8_t * unused_uint8_p_t, char *unused_char_p_t);
 #define        NRSTR   3       /* restore saved state */
 
 #define        STATMAX 65535U  /* max length of machine-independent stat structure */
 #define        NRSTR   3       /* restore saved state */
 
 #define        STATMAX 65535U  /* max length of machine-independent stat structure */
-#define        ERRMAX                  128     /* max length of error string */
-#define        KNAMELEN                28      /* max length of name held in kernel */
+#define        ERRMAX          128     /* max length of error string */
+#define        KNAMELEN        28      /* max length of name held in kernel */
 
 /* bits in Qid.type */
 #define QTDIR          0x80    /* type bit for directories */
 
 /* bits in Qid.type */
 #define QTDIR          0x80    /* type bit for directories */
@@ -112,7 +110,8 @@ extern int parseether(uint8_t * unused_uint8_p_t, char *unused_char_p_t);
 #define QTEXCL         0x20    /* type bit for exclusive use files */
 #define QTMOUNT                0x10    /* type bit for mounted channel */
 #define QTAUTH         0x08    /* type bit for authentication file */
 #define QTEXCL         0x20    /* type bit for exclusive use files */
 #define QTMOUNT                0x10    /* type bit for mounted channel */
 #define QTAUTH         0x08    /* type bit for authentication file */
-#define QTFILE         0x01    /* plain file */
+#define QTSYMLINK      0x02    /* type bit for symlinks */
+#define QTFILE         0x00    /* plain file.  Yeah, a zero.  Fucking 9p. */
 
 /* bits in Dir.mode */
 #define DMDIR          0x80000000      /* mode bit for directories */
 
 /* bits in Dir.mode */
 #define DMDIR          0x80000000      /* mode bit for directories */
@@ -122,9 +121,9 @@ extern int parseether(uint8_t * unused_uint8_p_t, char *unused_char_p_t);
 #define DMWRITABLE     0x08000000      /* non-standard, for select() */
 #define DMREADABLE     0x04000000      /* non-standard, for select() */
 #define DMSYMLINK      0x02000000      /* symlink -- from 9p2000.u */
 #define DMWRITABLE     0x08000000      /* non-standard, for select() */
 #define DMREADABLE     0x04000000      /* non-standard, for select() */
 #define DMSYMLINK      0x02000000      /* symlink -- from 9p2000.u */
-#define DMREAD         0x4     /* mode bit for read permission */
-#define DMWRITE                0x2     /* mode bit for write permission */
-#define DMEXEC         0x1     /* mode bit for execute permission */
+/* The lower parts of dir.mode are the three rwx perms (S_PMASK) */
+#define DMMODE_BITS (DMDIR | DMAPPEND | DMEXCL | DMMOUNT | DMWRITABLE \
+                     | DMREADABLE | DMSYMLINK)
 
 struct qid {
        uint64_t path;
 
 struct qid {
        uint64_t path;
@@ -132,26 +131,39 @@ struct qid {
        uint8_t type;
 };
 
        uint8_t type;
 };
 
+static inline bool qid_is_file(struct qid q)
+{
+       return (q.type & (QTDIR | QTSYMLINK)) == 0;
+}
+
 struct dir {
        /* system-modified data */
 struct dir {
        /* system-modified data */
-       uint16_t type;                          /* server type */
-       unsigned int dev;                       /* server subtype */
+       uint16_t type;          /* server type */
+       uint32_t dev;           /* server subtype */
        /* file data */
        /* file data */
-       struct qid qid;                         /* unique id from server */
-       uint32_t mode;                          /* permissions */
-       uint32_t atime;                         /* last read time */
-       uint32_t mtime;                         /* last write time */
-       int64_t length;                         /* file length: see <u.h> */
-       char *name;                                     /* last element of path */
-       char *uid;                                      /* owner name */
-       char *gid;                                      /* group name */
-       char *muid;                                     /* last modifier name */
+       struct qid qid;         /* unique id from server */
+       uint32_t mode;          /* permissions */
+       /* 9p stat has u32 atime (seconds) here */
+       /* 9p stat has u32 mtime (seconds) here */
+       uint64_t length;        /* file length: see <u.h> */
+       char *name;             /* last element of path */
+       char *uid;              /* owner name */
+       char *gid;              /* group name */
+       char *muid;             /* last modifier name */
+       char *ext;              /* extensions for special files (symlinks) */
+       uint32_t n_uid;         /* numeric owner uid */
+       uint32_t n_gid;         /* numeric group id */
+       uint32_t n_muid;        /* numeric last modifier id */
+       struct timespec atime;  /* last access time */
+       struct timespec btime;  /* file creation time */
+       struct timespec ctime;  /* last attribute change time */
+       struct timespec mtime;  /* last data modification time */
 };
 
 struct waitmsg {
 };
 
 struct waitmsg {
-       int pid;                                        /* of loved one */
-       uint32_t time[3];                       /* of loved one and descendants */
-       char msg[ERRMAX];                       /* actually variable-size in user mode */
+       int pid;                /* of loved one */
+       uint32_t time[3];       /* of loved one and descendants */
+       char msg[ERRMAX];       /* actually variable-size in user mode */
 };
 
 #define        VERSION9P       "9P2000"
 };
 
 #define        VERSION9P       "9P2000"
@@ -165,78 +177,118 @@ typedef
        uint16_t tag;
        /* union { */
        /* struct { */
        uint16_t tag;
        /* union { */
        /* struct { */
-       uint32_t msize;                         /* Tversion, Rversion */
-       char *version;                          /* Tversion, Rversion */
+       uint32_t msize;                 /* Tversion, Rversion */
+       char *version;                  /* Tversion, Rversion */
        /* }; */
        /* struct { */
        /* }; */
        /* struct { */
-       uint16_t oldtag;                        /* Tflush */
+       uint16_t oldtag;                /* Tflush */
        /* }; */
        /* struct { */
        /* }; */
        /* struct { */
-       char *ename;                            /* Rerror */
+       char *ename;                    /* Rerror */
        /* }; */
        /* struct { */
        /* }; */
        /* struct { */
-       struct qid qid;                         /* Rattach, Ropen, Rcreate */
-       uint32_t iounit;                        /* Ropen, Rcreate */
+       struct qid qid;                 /* Rattach, Ropen, Rcreate */
+       uint32_t iounit;                /* Ropen, Rcreate */
        /* }; */
        /* struct { */
        /* }; */
        /* struct { */
-       struct qid aqid;                        /* Rauth */
+       struct qid aqid;                /* Rauth */
        /* }; */
        /* struct { */
        /* }; */
        /* struct { */
-       uint32_t afid;                          /* Tauth, Tattach */
-       char *uname;                            /* Tauth, Tattach */
-       char *aname;                            /* Tauth, Tattach */
+       uint32_t afid;                  /* Tauth, Tattach */
+       char *uname;                    /* Tauth, Tattach */
+       char *aname;                    /* Tauth, Tattach */
        /* }; */
        /* struct { */
        /* }; */
        /* struct { */
-       uint32_t perm;                          /* Tcreate */
-       char *name;                                     /* Tcreate */
-       uint8_t mode;                           /* Tcreate, Topen */
+       uint32_t perm;                  /* Tcreate */
+       char *name;                     /* Tcreate */
+       uint8_t mode;                   /* Tcreate, Topen */
        /* }; */
        /* struct { */
        /* }; */
        /* struct { */
-       uint32_t newfid;                        /* Twalk */
-       uint16_t nwname;                        /* Twalk */
+       uint32_t newfid;                /* Twalk */
+       uint16_t nwname;                /* Twalk */
        char *wname[MAXWELEM];          /* Twalk */
        /* }; */
        /* struct { */
        char *wname[MAXWELEM];          /* Twalk */
        /* }; */
        /* struct { */
-       uint16_t nwqid;                         /* Rwalk */
+       uint16_t nwqid;                 /* Rwalk */
        struct qid wqid[MAXWELEM];      /* Rwalk */
        /* }; */
        /* struct { */
        struct qid wqid[MAXWELEM];      /* Rwalk */
        /* }; */
        /* struct { */
-       int64_t offset;                         /* Tread, Twrite */
-       uint32_t count;                         /* Tread, Twrite, Rread */
-       char *data;                                     /* Twrite, Rread */
+       int64_t offset;                 /* Tread, Twrite */
+       uint32_t count;                 /* Tread, Twrite, Rread */
+       char *data;                     /* Twrite, Rread */
        /* }; */
        /* struct { */
        /* }; */
        /* struct { */
-       uint16_t nstat;                         /* Twstat, Rstat */
-       uint8_t *stat;                          /* Twstat, Rstat */
+       uint16_t nstat;                 /* Twstat, Rstat */
+       uint8_t *stat;                  /* Twstat, Rstat */
        /* }; */
        /* }; */
 } fcall;
 
        /* }; */
        /* }; */
 } fcall;
 
-#define        GBIT8(p)        ((p)[0])
-#define        GBIT16(p)       ((p)[0]|((p)[1]<<8))
-#define        GBIT32(p)       ((uint32_t)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)))
-#define        GBIT64(p)       ((uint32_t)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) |\
-                               ((int64_t)((p)[4]|((p)[5]<<8)|((p)[6]<<16)|((p)[7]<<24)) << 32))
-
-#define        PBIT8(p,v)      (p)[0]=(v)
-#define        PBIT16(p,v)     (p)[0]=(v);(p)[1]=(v)>>8
-#define        PBIT32(p,v)     (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24
-#define        PBIT64(p,v)     (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24;\
-                       (p)[4]=(v)>>32;(p)[5]=(v)>>40;(p)[6]=(v)>>48;(p)[7]=(v)>>56
-
-#define        BIT8SZ          1
-#define        BIT16SZ         2
-#define        BIT32SZ         4
-#define        BIT64SZ         8
+#define        GBIT8(p)  ((p)[0])
+#define        GBIT16(p) ((p)[0]|((p)[1]<<8))
+#define        GBIT32(p) ((uint32_t)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)))
+#define        GBIT64(p) ((uint32_t)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) |\
+       ((int64_t)((p)[4]|((p)[5]<<8)|((p)[6]<<16)|((p)[7]<<24)) << 32))
+
+#define        PBIT8(p,v)  (p)[0]=(v)
+#define        PBIT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8
+#define        PBIT32(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24
+#define        PBIT64(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24;\
+               (p)[4]=(v)>>32;(p)[5]=(v)>>40;(p)[6]=(v)>>48;(p)[7]=(v)>>56
+
+#define        BIT8SZ  1
+#define        BIT16SZ 2
+#define        BIT32SZ 4
+#define        BIT64SZ 8
 #define        QIDSZ   (BIT8SZ+BIT32SZ+BIT64SZ)
 
 #define        QIDSZ   (BIT8SZ+BIT32SZ+BIT64SZ)
 
-/* STATFIXLEN includes leading 16-bit count */
-/* The count, however, excludes itself; total size is BIT16SZ+count */
-#define STATFIXLEN     (BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ)   /* amount of fixed length data in a stat buffer */
+/* The 9p STATFIXLENs include the leading 16-bit count.  The count, however,
+ * excludes itself; total size is BIT16SZ + count.  This is the amount of fixed
+ * length data in a stat buffer.  This does not include the strings, but it
+ * includes the string counts (u16s)
+ *
+ * STAT_FIX_LEN_9P is the original 9p stat message: type to length, including
+ * u32 atime and u32 mtime.  This is the bare minimum for a stat that we
+ * receive.  We check in e.g. convM2D for any extra fields.
+ *
+ * STAT_FIX_LEN_AK is the stat message used by Akaros, which includes Eric VH's
+ * extensions and full timespecs.  It is analogous to struct dir, including the
+ * u32s for the legacy atime/mtime.  We always send stats of this size, e.g. in
+ * convD2M.
+ *
+ * Note that the extended stat message has fixed data after the strings, but to
+ * get to this data, you have to jump through the string and their counts
+ * (u16s).  The counts are part of the fixed length, but not the strings.  Also
+ * note that the _AK version has an extra string. */
+#define STAT_NR_STRINGS_9P 4
+#define STAT_NR_STRINGS_AK 5
+#define STAT_FIX_LEN_9P (BIT16SZ +                      /* size */             \
+                         BIT16SZ +                      /* type */             \
+                         BIT32SZ +                      /* dev */              \
+                         QIDSZ +                        /* qid */              \
+                         BIT32SZ +                      /* mode */             \
+                         BIT32SZ +                      /* atime u32 */        \
+                         BIT32SZ +                      /* mtime u32 */        \
+                         BIT64SZ +                      /* length */           \
+                         STAT_NR_STRINGS_9P * BIT16SZ + /* string counts */    \
+                                                0)
+#define __STAT_FIX_LEN_AK_NONSTRING (                                          \
+                         BIT32SZ +                      /* n_uid */            \
+                         BIT32SZ +                      /* n_gid */            \
+                         BIT32SZ +                      /* n_muid */           \
+                         2 * BIT64SZ +                  /* atime */            \
+                         2 * BIT64SZ +                  /* btime */            \
+                         2 * BIT64SZ +                  /* ctime */            \
+                         2 * BIT64SZ +                  /* mtime */            \
+                                                0)
+#define STAT_FIX_LEN_AK (STAT_FIX_LEN_9P +                                     \
+                         (STAT_NR_STRINGS_AK - STAT_NR_STRINGS_9P) * BIT16SZ + \
+                         __STAT_FIX_LEN_AK_NONSTRING +                         \
+                                                0)
 
 #define        NOTAG           (uint16_t)~0U   /* Dummy tag */
 #define        NOFID           (uint32_t)~0U   /* Dummy fid */
 
 #define        NOTAG           (uint16_t)~0U   /* Dummy tag */
 #define        NOFID           (uint32_t)~0U   /* Dummy fid */
-#define        IOHDRSZ         24      /* ample room for Twrite/Rread header (iounit) */
+#define        IOHDRSZ         24 /* ample room for Twrite/Rread header (iounit) */
 
 enum {
        Tversion = 100,
 
 enum {
        Tversion = 100,
@@ -272,17 +324,17 @@ enum {
 
 void init_empty_dir(struct dir *d);
 unsigned int convM2S(uint8_t * unused_uint8_p_t, unsigned int unused_int,
 
 void init_empty_dir(struct dir *d);
 unsigned int convM2S(uint8_t * unused_uint8_p_t, unsigned int unused_int,
-                                        struct fcall *);
+                    struct fcall *);
 unsigned int convS2M(struct fcall *, uint8_t * unused_uint8_p_t, unsigned int);
 unsigned int sizeS2M(struct fcall *);
 
 unsigned int convM2kdirent(uint8_t * buf, unsigned int nbuf, struct kdirent *kd,
 unsigned int convS2M(struct fcall *, uint8_t * unused_uint8_p_t, unsigned int);
 unsigned int sizeS2M(struct fcall *);
 
 unsigned int convM2kdirent(uint8_t * buf, unsigned int nbuf, struct kdirent *kd,
-                                                  char *strs);
+                          char *strs);
 unsigned int convM2kstat(uint8_t * buf, unsigned int nbuf, struct kstat *ks);
 
 unsigned int convM2kstat(uint8_t * buf, unsigned int nbuf, struct kstat *ks);
 
-int statcheck(uint8_t * abuf, unsigned int nbuf);
+void statcheck(uint8_t *buf, size_t nbuf);
 unsigned int convM2D(uint8_t * unused_uint8_p_t, unsigned int unused_int,
 unsigned int convM2D(uint8_t * unused_uint8_p_t, unsigned int unused_int,
-                                        struct dir *, char *unused_char_p_t);
+                    struct dir *, char *unused_char_p_t);
 unsigned int convD2M(struct dir *, uint8_t * unused_uint8_p_t, unsigned int);
 unsigned int sizeD2M(struct dir *);
 
 unsigned int convD2M(struct dir *, uint8_t * unused_uint8_p_t, unsigned int);
 unsigned int sizeD2M(struct dir *);
 
@@ -321,21 +373,20 @@ struct alarms {
  * Access types in namec & channel flags
  */
 enum {
  * Access types in namec & channel flags
  */
 enum {
-       Aaccess,                                        /* as in stat, wstat */
-       Abind,                                          /* for left-hand-side of bind */
-       Atodir,                                         /* as in chdir */
-       Aopen,                                          /* for i/o */
-       Amount,                                         /* to be mounted or mounted upon */
-       Acreate,                                        /* is to be created */
-       Aremove,                                        /* will be removed by caller */
-       Acreatechan,                                    /* return a chan for a create request. for sysrename. */
+       Aaccess,                        /* as in stat, wstat */
+       Abind,                          /* for left-hand-side of bind */
+       Atodir,                         /* as in chdir */
+       Aopen,                          /* for i/o */
+       Amount,                         /* to be mounted or mounted upon */
+       Acreate,                        /* is to be created */
+       Aremove,                        /* will be removed by caller */
+       Arename,                        /* new_path of a rename */
 
        /* internal chan flags, used by the kernel only */
        COPEN =                 0x0001, /* for i/o */
        CMSG =                  0x0002, /* the message channel for a mount */
        CFREE =                 0x0004, /* not in use */
 
        /* internal chan flags, used by the kernel only */
        COPEN =                 0x0001, /* for i/o */
        CMSG =                  0x0002, /* the message channel for a mount */
        CFREE =                 0x0004, /* not in use */
-       CCACHE =                0x0008, /* client cache */
-       CINTERNAL_FLAGS = (COPEN | CMSG | CFREE | CCACHE),
+       CINTERNAL_FLAGS = (COPEN | CMSG | CFREE),
 
        /* chan/file flags, getable via fcntl/getfl and setably via open and
         * sometimes fcntl/setfl.  those that can't be set cause an error() in
 
        /* chan/file flags, getable via fcntl/getfl and setably via open and
         * sometimes fcntl/setfl.  those that can't be set cause an error() in
@@ -358,13 +409,15 @@ enum {
 
 enum {
        BFREE = (1 << 1),
 
 enum {
        BFREE = (1 << 1),
-       Bipck = (1 << NS_IPCK_SHIFT),   /* ip checksum */
-       Budpck = (1 << NS_UDPCK_SHIFT), /* udp checksum */
-       Btcpck = (1 << NS_TCPCK_SHIFT), /* tcp checksum */
-       Bpktck = (1 << NS_PKTCK_SHIFT), /* packet checksum */
-       Btso = (1 << NS_TSO_SHIFT),     /* TSO */
+       Bipck = (1 << NS_IPCK_SHIFT),   /* ip checksum (rx) */
+       Budpck = (1 << NS_UDPCK_SHIFT), /* udp checksum (rx), needed (tx) */
+       Btcpck = (1 << NS_TCPCK_SHIFT), /* tcp checksum (rx), needed (tx) */
+       Bpktck = (1 << NS_PKTCK_SHIFT), /* packet checksum (rx, maybe) */
+       Btso = (1 << NS_TSO_SHIFT),     /* TSO desired (tx) */
 };
 };
-#define BCKSUM_FLAGS (Bipck|Budpck|Btcpck|Bpktck|Btso)
+#define BLOCK_META_FLAGS (Bipck | Budpck | Btcpck | Bpktck | Btso)
+#define BLOCK_TRANS_TX_CSUM (Budpck | Btcpck)
+#define BLOCK_RX_CSUM (Bipck | Budpck | Btcpck)
 
 struct extra_bdata {
        uintptr_t base;
 
 struct extra_bdata {
        uintptr_t base;
@@ -376,16 +429,16 @@ struct extra_bdata {
 struct block {
        struct block *next;
        struct block *list;
 struct block {
        struct block *next;
        struct block *list;
-       uint8_t *rp;                            /* first unconsumed byte */
-       uint8_t *wp;                            /* first empty byte */
-       uint8_t *lim;                           /* 1 past the end of the buffer */
-       uint8_t *base;                          /* start of the buffer */
+       uint8_t *rp;                    /* first unconsumed byte */
+       uint8_t *wp;                    /* first empty byte */
+       uint8_t *lim;                   /* 1 past the end of the buffer */
+       uint8_t *base;                  /* start of the buffer */
        void (*free) (struct block *);
        uint16_t flag;
        void (*free) (struct block *);
        uint16_t flag;
-       uint16_t checksum;                      /* IP checksum of complete packet (minus media header) */
-       uint16_t checksum_start;                /* off from start of block to start csum */
-       uint16_t checksum_offset;               /* off from checksum_start to store csum */
-       uint16_t mss;               /* TCP MSS for TSO */
+       uint16_t mss;                   /* TCP MSS for TSO */
+       uint16_t network_offset;        /* offset from rp */
+       uint16_t transport_offset;      /* offset from rp */
+       uint16_t tx_csum_offset;        /* offset from tx_offset to store csum */
        /* might want something to track the next free extra_data slot */
        size_t extra_len;
        unsigned int nr_extra_bufs;
        /* might want something to track the next free extra_data slot */
        size_t extra_len;
        unsigned int nr_extra_bufs;
@@ -398,80 +451,94 @@ struct block {
 struct chan {
        spinlock_t lock;
        struct kref ref;
 struct chan {
        spinlock_t lock;
        struct kref ref;
-       struct chan *next;                      /* allocation */
+       struct chan *next;      /* allocation */
        struct chan *link;
        struct chan *link;
-       int64_t offset;                         /* in file */
-       int type;
-       uint32_t dev;
-       uint16_t mode;                          /* read/write */
-       uint16_t flag;
+       int64_t offset;         /* in file */
+       int type;               /* ID for device type, e.g. #mnt, #kfs, #ip */
+       uint32_t dev;           /* device specific; can be an instance ID */
+       uint16_t mode;          /* read/write */
+       int flag;
        struct qid qid;
        struct qid qid;
-       int fid;                                        /* for devmnt */
-       uint32_t iounit;                        /* chunk size for i/o; 0==default */
-       struct mhead *umh;                      /* mount point that derived Chan; used in unionread */
-       struct chan *umc;                       /* channel in union; held for union read */
-       qlock_t umqlock;                        /* serialize unionreads */
-       int uri;                                        /* union read index */
-       int dri;                                        /* devdirread index */
+       int fid;                /* for devmnt */
+       uint32_t iounit;        /* chunk size for i/o; 0==default */
+       struct mhead *umh;      /* mount point that derived Chan */
+       struct chan *umc;       /* channel in union; for union read */
+       qlock_t umqlock;        /* serialize unionreads */
+       int uri;                /* union read index */
+       int dri;                /* devdirread index */
        uint32_t mountid;
        uint32_t mountid;
-       struct mntcache *mcp;           /* Mount cache pointer */
-       struct mnt *mux;                        /* Mnt for clients using me for messages */
+       struct mntcache *mcp;   /* Mount cache pointer */
+       struct mnt *mux;        /* Mnt for clients using me for messages */
        union {
                void *aux;
        union {
                void *aux;
-               char tag[4];                    /* for iproute */
+               char tag[4];    /* for iproute */
        };
        /* mountpoint, as discovered during walk.
         * Used for rename at present.
         */
        struct chan *mountpoint;
        };
        /* mountpoint, as discovered during walk.
         * Used for rename at present.
         */
        struct chan *mountpoint;
-       struct chan *mchan;                     /* channel to mounted server */
-       struct qid mqid;                        /* qid of root of mount point */
+       struct chan *mchan;     /* channel to mounted server */
+       struct qid mqid;        /* qid of root of mount point */
        struct cname *name;
        /* hack for dir reads to try to get them right. */
        int ateof;
        void *buf;
        int bufused;
        struct cname *name;
        /* hack for dir reads to try to get them right. */
        int ateof;
        void *buf;
        int bufused;
+       /* A lot of synthetic files need something generated at open time, which
+        * the user can read from (including offsets) while the underlying file
+        * changes.  Hang that buffer here. */
+       void *synth_buf;
 };
 
 };
 
+extern struct chan *kern_slash;
+
 struct cname {
        struct kref ref;
 struct cname {
        struct kref ref;
-       int alen;                                       /* allocated length */
-       int len;                                        /* strlen(s) */
+       int alen;               /* allocated length */
+       int len;                /* strlen(s) */
        char *s;
 };
 
        char *s;
 };
 
+struct fs_file;
+
 struct dev {
        char *name;
 
 struct dev {
        char *name;
 
-       void (*reset) (void);
-       void (*init) (void);
-       void (*shutdown) (void);
-       struct chan *(*attach) (char *muxattach);
-       struct walkqid *(*walk) (struct chan *, struct chan *, char **name, int);
-       int (*stat) (struct chan *, uint8_t *, int);
-       struct chan *(*open) (struct chan *, int);
-       void (*create) (struct chan *, char *, int, uint32_t);
-       void (*close) (struct chan *);
-       long (*read) (struct chan *, void *, long, int64_t);
-       struct block *(*bread) (struct chan *, long, uint32_t);
-       long (*write) (struct chan *, void *, long, int64_t);
-       long (*bwrite) (struct chan *, struct block *, uint32_t);
-       void (*remove) (struct chan *);
-       int (*wstat) (struct chan *, uint8_t * unused_uint8_p_t, int);
-       void (*power) (int);            /* power mgt: power(1) → on, power (0) → off */
+       void (*reset)(void);
+       void (*init)(void);
+       void (*shutdown)(void);
+       struct chan *(*attach)(char *muxattach);
+       struct walkqid *(*walk)(struct chan *, struct chan *, char **name,
+                               unsigned int);
+       size_t (*stat)(struct chan *, uint8_t *, size_t);
+       struct chan *(*open)(struct chan *, int);
+       void (*create)(struct chan *, char *, int, uint32_t, char *);
+       void (*close)(struct chan *);
+       size_t (*read)(struct chan *, void *, size_t, off64_t);
+       struct block *(*bread)(struct chan *, size_t, off64_t);
+       size_t (*write)(struct chan *, void *, size_t, off64_t);
+       size_t (*bwrite)(struct chan *, struct block *, off64_t);
+       void (*remove)(struct chan *);
+       void (*rename)(struct chan *, struct chan *, const char *, int);
+       size_t (*wstat)(struct chan *, uint8_t *, size_t);
+       void (*power)(int);     /* power mgt: power(1) → on, power (0) → off */
 //  int (*config)( int unused_int, char *unused_char_p_t, DevConf*);
 //  int (*config)( int unused_int, char *unused_char_p_t, DevConf*);
-       char *(*chaninfo) (struct chan *, char *, size_t);
-       int (*tapfd) (struct chan *, struct fd_tap *, int);
-       int (*chan_ctl)(struct chan *, int);
-       /* we need to be aligned, we think to 64 bytes, for the linker tables. */
+       char *(*chaninfo)(struct chan *, char *, size_t);
+       int (*tapfd)(struct chan *, struct fd_tap *, int);
+       unsigned long (*chan_ctl)(struct chan *c, int op, unsigned long a1,
+                                 unsigned long a2, unsigned long a3,
+                                 unsigned long a4);
+       struct fs_file *(*mmap)(struct chan *, struct vm_region *, int, int);
+       /* we need to be aligned to 64 bytes for the linker tables. */
 } __attribute__ ((aligned(64)));
 
 struct dirtab {
        char name[KNAMELEN];
        struct qid qid;
        int64_t length;
 } __attribute__ ((aligned(64)));
 
 struct dirtab {
        char name[KNAMELEN];
        struct qid qid;
        int64_t length;
-       long perm;
-};
+       int perm;
+       /* we need to be aligned to 64 bytes for the linker tables. */
+} __attribute__ ((aligned(64)));
 
 struct walkqid {
        struct chan *clone;
 
 struct walkqid {
        struct chan *clone;
@@ -485,7 +552,7 @@ enum {
        NSCACHE = (1 << NSLOG),
 };
 
        NSCACHE = (1 << NSLOG),
 };
 
-struct mntwalk {                               /* state for /proc/#/ns */
+struct mntwalk {                       /* state for /proc/#/ns */
        int cddone;
        uint32_t id;
        struct mhead *mh;
        int cddone;
        uint32_t id;
        struct mhead *mh;
@@ -498,7 +565,7 @@ struct mount {
        struct mhead *head;
        struct mount *copy;
        struct mount *order;
        struct mhead *head;
        struct mount *copy;
        struct mount *order;
-       struct chan *to;                        /* channel replacing channel */
+       struct chan *to;                /* channel replacing channel */
        int mflag;
        char *spec;
 };
        int mflag;
        char *spec;
 };
@@ -506,23 +573,24 @@ struct mount {
 struct mhead {
        struct kref ref;
        struct rwlock lock;
 struct mhead {
        struct kref ref;
        struct rwlock lock;
-       struct chan *from;                      /* channel mounted upon */
+       struct chan *from;              /* channel mounted upon */
        struct mount *mount;            /* what's mounted upon it */
        struct mount *mount;            /* what's mounted upon it */
-       struct mhead *hash;                     /* Hash chain */
+       struct mhead *hash;             /* Hash chain */
 };
 
 struct mnt {
        spinlock_t lock;
 };
 
 struct mnt {
        spinlock_t lock;
-       /* references are counted using c->ref; channels on this mount point incref(c->mchan) == Mnt.c */
-       struct chan *c;                         /* Channel to file service */
-       struct proc *rip;                       /* Reader in progress */
-       struct mntrpc *queue;           /* Queue of pending requests on this channel */
-       uint32_t id;                            /* Multiplexer id for channel check */
-       struct mnt *list;                       /* Free list */
-       int flags;                                      /* cache */
-       int msize;                                      /* data + IOHDRSZ */
-       char *version;                          /* 9P version */
-       struct queue *q;                        /* input queue */
+       /* references are counted using c->ref; channels on this mount point
+        * incref(c->mchan) == Mnt.c */
+       struct chan *c;                 /* Channel to file service */
+       struct kthread *rip;            /* Reader in progress */
+       struct mntrpc *queue;           /* Queue of pending requests on chan */
+       uint32_t id;                    /* Multiplexer id for channel check */
+       struct mnt *list;               /* Free list */
+       int flags;                      /* cache */
+       int msize;                      /* data + IOHDRSZ */
+       char *version;                  /* 9P version */
+       struct queue *q;                /* input queue */
 };
 
 enum {
 };
 
 enum {
@@ -540,19 +608,16 @@ struct mntparam {
        struct chan *chan;
        struct chan *authchan;
        char *spec;
        struct chan *chan;
        struct chan *authchan;
        char *spec;
-       int flags;
 };
 
 struct pgrp {
 };
 
 struct pgrp {
-       struct kref ref;                        /* also used as a lock when mounting */
+       struct kref ref;                /* also used as a lock when mounting */
        uint32_t pgrpid;
        uint32_t pgrpid;
-       qlock_t debug;                          /* single access via devproc.c */
-       struct rwlock ns;                       /* Namespace n read/one write lock */
+       qlock_t debug;                  /* single access via devproc.c */
+       struct rwlock ns;               /* Namespace n read/one write lock */
        qlock_t nsh;
        struct mhead *mnthash[MNTHASH];
        int progmode;
        qlock_t nsh;
        struct mhead *mnthash[MNTHASH];
        int progmode;
-       struct chan *dot;
-       struct chan *slash;
        int nodevs;
        int pin;
 };
        int nodevs;
        int pin;
 };
@@ -569,8 +634,8 @@ struct egrp {
        struct kref ref;
        qlock_t qlock;
        struct evalue *entries;
        struct kref ref;
        qlock_t qlock;
        struct evalue *entries;
-       uint32_t path;                          /* qid.path of next Evalue to be allocated */
-       uint32_t vers;                          /* of Egrp */
+       uint32_t path;          /* qid.path of next Evalue to be allocated */
+       uint32_t vers;          /* of Egrp */
 };
 
 struct signerkey {
 };
 
 struct signerkey {
@@ -597,9 +662,9 @@ struct skeyset {
  */
 enum {
        /* Mode */
  */
 enum {
        /* Mode */
-       Trelative,                                      /* timer programmed in ns from now */
-       Tabsolute,                                      /* timer programmed in ns since epoch */
-       Tperiodic,                                      /* periodic timer, period in ns */
+       Trelative,              /* timer programmed in ns from now */
+       Tabsolute,              /* timer programmed in ns since epoch */
+       Tperiodic,              /* periodic timer, period in ns */
 };
 
 enum {
 };
 
 enum {
@@ -619,26 +684,80 @@ struct cmdbuf {
 };
 
 struct cmdtab {
 };
 
 struct cmdtab {
-       int index;                                      /* used by client to switch on result */
-       char *cmd;                                      /* command name */
-       int narg;                                       /* expected #args; 0 ==> variadic */
+       int index;              /* used by client to switch on result */
+       char *cmd;              /* command name */
+       int narg;               /* expected #args; 0 ==> variadic */
 };
 
 /* queue state bits, all can be set in qopen (Qstarve is always set) */
 enum {
 };
 
 /* queue state bits, all can be set in qopen (Qstarve is always set) */
 enum {
-       Qstarve = (1 << 0),                     /* consumer starved */
-       Qmsg = (1 << 1),        /* message stream */
-       Qclosed = (1 << 2),     /* queue has been closed/hungup */
-       Qflow = (1 << 3),       /* producer flow controlled */
-       Qcoalesce = (1 << 4),   /* coalesce empty packets on read */
-       Qkick = (1 << 5),       /* always call the kick routine after qwrite */
-       Qdropoverflow = (1 << 6),       /* writes that would block will be dropped */
+       Qmsg            = (1 << 1),     /* message stream */
+       Qclosed         = (1 << 2),     /* queue has been closed/hungup */
+       Qcoalesce       = (1 << 3),     /* coalesce empty packets on read */
+       Qkick           = (1 << 4),     /* always call kick() after qwrite */
+       Qdropoverflow   = (1 << 5),     /* drop writes that would block */
 };
 
 };
 
+/* Per-process structs */
+#define NR_OPEN_FILES_DEFAULT 32
+#define NR_FILE_DESC_DEFAULT 32
+
+/* Bitmask for file descriptors, big for when we exceed the initial small.  We
+ * could just use the fd_array to check for openness instead of the bitmask,
+ * but eventually we might want to use the bitmasks for other things (like
+ * which files are close_on_exec. */
+
+typedef struct fd_set {
+    uint8_t fds_bits[BYTES_FOR_BITMASK(NR_FILE_DESC_MAX)];
+} fd_set;
+
+
+struct small_fd_set {
+    uint8_t fds_bits[BYTES_FOR_BITMASK(NR_FILE_DESC_DEFAULT)];
+};
+
+/* Helper macros to manage fd_sets */
+#define FD_SET(n, p)   ((p)->fds_bits[(n) / 8] |=  (1 << ((n) & 7)))
+#define FD_CLR(n, p)   ((p)->fds_bits[(n) / 8] &= ~(1 << ((n) & 7)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n) / 8] &   (1 << ((n) & 7)))
+#define FD_ZERO(p)             memset((void*)(p), 0, sizeof(*(p)))
+
+/* Describes an open file.  We need this, since the FD flags are supposed to be
+ * per file descriptor, not per file (like the file status flags). */
+struct file_desc {
+       struct chan             *fd_chan;
+       unsigned int            fd_flags;
+       struct fd_tap           *fd_tap;
+};
+
+/* All open files for a process */
+struct fd_table {
+       spinlock_t              lock;
+       bool                    closed;
+       int                     max_files;      /* max files ptd to by fd */
+       int                     max_fdset;      /* max of the current fd_set */
+       int                     hint_min_fd;    /* <= min available fd */
+       struct file_desc        *fd;            /* initially pts to fd_array */
+       struct fd_set           *open_fds;      /* init, pts to open_fds_init */
+       struct small_fd_set     open_fds_init;
+       struct file_desc        fd_array[NR_OPEN_FILES_DEFAULT];
+};
+
+ssize_t kread_file(struct file_or_chan *file, void *buf, size_t sz);
+void *kread_whole_file(struct file_or_chan *file);
+
+/* Process-related File management functions */
+void *lookup_fd(struct fd_table *fdt, int fd, bool incref);
+int insert_obj_fdt(struct fd_table *fdt, void *obj, int low_fd, int fd_flags,
+                   bool must_use_low);
+bool close_fd(struct fd_table *fdt, int fd);
+void close_fdt(struct fd_table *open_files, bool cloexec);
+void clone_fdt(struct fd_table *src, struct fd_table *dst);
+
 #define DEVDOTDOT -1
 
 typedef int Devgen(struct chan *, char *unused_char_p_t, struct dirtab *,
 #define DEVDOTDOT -1
 
 typedef int Devgen(struct chan *, char *unused_char_p_t, struct dirtab *,
-                                  int unused_int, int, struct dir *);
+                  int unused_int, int, struct dir *);
 
 /* inferno portfns.h. Not all these are needed. */
 #define                FPinit() fpinit()       /* remove this if math lib is linked */
 
 /* inferno portfns.h. Not all these are needed. */
 #define                FPinit() fpinit()       /* remove this if math lib is linked */
@@ -652,6 +771,13 @@ struct block *block_alloc(size_t, int);
 int block_add_extd(struct block *b, unsigned int nr_bufs, int mem_flags);
 int block_append_extra(struct block *b, uintptr_t base, uint32_t off,
                        uint32_t len, int mem_flags);
 int block_add_extd(struct block *b, unsigned int nr_bufs, int mem_flags);
 int block_append_extra(struct block *b, uintptr_t base, uint32_t off,
                        uint32_t len, int mem_flags);
+void block_copy_metadata(struct block *new_b, struct block *old_b);
+void block_reset_metadata(struct block *b);
+void block_add_to_offsets(struct block *b, int delta);
+void block_transfer_extras(struct block *new, struct block *old);
+void block_replace_extras(struct block *new, struct block *old);
+struct block *block_realloc(struct block *b, size_t header_space);
+size_t block_copy_to_body(struct block *to, void *from, size_t copy_amt);
 int anyhigher(void);
 int anyready(void);
 void _assert(char *unused_char_p_t);
 int anyhigher(void);
 int anyready(void);
 void _assert(char *unused_char_p_t);
@@ -667,7 +793,6 @@ void chanfree(struct chan *);
 void chanrec(struct mnt *);
 void checkalarms(void);
 void checkb(struct block *, char *unused_char_p_t);
 void chanrec(struct mnt *);
 void checkalarms(void);
 void checkb(struct block *, char *unused_char_p_t);
-void cinit(void);
 struct chan *cclone(struct chan *);
 void cclose(struct chan *);
 void closeegrp(struct egrp *);
 struct chan *cclone(struct chan *);
 void cclose(struct chan *);
 void closeegrp(struct egrp *);
@@ -682,45 +807,40 @@ struct block *concatblock(struct block *);
 struct block *linearizeblock(struct block *b);
 void confinit(void);
 void cons_add_char(char c);
 struct block *linearizeblock(struct block *b);
 void confinit(void);
 void cons_add_char(char c);
-void copen(struct chan *);
 struct block *copyblock(struct block *b, int mem_flags);
 struct block *copyblock(struct block *b, int mem_flags);
-int cread(struct chan *, uint8_t * unused_uint8_p_t, int unused_int, int64_t);
 struct chan *cunique(struct chan *);
 struct chan *createdir(struct chan *, struct mhead *);
 void cunmount(struct chan *, struct chan *);
 struct chan *cunique(struct chan *);
 struct chan *createdir(struct chan *, struct mhead *);
 void cunmount(struct chan *, struct chan *);
-void cupdate(struct chan *, uint8_t * unused_uint8_p_t, int unused_int,
-                        int64_t);
 void cursorenable(void);
 void cursordisable(void);
 int cursoron(int);
 void cursoroff(int);
 void cursorenable(void);
 void cursordisable(void);
 int cursoron(int);
 void cursoroff(int);
-void cwrite(struct chan *, uint8_t * unused_uint8_p_t, int unused_int, int64_t);
 struct chan *devattach(const char *name, char *spec);
 struct chan *devattach(const char *name, char *spec);
-struct block *devbread(struct chan *, long, uint32_t);
-long devbwrite(struct chan *, struct block *, uint32_t);
+struct block *devbread(struct chan *, size_t, off64_t);
+size_t devbwrite(struct chan *, struct block *, off64_t);
 struct chan *devclone(struct chan *);
 struct chan *devclone(struct chan *);
-void devcreate(struct chan *, char *name, int mode, uint32_t perm);
+void devcreate(struct chan *, char *name, int mode, uint32_t perm, char *ext);
 void devdir(struct chan *, struct qid, char *, int64_t, char *, long,
 void devdir(struct chan *, struct qid, char *, int64_t, char *, long,
-                       struct dir *);
+           struct dir *);
 long devdirread(struct chan *, char *, long, struct dirtab *, int, Devgen *);
 Devgen devgen;
 void devinit(void);
 int devno(const char *name, int user);
 void devpower(int);
 struct dev *devbyname(char *unused_char_p_t);
 long devdirread(struct chan *, char *, long, struct dirtab *, int, Devgen *);
 Devgen devgen;
 void devinit(void);
 int devno(const char *name, int user);
 void devpower(int);
 struct dev *devbyname(char *unused_char_p_t);
-struct chan *devopen(struct chan *, int unused_int,
-                                        struct dirtab *, int unused_int2, Devgen *);
+struct chan *devopen(struct chan *, int unused_int, struct dirtab *,
+                    int unused_int2, Devgen *);
 void devpermcheck(char *unused_char_p_t, uint32_t, int);
 void devremove(struct chan *);
 void devreset(void);
 void devshutdown(void);
 size_t dev_make_stat(struct chan *c, struct dir *dir, uint8_t *dp, size_t n);
 void devpermcheck(char *unused_char_p_t, uint32_t, int);
 void devremove(struct chan *);
 void devreset(void);
 void devshutdown(void);
 size_t dev_make_stat(struct chan *c, struct dir *dir, uint8_t *dp, size_t n);
-int devstat(struct chan *, uint8_t * unused_uint8_p_t, int unused_int,
-                       struct dirtab *, int unused_int2, Devgen *);
-struct walkqid *devwalk(struct chan *,
-                                               struct chan *, char **unused_char_pp_t, int unused_int,
-                                               struct dirtab *, int unused_intw, Devgen *);
-int devwstat(struct chan *, uint8_t * unused_uint8_p_t, int);
+size_t devstat(struct chan *, uint8_t *db, size_t n, struct dirtab *,
+               int ntab, Devgen *);
+struct walkqid *devwalk(struct chan *, struct chan *, char **unused_char_pp_t,
+                       int unused_int, struct dirtab *, int unused_intw,
+                       Devgen *);
+size_t devwstat(struct chan *, uint8_t *, size_t);
 char *devchaninfo(struct chan *chan, char *ret, size_t ret_l);
 void disinit(void *);
 void disfault(void *, char *unused_char_p_t);
 char *devchaninfo(struct chan *chan, char *ret, size_t ret_l);
 void disinit(void *);
 void disfault(void *, char *unused_char_p_t);
@@ -779,13 +899,14 @@ void mousetrack(int unused_int, int, int, int);
 uint64_t ms2fastticks(uint32_t);
 void mul64fract(uint64_t *, uint64_t, uint64_t);
 void muxclose(struct mnt *);
 uint64_t ms2fastticks(uint32_t);
 void mul64fract(uint64_t *, uint64_t, uint64_t);
 void muxclose(struct mnt *);
-struct chan *namec(char *unused_char_p_t, int unused_int, int, uint32_t);
+struct chan *namec(char *unused_char_p_t, int unused_int, int, uint32_t,
+                   void *ext);
 struct chan *namec_from(struct chan *c, char *name, int amode, int omode,
 struct chan *namec_from(struct chan *c, char *name, int amode, int omode,
-                        uint32_t perm);
+                        uint32_t perm, void *ext);
 struct chan *newchan(void);
 struct egrp *newegrp(void);
 struct mount *newmount(struct mhead *, struct chan *, int unused_int,
 struct chan *newchan(void);
 struct egrp *newegrp(void);
 struct mount *newmount(struct mhead *, struct chan *, int unused_int,
-                                          char *unused_char_p_t);
+                      char *unused_char_p_t);
 struct pgrp *newpgrp(void);
 struct proc *newproc(void);
 char *nextelem(char *unused_char_p_t, char *);
 struct pgrp *newpgrp(void);
 struct proc *newproc(void);
 char *nextelem(char *unused_char_p_t, char *);
@@ -798,13 +919,14 @@ uint64_t ns2fastticks(uint64_t);
 int okaddr(uint32_t, uint32_t, int);
 int omode_to_rwx(int);
 int omode_to_9p_accmode(int open_flags);
 int okaddr(uint32_t, uint32_t, int);
 int omode_to_rwx(int);
 int omode_to_9p_accmode(int open_flags);
+int access_bits_to_omode(int access_bits);
 struct block *packblock(struct block *);
 struct block *padblock(struct block *, int);
 
 void pgrpcpy(struct pgrp *, struct pgrp *);
 
 int progfdprint(struct chan *, int unused_int, int, char *unused_char_p_t,
 struct block *packblock(struct block *);
 struct block *padblock(struct block *, int);
 
 void pgrpcpy(struct pgrp *, struct pgrp *);
 
 int progfdprint(struct chan *, int unused_int, int, char *unused_char_p_t,
-                               int i);
+               int i);
 int pullblock(struct block **, int);
 struct block *pullupblock(struct block *, int);
 struct block *pullupqueue(struct queue *, int);
 int pullblock(struct block **, int);
 struct block *pullupblock(struct block *, int);
 struct block *pullupqueue(struct queue *, int);
@@ -833,6 +955,7 @@ void qhangup(struct queue *, char *unused_char_p_t);
 int qisclosed(struct queue *);
 ssize_t qiwrite(struct queue *, void *, int);
 int qlen(struct queue *);
 int qisclosed(struct queue *);
 ssize_t qiwrite(struct queue *, void *, int);
 int qlen(struct queue *);
+size_t q_bytes_read(struct queue *q);
 void qdropoverflow(struct queue *, bool);
 void q_toggle_qmsg(struct queue *q, bool onoff);
 void q_toggle_qcoalesce(struct queue *q, bool onoff);
 void qdropoverflow(struct queue *, bool);
 void q_toggle_qmsg(struct queue *q, bool onoff);
 void q_toggle_qcoalesce(struct queue *q, bool onoff);
@@ -843,7 +966,8 @@ void qputback(struct queue *, struct block *);
 size_t qread(struct queue *q, void *va, size_t len);
 size_t qread_nonblock(struct queue *q, void *va, size_t len);
 void qreopen(struct queue *);
 size_t qread(struct queue *q, void *va, size_t len);
 size_t qread_nonblock(struct queue *q, void *va, size_t len);
 void qreopen(struct queue *);
-void qsetlimit(struct queue *, int);
+void qsetlimit(struct queue *, size_t);
+size_t qgetlimit(struct queue *);
 int qwindow(struct queue *);
 ssize_t qwrite(struct queue *, void *, int);
 ssize_t qwrite_nonblock(struct queue *, void *, int);
 int qwindow(struct queue *);
 ssize_t qwrite(struct queue *, void *, int);
 ssize_t qwrite_nonblock(struct queue *, void *, int);
@@ -853,13 +977,13 @@ bool qreadable(struct queue *q);
 bool qwritable(struct queue *q);
 
 void *realloc(void *, uint32_t);
 bool qwritable(struct queue *q);
 
 void *realloc(void *, uint32_t);
-int readmem(unsigned long offset, char *buf, unsigned long n,
-                       void *mem, size_t mem_len);
+int readmem(unsigned long offset, char *buf, unsigned long n, const void *mem,
+           size_t mem_len);
 int readnum(unsigned long off, char *buf, unsigned long n, unsigned long val,
 int readnum(unsigned long off, char *buf, unsigned long n, unsigned long val,
-                       size_t size);
+           size_t size);
 int readnum_hex(unsigned long off, char *buf, unsigned long n,
                 unsigned long val, size_t size);
 int readnum_hex(unsigned long off, char *buf, unsigned long n,
                 unsigned long val, size_t size);
-int readstr(unsigned long offset, char *buf, unsigned long n, char *str);
+int readstr(unsigned long offset, char *buf, unsigned long n, const char *str);
 int readnum_int64_t(uint32_t, char *unused_char_p_t, uint32_t, int64_t, int);
 unsigned long strtoul_from_ubuf(void *ubuf, size_t count, int base);
 void ready(struct proc *);
 int readnum_int64_t(uint32_t, char *unused_char_p_t, uint32_t, int64_t, int);
 unsigned long strtoul_from_ubuf(void *ubuf, size_t count, int base);
 void ready(struct proc *);
@@ -899,7 +1023,6 @@ void userinit(void);
 uint32_t userpc(void);
 void validname(char *, int);
 void validwstatname(char *);
 uint32_t userpc(void);
 void validname(char *, int);
 void validwstatname(char *);
-int walk(struct chan **, char **unused_char_pp_t, int unused_int, bool, int *);
 void *xalloc(uint32_t);
 void *xallocz(uint32_t, int);
 void xfree(void *);
 void *xalloc(uint32_t);
 void *xallocz(uint32_t, int);
 void xfree(void *);
@@ -920,6 +1043,11 @@ uint16_t nhgets(void *);
 
 char *get_cur_genbuf(void);
 
 
 char *get_cur_genbuf(void);
 
+static inline const char *chan_dev_name(struct chan *c)
+{
+       return devtab[c->type].name;
+}
+
 /* hack for now. */
 #define        NOW     tsc2msec(read_tsc())
 #define        seconds() tsc2sec(read_tsc())
 /* hack for now. */
 #define        NOW     tsc2msec(read_tsc())
 #define        seconds() tsc2sec(read_tsc())
@@ -930,32 +1058,34 @@ void devtabinit();
 void devtabreset();
 
 /* kern/src/ns/parse.c */
 void devtabreset();
 
 /* kern/src/ns/parse.c */
-struct cmdbuf *parsecmd(char *p, int n);
+struct cmdbuf *parsecmd(char *p, size_t n);
 void cmderror(struct cmdbuf *cb, char *s);
 struct cmdtab *lookupcmd(struct cmdbuf *cb, struct cmdtab *ctab, int nctab);
 
 /* kern/src/ns/sysfile.c */
 void cmderror(struct cmdbuf *cb, char *s);
 struct cmdtab *lookupcmd(struct cmdbuf *cb, struct cmdtab *ctab, int nctab);
 
 /* kern/src/ns/sysfile.c */
-int newfd(struct chan *c, int oflags);
+int newfd(struct chan *c, int low_fd, int oflags, bool must_use_low);
 struct chan *fdtochan(struct fd_table *fdt, int fd, int mode, int chkmnt,
                       int iref);
 long kchanio(void *vc, void *buf, int n, int mode);
 int openmode(uint32_t o);
 void fdclose(struct fd_table *fdt, int fd);
 struct chan *fdtochan(struct fd_table *fdt, int fd, int mode, int chkmnt,
                       int iref);
 long kchanio(void *vc, void *buf, int n, int mode);
 int openmode(uint32_t o);
 void fdclose(struct fd_table *fdt, int fd);
-int syschdir(char *path);
+int syschdir(struct proc *target, char *path);
+int sysfchdir(struct proc *target, int fd);
 int grpclose(struct fd_table *fdt, int fd);
 int sysclose(int fd);
 int syscreate(char *path, int mode, uint32_t perm);
 int grpclose(struct fd_table *fdt, int fd);
 int sysclose(int fd);
 int syscreate(char *path, int mode, uint32_t perm);
-int sysdup(int old);
+int sysdup(int old, int low_fd, bool must_use_low);
 int sys_dup_to(struct proc *from_proc, unsigned int from_fd,
                struct proc *to_proc, unsigned int to_fd);
 int sysfstat(int fd, uint8_t*, int n);
 int sysfstatakaros(int fd, struct kstat *);
 int sys_dup_to(struct proc *from_proc, unsigned int from_fd,
                struct proc *to_proc, unsigned int to_fd);
 int sysfstat(int fd, uint8_t*, int n);
 int sysfstatakaros(int fd, struct kstat *);
-char *sysfd2path(int fd);
+char *sysgetcwd(void);
 int sysfauth(int fd, char *aname);
 int sysfversion(int fd, unsigned int msize, char *vers, unsigned int arglen);
 int sysfwstat(int fd, uint8_t * buf, int n);
 long bindmount(struct chan *c, char *old, int flag, char *spec);
 int sysbind(char *new, char *old, int flags);
 int sysfauth(int fd, char *aname);
 int sysfversion(int fd, unsigned int msize, char *vers, unsigned int arglen);
 int sysfwstat(int fd, uint8_t * buf, int n);
 long bindmount(struct chan *c, char *old, int flag, char *spec);
 int sysbind(char *new, char *old, int flags);
+int syssymlink(char *new_path, char *old_path);
 int sysmount(int fd, int afd, char *old, int flags, char *spec);
 int sysunmount(char *old, char *new);
 int sysopenat(int dirfd, char *path, int vfs_flags);
 int sysmount(int fd, int afd, char *old, int flags, char *spec);
 int sysunmount(char *old, char *new);
 int sysopenat(int dirfd, char *path, int vfs_flags);
@@ -965,15 +1095,18 @@ void read_exactly_n(struct chan *c, void *vp, long n);
 long sysread(int fd, void *va, long n);
 long syspread(int fd, void *va, long n, int64_t off);
 int sysremove(char *path);
 long sysread(int fd, void *va, long n);
 long syspread(int fd, void *va, long n, int64_t off);
 int sysremove(char *path);
+int sysrename(char *from_path, char *to_path);
 int64_t sysseek(int fd, int64_t off, int whence);
 void validstat(uint8_t * s, int n, int slashok);
 int sysstat(char *path, uint8_t*, int n);
 int64_t sysseek(int fd, int64_t off, int whence);
 void validstat(uint8_t * s, int n, int slashok);
 int sysstat(char *path, uint8_t*, int n);
-int sysstatakaros(char *path, struct kstat *);
+int syslstat(char *path, uint8_t*, int n);
+int sysstatakaros(char *path, struct kstat *, int flags);
 long syswrite(int fd, void *va, long n);
 long syspwrite(int fd, void *va, long n, int64_t off);
 int syswstat(char *path, uint8_t * buf, int n);
 struct dir *chandirstat(struct chan *c);
 struct dir *sysdirstat(char *name);
 long syswrite(int fd, void *va, long n);
 long syspwrite(int fd, void *va, long n, int64_t off);
 int syswstat(char *path, uint8_t * buf, int n);
 struct dir *chandirstat(struct chan *c);
 struct dir *sysdirstat(char *name);
+struct dir *sysdirlstat(char *name);
 struct dir *sysdirfstat(int fd);
 int sysdirwstat(char *name, struct dir *dir);
 int sysdirfwstat(int fd, struct dir *dir);
 struct dir *sysdirfstat(int fd);
 int sysdirwstat(char *name, struct dir *dir);
 int sysdirfwstat(int fd, struct dir *dir);
@@ -983,7 +1116,10 @@ void print_chaninfo(struct chan *ch);
 int plan9setup(struct proc *new_proc, struct proc *parent, int flags);
 int iseve(void);
 int fd_getfl(int fd);
 int plan9setup(struct proc *new_proc, struct proc *parent, int flags);
 int iseve(void);
 int fd_getfl(int fd);
-int fd_setfl(int fd, int flags);
+int fd_chan_ctl(int fd, int cmd, unsigned long arg1, unsigned long arg2,
+                unsigned long arg3, unsigned long arg4);
+int fd_get_fd_flags(struct fd_table *fdt, int fd);
+int fd_set_fd_flags(struct fd_table *fdt, int fd, int new_fl);
 
 /* kern/drivers/dev/srv.c */
 char *srvname(struct chan *c);
 
 /* kern/drivers/dev/srv.c */
 char *srvname(struct chan *c);
@@ -993,6 +1129,12 @@ void printqid(void (*putch) (int, void **), void **putdat, struct qid *q);
 void printcname(void (*putch) (int, void **), void **putdat, struct cname *c);
 void printchan(void (*putch) (int, void **), void **putdat, struct chan *c);
 
 void printcname(void (*putch) (int, void **), void **putdat, struct cname *c);
 void printchan(void (*putch) (int, void **), void **putdat, struct chan *c);
 
+/* kern/src/ns/util.c */
+bool caller_is_username(char *uid);
+bool caller_has_perms(char *fileuid, uint32_t perm, int omode);
+bool caller_has_dir_perms(struct dir *dir, int omode);
+void dir_perm_check(struct dir *dir, int omode);
+
 static inline int abs(int a)
 {
        if (a < 0)
 static inline int abs(int a)
 {
        if (a < 0)
@@ -1000,7 +1142,7 @@ static inline int abs(int a)
        return a;
 }
 
        return a;
 }
 
-extern char *eve;
+extern struct username eve;
 extern unsigned int qiomaxatomic;
 
 /* special sections */
 extern unsigned int qiomaxatomic;
 
 /* special sections */