qio: add a few block helpers
[akaros.git] / kern / include / ns.h
index 9e0f884..ddab4ae 100644 (file)
 
 #pragma once
 
-#include <env.h>
 #include <err.h>
 #include <rendez.h>
 #include <rwlock.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 {
-       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) */
-       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) */
 };
 
 /*
@@ -65,11 +67,6 @@ extern double pow10(int);
  * 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 *);
@@ -104,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        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 */
@@ -114,7 +111,7 @@ extern int parseether(uint8_t * unused_uint8_p_t, char *unused_char_p_t);
 #define QTMOUNT                0x10    /* type bit for mounted channel */
 #define QTAUTH         0x08    /* type bit for authentication file */
 #define QTSYMLINK      0x02    /* type bit for symlinks */
-#define QTFILE         0x01    /* plain file */
+#define QTFILE         0x00    /* plain file.  Yeah, a zero.  Fucking 9p. */
 
 /* bits in Dir.mode */
 #define DMDIR          0x80000000      /* mode bit for directories */
@@ -124,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 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;
@@ -134,34 +131,39 @@ struct qid {
        uint8_t type;
 };
 
+static inline bool qid_is_file(struct qid q)
+{
+       return (q.type & (QTDIR | QTSYMLINK)) == 0;
+}
+
 struct dir {
        /* system-modified data */
-       uint16_t type;                          /* server type */
-       uint32_t dev;                   /* server subtype */
+       uint16_t type;          /* server type */
+       uint32_t dev;           /* server subtype */
        /* file data */
-       struct qid qid;                         /* unique id from server */
-       uint32_t mode;                          /* permissions */
+       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 */
+       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 {
-       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"
@@ -175,69 +177,69 @@ typedef
        uint16_t tag;
        /* union { */
        /* struct { */
-       uint32_t msize;                         /* Tversion, Rversion */
-       char *version;                          /* Tversion, Rversion */
+       uint32_t msize;                 /* Tversion, Rversion */
+       char *version;                  /* Tversion, Rversion */
        /* }; */
        /* struct { */
-       uint16_t oldtag;                        /* Tflush */
+       uint16_t oldtag;                /* Tflush */
        /* }; */
        /* struct { */
-       char *ename;                            /* Rerror */
+       char *ename;                    /* Rerror */
        /* }; */
        /* 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 qid aqid;                        /* Rauth */
+       struct qid aqid;                /* Rauth */
        /* }; */
        /* 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 { */
-       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 { */
-       uint32_t newfid;                        /* Twalk */
-       uint16_t nwname;                        /* Twalk */
+       uint32_t newfid;                /* Twalk */
+       uint16_t nwname;                /* Twalk */
        char *wname[MAXWELEM];          /* Twalk */
        /* }; */
        /* struct { */
-       uint16_t nwqid;                         /* Rwalk */
+       uint16_t nwqid;                 /* Rwalk */
        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 { */
-       uint16_t nstat;                         /* Twstat, Rstat */
-       uint8_t *stat;                          /* Twstat, Rstat */
+       uint16_t nstat;                 /* Twstat, Rstat */
+       uint8_t *stat;                  /* Twstat, Rstat */
        /* }; */
        /* }; */
 } 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)
 
 /* The 9p STATFIXLENs include the leading 16-bit count.  The count, however,
@@ -286,7 +288,7 @@ typedef
 
 #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,
@@ -322,17 +324,17 @@ enum {
 
 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,
-                                                  char *strs);
+                          char *strs);
 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,
-                                        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 *);
 
@@ -371,20 +373,20 @@ struct alarms {
  * 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 */
+       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 */
-       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
@@ -411,7 +413,7 @@ enum {
        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) */
+       Btso = (1 << NS_TSO_SHIFT),     /* TSO desired (tx) */
 };
 #define BLOCK_META_FLAGS (Bipck | Budpck | Btcpck | Bpktck | Btso)
 #define BLOCK_TRANS_TX_CSUM (Budpck | Btcpck)
@@ -427,15 +429,15 @@ struct extra_bdata {
 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;
-       uint16_t mss;               /* TCP MSS for TSO */
-       uint16_t network_offset;        /* offset from start */
-       uint16_t transport_offset;      /* offset from start */
+       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;
@@ -449,42 +451,42 @@ struct block {
 struct chan {
        spinlock_t lock;
        struct kref ref;
-       struct chan *next;                      /* allocation */
+       struct chan *next;      /* allocation */
        struct chan *link;
-       int64_t offset;                         /* in file */
-       int type;
-       uint32_t dev;
-       uint16_t mode;                          /* read/write */
+       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;
-       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;
-       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;
-               char tag[4];                    /* for iproute */
+               char tag[4];    /* for iproute */
        };
        /* 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;
-       /* 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. */
+       /* 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;
 };
 
@@ -492,8 +494,8 @@ extern struct chan *kern_slash;
 
 struct cname {
        struct kref ref;
-       int alen;                                       /* allocated length */
-       int len;                                        /* strlen(s) */
+       int alen;               /* allocated length */
+       int len;                /* strlen(s) */
        char *s;
 };
 
@@ -517,12 +519,15 @@ struct dev {
        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 */
+       void (*power)(int);     /* power mgt: power(1) → on, power (0) → off */
 //  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);
+       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)));
@@ -547,7 +552,7 @@ enum {
        NSCACHE = (1 << NSLOG),
 };
 
