summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2012-08-24 13:00:14 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2012-08-24 13:00:14 +0200
commitd404e9e9f8250f740bacb0b30d586ea1ad808015 (patch)
treef8e93250684eda8555479962b7ae9e14e79663fc
parent80a5bfc1d812618d4f6a16eb29026f412df7b56c (diff)
downloadplan9front-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.c32
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;