diff options
| author | cinap_lenrek <cinap_lenrek@gmx.de> | 2012-08-24 13:00:14 +0200 |
|---|---|---|
| committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2012-08-24 13:00:14 +0200 |
| commit | d404e9e9f8250f740bacb0b30d586ea1ad808015 (patch) | |
| tree | f8e93250684eda8555479962b7ae9e14e79663fc | |
| parent | 80a5bfc1d812618d4f6a16eb29026f412df7b56c (diff) | |
| download | plan9front-d404e9e9f8250f740bacb0b30d586ea1ad808015.tar.xz | |
devmnt: more carefull wakeup in mountmux
once we set q->done = 1 in mountmux, the sleeper might return freeing q
so the wakeup might access invalid memory. we change the embedded Rendez
structure in the Mntrpc into a pointer to the sleeping procs up->sleep
rendez so the rendez is always going to be valid even if the rpc has been
freed.
the call to mntstats was moved before we set q->done also to prevent
accessing invalid memory.
| -rw-r--r-- | sys/src/9/port/devmnt.c | 32 |
1 files changed, 18 insertions, 14 deletions
diff --git a/sys/src/9/port/devmnt.c b/sys/src/9/port/devmnt.c index 12aa51459..5f46b9467 100644 --- a/sys/src/9/port/devmnt.c +++ b/sys/src/9/port/devmnt.c @@ -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 @@ -75,8 +75,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) @@ -784,6 +784,7 @@ mountio(Mnt *m, Mntrpc *r) } lock(m); + r->z = &up->sleep; r->m = m; r->list = m->queue; m->queue = r; @@ -806,7 +807,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 +925,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 +935,7 @@ void mountmux(Mnt *m, Mntrpc *r) { Mntrpc **l, *q; + Rendez *z; lock(m); l = &m->queue; @@ -941,6 +943,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 +955,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; |
