]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/port/devmnt.c
devmnt: make abandoning fid on botched clunk handle flushes
[plan9front.git] / sys / src / 9 / port / devmnt.c
index adb65155bc3d46963e70156f07a35df60f84dee2..cce379095e4835cea192b04b114107ba3c8e9a75 100644 (file)
@@ -25,15 +25,15 @@ struct Mntrpc
        Fcall   request;        /* Outgoing file system protocol message */
        Fcall   reply;          /* Incoming reply */
        Mnt*    m;              /* Mount device during rpc */
-       Rendez  r;              /* Place to hang out */
+       Rendez* z;              /* Place to hang out */
        uchar*  rpc;            /* I/O Data buffer */
        uint    rpclen;         /* len of buffer */
-       Block   *b;             /* reply blocks */
-       char    done;           /* Rpc completed */
+       Block*  b;              /* reply blocks */
        uvlong  stime;          /* start time for mnt statistics */
        ulong   reqlen;         /* request length for mnt statistics */
        ulong   replen;         /* reply length for mnt statistics */
        Mntrpc* flushed;        /* message this one flushes */
+       char    done;           /* Rpc completed */
 };
 
 enum
@@ -58,10 +58,9 @@ struct Mntalloc
 Mnt*   mntchk(Chan*);
 void   mntdirfix(uchar*, Chan*);
 Mntrpc*        mntflushalloc(Mntrpc*, ulong);
-void   mntflushfree(Mnt*, Mntrpc*);
+Mntrpc*        mntflushfree(Mnt*, Mntrpc*);
 void   mntfree(Mntrpc*);
 void   mntgate(Mnt*);
-void   mntpntfree(Mnt*);
 void   mntqrm(Mnt*, Mntrpc*);
 Mntrpc*        mntralloc(Chan*, ulong);
 long   mntrdwr(int, Chan*, void*, long, vlong);
@@ -75,8 +74,8 @@ Chan* mntchan(void);
 char   Esbadstat[] = "invalid directory entry received from server";
 char   Enoversion[] = "version not established for mount channel";
 
+void   (*mntstats)(int, Chan*, uvlong, ulong);
 
-void (*mntstats)(int, Chan*, uvlong, ulong);
 
 static void
 mntreset(void)
@@ -101,6 +100,7 @@ mntversion(Chan *c, char *version, int msize, int returnlen)
        uchar *msg;
        Mnt *m;
        char *v;
+       Queue *q;
        long k, l;
        uvlong oo;
        char buf[128];
@@ -199,6 +199,16 @@ mntversion(Chan *c, char *version, int msize, int returnlen)
        k = strlen(f.version);
        if(strncmp(f.version, v, k) != 0)
                error("bad 9P version returned from server");
+       if(returnlen > 0 && returnlen < k)
+               error(Eshort);
+
+       v = nil;
+       kstrdup(&v, f.version);
+       q = qopen(10*MAXRPC, 0, nil, nil);
+       if(q == nil){
+               free(v);
+               exhausted("mount queues");
+       }
 
        /* now build Mnt associated with this connection */
        lock(&mntalloc);
@@ -208,24 +218,22 @@ mntversion(Chan *c, char *version, int msize, int returnlen)
        else {
                m = malloc(sizeof(Mnt));
                if(m == 0) {
+                       qfree(q);
+                       free(v);
                        unlock(&mntalloc);
                        exhausted("mount devices");
                }
        }
        m->list = mntalloc.list;
        mntalloc.list = m;
-       m->version = nil;
-       kstrdup(&m->version, f.version);
+       m->version = v;
        m->id = mntalloc.id++;
-       m->q = qopen(10*MAXRPC, 0, nil, nil);
+       m->q = q;
        m->msize = f.msize;
        unlock(&mntalloc);
 
-       if(returnlen > 0){
-               if(returnlen < k)
-                       error(Eshort);
-               memmove(version, f.version, k);
-       }
+       if(returnlen > 0)
+               memmove(version, f.version, k); /* length was checked above */
 
        poperror();     /* msg */
        free(msg);
@@ -564,23 +572,18 @@ mntclunk(Chan *c, int t)
 void
 muxclose(Mnt *m)
 {
-       Mntrpc *q, *r;
+       Mnt *f, **l;
+       Mntrpc *r;
 
-       for(q = m->queue; q; q = r) {
-               r = q->list;
-               mntfree(q);
+       while((r = m->queue) != nil){
+               m->queue = r->list;
+               mntfree(r);
        }
        m->id = 0;
        free(m->version);
        m->version = nil;
-       mntpntfree(m);
-}
-
-void
-mntpntfree(Mnt *m)
-{
-       Mnt *f, **l;
-       Queue *q;
+       qfree(m->q);
+       m->q = nil;
 
        lock(&mntalloc);
        l = &mntalloc.list;
@@ -593,10 +596,7 @@ mntpntfree(Mnt *m)
        }
        m->list = mntalloc.mntfree;
        mntalloc.mntfree = m;
-       q = m->q;
        unlock(&mntalloc);
-
-       qfree(q);
 }
 
 static void
