Convert omode to 9p for devmnt [4/7]
[akaros.git] / kern / drivers / dev / mnt.c
index 55cccec..af219d9 100644 (file)
@@ -12,6 +12,7 @@
 #include <pmap.h>
 #include <smp.h>
 #include <ip.h>
+#include <smallidpool.h>
 
 /*
  * References are managed as follows:
@@ -25,6 +26,7 @@
  */
 
 #define MAXRPC (IOHDRSZ+8192)
+#define MAXTAG MAX_U16_POOL_SZ
 
 static __inline int isxdigit(int c)
 {
@@ -54,12 +56,6 @@ struct mntrpc {
        struct mntrpc *flushed;         /* message this one flushes */
 };
 
-enum {
-       TAGSHIFT = 5,                           /* uint32_t has to be 32 bits */
-       TAGMASK = (1 << TAGSHIFT) - 1,
-       NMASK = (64 * 1024) >> TAGSHIFT,
-};
-
 /* Our TRUNC and remove on close differ from 9ps, so we'll need to translate.
  * I got these flags from http://man.cat-v.org/plan_9/5/open */
 #define MNT_9P_OPEN_OTRUNC             0x10
@@ -73,7 +69,7 @@ struct Mntalloc {
        int nrpcfree;
        int nrpcused;
        uint32_t id;
-       uint32_t tagmask[NMASK];
+       struct u16_pool *tags;
 } mntalloc;
 
 void mattach(struct mnt *, struct chan *, char *unused_char_p_t);
@@ -102,8 +98,8 @@ void (*mntstats) (int unused_int, struct chan *, uint64_t, uint32_t);
 static void mntinit(void)
 {
        mntalloc.id = 1;
-       mntalloc.tagmask[0] = 1;        /* don't allow 0 as a tag */
-       mntalloc.tagmask[NMASK - 1] = 0x80000000UL;     /* don't allow NOTAG */
+       mntalloc.tags = create_u16_pool(MAXTAG);
+       (void) get_u16(mntalloc.tags);  /* don't allow 0 as a tag */
        //fmtinstall('F', fcallfmt);
 /*     fmtinstall('D', dirfmt); */
 /*     fmtinstall('M', dirmodefmt);  */
@@ -304,7 +300,7 @@ struct chan *mntauth(struct chan *c, char *spec)
 
        c->qid = r->reply.aqid;
        c->mchan = m->c;
-       kref_get(&m->c->ref, 1);
+       chan_incref(m->c);
        c->mqid = c->qid;
        c->mode = ORDWR;
 
@@ -370,7 +366,7 @@ static struct chan *mntattach(char *muxattach)
 
        c->qid = r->reply.qid;
        c->mchan = m->c;
-       kref_get(&m->c->ref, 1);
+       chan_incref(m->c);
        c->mqid = c->qid;
 
        poperror();     /* r */
@@ -465,7 +461,7 @@ static struct walkqid *mntwalk(struct chan *c, struct chan *nc, char **name,
                if (wq->clone != c) {
                        wq->clone->type = c->type;
                        wq->clone->mchan = c->mchan;
-                       kref_get(&c->mchan->ref, 1);
+                       chan_incref(c->mchan);
                }
                if (r->reply.nwqid > 0)
                        wq->clone->qid = r->reply.wqid[r->reply.nwqid - 1];
@@ -506,7 +502,7 @@ static int mntstat(struct chan *c, uint8_t * dp, int n)
        } else {
                n = r->reply.nstat;
                memmove(dp, r->reply.stat, n);
-               validstat(dp, n);
+               validstat(dp, n, 0);
                mntdirfix(dp, c);
        }
        poperror();
@@ -529,7 +525,7 @@ static struct chan *mntopencreate(int type, struct chan *c, char *name,
        }
        r->request.type = type;
        r->request.fid = c->fid;
-       r->request.mode = omode & O_ACCMODE;    /* not using openmode, want O_EXEC */
+       r->request.mode = omode_to_9p_accmode(omode);
        if (omode & O_TRUNC)
                r->request.mode |= MNT_9P_OPEN_OTRUNC;
        if (omode & O_REMCLO)
@@ -654,10 +650,17 @@ static int mntwstat(struct chan *c, uint8_t * dp, int n)
        return n;
 }
 
+/* the servers should either return units of whole directory entries
+ * OR support seeking to an arbitrary place. One or other.
+ * Both are fine, but at least one is a minimum.
+ * If the return a partial result, but more than one result,
+ * we'll return a shorter read and the next offset will be aligned
+ */
 static long mntread(struct chan *c, void *buf, long n, int64_t off)
 {
        uint8_t *p, *e;
        int nc, cache, isdir, dirlen;
+       int numdirent = 0;
 
        isdir = 0;
        cache = c->flag & CCACHE;
@@ -682,16 +685,24 @@ static long mntread(struct chan *c, void *buf, long n, int64_t off)
        }
 
        n = mntrdwr(Tread, c, buf, n, off);
+
        if (isdir) {
                for (e = &p[n]; p + BIT16SZ < e; p += dirlen) {
                        dirlen = BIT16SZ + GBIT16(p);
-                       if (p + dirlen > e)
+                       if (p + dirlen > e){
                                break;
-                       validstat(p, dirlen);
+                       }
+                       validstat(p, dirlen, 0);
                        mntdirfix(p, c);
+                       numdirent += dirlen;
+               }
+               if (p != e) {
+                       //error(Esbadstat);
+                       /* not really. Maybe the server supports
+                        * arbitrary seek like go9p now does.
+                        */
+                       n = numdirent;
                }
-               if (p != e)
-                       error(Esbadstat);
        }
        return n;
 }