-struct mntwalk {                               /* state for /proc/#/ns */
+struct mntwalk {                       /* state for /proc/#/ns */
        int cddone;
        uint32_t id;
        struct mhead *mh;
@@ -560,7 +565,7 @@ struct mount {
        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;
 };
@@ -568,23 +573,24 @@ struct mount {
 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 mhead *hash;                     /* Hash chain */
+       struct mhead *hash;             /* Hash chain */
 };
 
 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 {
@@ -602,14 +608,13 @@ struct mntparam {
        struct chan *chan;
        struct chan *authchan;
        char *spec;
-       int flags;
 };
 
 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;
-       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;
@@ -629,8 +634,8 @@ struct egrp {
        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 {
@@ -657,9 +662,9 @@ struct skeyset {
  */
 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 {
@@ -679,24 +684,80 @@ struct cmdbuf {
 };
 
 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 {
-       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 the kick routine after qwrite */
-       Qdropoverflow   = (1 << 5),     /* 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 *,
-                                  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 */
@@ -712,6 +773,11 @@ 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);
@@ -727,7 +793,6 @@ void chanfree(struct chan *);
 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 *);
@@ -742,34 +807,29 @@ struct block *concatblock(struct block *);
 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);
-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 *);
-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 cwrite(struct chan *, uint8_t * unused_uint8_p_t, int unused_int, int64_t);
 struct chan *devattach(const char *name, char *spec);
 struct block *devbread(struct chan *, size_t, off64_t);
 size_t devbwrite(struct chan *, struct block *, off64_t);
 struct chan *devclone(struct chan *);
 void devcreate(struct chan *, char *name, int mode, uint32_t perm, char *ext);
 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);
-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);
@@ -777,9 +837,9 @@ void devshutdown(void);
 size_t dev_make_stat(struct chan *c, struct dir *dir, uint8_t *dp, size_t n);
 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 *);
+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 *);
@@ -846,7 +906,7 @@ struct chan *namec_from(struct chan *c, char *name, int amode, int omode,
 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 *);
@@ -866,7 +926,7 @@ 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);
@@ -917,10 +977,10 @@ bool qreadable(struct queue *q);
 bool qwritable(struct queue *q);
 
 void *realloc(void *, uint32_t);
-int readmem(unsigned long offset, char *buf, unsigned long n,
-                       const 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,
-                       size_t size);
+           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, const char *str);
@@ -983,6 +1043,11 @@ uint16_t nhgets(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())
@@ -993,7 +1058,7 @@ void devtabinit();
 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);
 
@@ -1004,8 +1069,8 @@ struct chan *fdtochan(struct fd_table *fdt, int fd, int mode, int chkmnt,
 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 sysfchdir(int fd);
+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);
@@ -1014,7 +1079,6 @@ 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);
@@ -1031,6 +1095,7 @@ 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);
+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);
@@ -1051,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 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);