@@ -777,13 +777,21 @@ mountio(Mnt *m, Mntrpc *r)
                if(m->rip == up)
                        mntgate(m);
                if(strcmp(up->errstr, Eintr) != 0){
-                       mntflushfree(m, r);
+                       r = mntflushfree(m, r);
+                       switch(r->request.type){
+                       case Tremove:
+                       case Tclunk:
+                               /* botch, abandon fid */ 
+                               if(strcmp(up->errstr, Ehungup) != 0)
+                                       r->c->fid = 0;
+                       }
                        nexterror();
                }
                r = mntflushalloc(r, m->msize);
        }
 
        lock(m);
+       r->z = &up->sleep;
        r->m = m;
        r->list = m->queue;
        m->queue = r;
@@ -793,8 +801,12 @@ mountio(Mnt *m, Mntrpc *r)
        if(m->msize == 0)
                panic("msize");
        n = convS2M(&r->request, r->rpc, m->msize);
-       if(n < 0)
-               panic("bad message type in mountio");
+       if(n <= 0){
+               print("mountio: proc %s %lud: convS2M returned %d for tag %d fid %d T%d\n",
+                       up->text, up->pid, n, r->request.tag, r->request.fid, r->request.type);
+               error(Emountrpc);
+       }
+               
        if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
                error(Emountrpc);
        r->stime = fastticks(nil);
@@ -806,7 +818,7 @@ mountio(Mnt *m, Mntrpc *r)
                if(m->rip == 0)
                        break;
                unlock(m);
-               sleep(&r->r, rpcattn, r);
+               sleep(r->z, rpcattn, r);
                if(r->done){
                        poperror();
                        mntflushfree(m, r);
@@ -924,7 +936,7 @@ mntgate(Mnt *m)
        m->rip = 0;
        for(q = m->queue; q; q = q->list) {
                if(q->done == 0)
-               if(wakeup(&q->r))
+               if(wakeup(q->z))
                        break;
        }
        unlock(m);
@@ -934,6 +946,7 @@ void
 mountmux(Mnt *m, Mntrpc *r)
 {
        Mntrpc **l, *q;
+       Rendez *z;
 
        lock(m);
        l = &m->queue;
@@ -941,6 +954,10 @@ mountmux(Mnt *m, Mntrpc *r)
                /* look for a reply to a message */
                if(q->request.tag == r->reply.tag) {
                        *l = q->list;
+                       if(mntstats != nil)
+                               (*mntstats)(q->request.type,
+                                       m->c, q->stime,
+                                       q->reqlen + r->replen);
                        if(q != r) {
                                /*
                                 * Completed someone else.
@@ -949,15 +966,13 @@ mountmux(Mnt *m, Mntrpc *r)
                                q->reply = r->reply;
                                q->b = r->b;
                                r->b = nil;
-                       }
-                       q->done = 1;
+                               z = q->z;
+                       } else
+                               z = nil;
+                       q->done = 1;    /* hands off */
+                       if(z != nil)
+                               wakeup(z);
                        unlock(m);
-                       if(mntstats != nil)
-                               (*mntstats)(q->request.type,
-                                       m->c, q->stime,
-                                       q->reqlen + r->replen);
-                       if(q != r)
-                               wakeup(&q->r);
                        return;
                }
                l = &q->list;
@@ -992,9 +1007,9 @@ mntflushalloc(Mntrpc *r, ulong iounit)
  *  flush and the original message from the unanswered
  *  request queue.  Mark the original message as done
  *  and if it hasn't been answered set the reply to to
- *  Rflush.
+ *  Rflush. Return the original rpc.
  */
-void
+Mntrpc*
 mntflushfree(Mnt *m, Mntrpc *r)
 {
        Mntrpc *fr;
@@ -1005,10 +1020,12 @@ mntflushfree(Mnt *m, Mntrpc *r)
                        r->reply.type = Rflush;
                        mntqrm(m, r);
                }
-               if(fr)
-                       mntfree(r);
+               if(fr == nil)
+                       break;
+               mntfree(r);
                r = fr;
        }
+       return r;
 }
 
 int
@@ -1134,7 +1151,7 @@ mntchk(Chan *c)
        /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
 
        if(c->mchan == nil)
-               panic("mntchk 1: nil mchan c %s\n", chanpath(c));
+               panic("mntchk 1: nil mchan c %s", chanpath(c));
 
        m = c->mchan->mux;