@@ -808,14 +819,13 @@ void mountio(struct mnt *m, struct mntrpc *r)
        while (waserror()) {
                if (m->rip == current)
                        mntgate(m);
-               if (!strcmp(current_errstr(), "syscall aborted")) {
-                       /* not sure what devmnt wants us to do here.  bail on aborted
-                        * syscall?  keep looping forever? (probably not) */
-                       printk("[kernel] mountio had aborted syscall");
-                       mntflushfree(m, r);
-                       nexterror();
-               }
-               if (strcmp(current_errstr(), Eintr) != 0) {
+               /* Syscall aborts are like Plan 9 Eintr.  For those, we need to change
+                * the old request to a flsh (mntflushalloc) and try again.  We'll
+                * always try to flush, and you can't get out until the flush either
+                * succeeds or errors out with a non-abort/Eintr error. */
+               if (strcmp(current_errstr(), "syscall aborted") &&
+                   strcmp(current_errstr(), Eintr)) {
+                       /* all other errors (not abort or Eintr) */
                        mntflushfree(m, r);
                        nexterror();
                }
@@ -929,6 +939,8 @@ int mntrpcread(struct mnt *m, struct mntrpc *r)
        *l = NULL;
        do {
                b = qremove(m->q);
+               /* TODO: have better block helpers for this and the memmove below */
+               b = linearizeblock(b);
                if (hlen > 0) {
                        b->rp += hlen;
                        len -= hlen;
@@ -1053,26 +1065,12 @@ void mntflushfree(struct mnt *m, struct mntrpc *r)
 
 static int alloctag(void)
 {
-       int i, j;
-       uint32_t v;
-
-       for (i = 0; i < NMASK; i++) {
-               v = mntalloc.tagmask[i];
-               if (v == ~0UL)
-                       continue;
-               for (j = 0; j < 1 << TAGSHIFT; j++)
-                       if ((v & (1 << j)) == 0) {
-                               mntalloc.tagmask[i] |= 1 << j;
-                               return (i << TAGSHIFT) + j;
-                       }
-       }
-       /* panic("no devmnt tags left"); */
-       return NOTAG;
+       return get_u16(mntalloc.tags);
 }
 
 static void freetag(int t)
 {
-       mntalloc.tagmask[t >> TAGSHIFT] &= ~(1 << (t & TAGMASK));
+       put_u16(mntalloc.tags, t);
 }
 
 struct mntrpc *mntralloc(struct chan *c, uint32_t msize)