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.
This commit is contained in:
parent
80a5bfc1d8
commit
d404e9e9f8
1 changed files with 18 additions and 14 deletions
|
@ -25,15 +25,15 @@ struct Mntrpc
|
||||||
Fcall request; /* Outgoing file system protocol message */
|
Fcall request; /* Outgoing file system protocol message */
|
||||||
Fcall reply; /* Incoming reply */
|
Fcall reply; /* Incoming reply */
|
||||||
Mnt* m; /* Mount device during rpc */
|
Mnt* m; /* Mount device during rpc */
|
||||||
Rendez r; /* Place to hang out */
|
Rendez* z; /* Place to hang out */
|
||||||
uchar* rpc; /* I/O Data buffer */
|
uchar* rpc; /* I/O Data buffer */
|
||||||
uint rpclen; /* len of buffer */
|
uint rpclen; /* len of buffer */
|
||||||
Block *b; /* reply blocks */
|
Block* b; /* reply blocks */
|
||||||
char done; /* Rpc completed */
|
|
||||||
uvlong stime; /* start time for mnt statistics */
|
uvlong stime; /* start time for mnt statistics */
|
||||||
ulong reqlen; /* request length for mnt statistics */
|
ulong reqlen; /* request length for mnt statistics */
|
||||||
ulong replen; /* reply length for mnt statistics */
|
ulong replen; /* reply length for mnt statistics */
|
||||||
Mntrpc* flushed; /* message this one flushes */
|
Mntrpc* flushed; /* message this one flushes */
|
||||||
|
char done; /* Rpc completed */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -75,8 +75,8 @@ Chan* mntchan(void);
|
||||||
char Esbadstat[] = "invalid directory entry received from server";
|
char Esbadstat[] = "invalid directory entry received from server";
|
||||||
char Enoversion[] = "version not established for mount channel";
|
char Enoversion[] = "version not established for mount channel";
|
||||||
|
|
||||||
|
void (*mntstats)(int, Chan*, uvlong, ulong);
|
||||||
|
|
||||||
void (*mntstats)(int, Chan*, uvlong, ulong);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mntreset(void)
|
mntreset(void)
|
||||||
|
@ -784,6 +784,7 @@ mountio(Mnt *m, Mntrpc *r)
|
||||||
}
|
}
|
||||||
|
|
||||||
lock(m);
|
lock(m);
|
||||||
|
r->z = &up->sleep;
|
||||||
r->m = m;
|
r->m = m;
|
||||||
r->list = m->queue;
|
r->list = m->queue;
|
||||||
m->queue = r;
|
m->queue = r;
|
||||||
|
@ -806,7 +807,7 @@ mountio(Mnt *m, Mntrpc *r)
|
||||||
if(m->rip == 0)
|
if(m->rip == 0)
|
||||||
break;
|
break;
|
||||||
unlock(m);
|
unlock(m);
|
||||||
sleep(&r->r, rpcattn, r);
|
sleep(r->z, rpcattn, r);
|
||||||
if(r->done){
|
if(r->done){
|
||||||
poperror();
|
poperror();
|
||||||
mntflushfree(m, r);
|
mntflushfree(m, r);
|
||||||
|
@ -924,7 +925,7 @@ mntgate(Mnt *m)
|
||||||
m->rip = 0;
|
m->rip = 0;
|
||||||
for(q = m->queue; q; q = q->list) {
|
for(q = m->queue; q; q = q->list) {
|
||||||
if(q->done == 0)
|
if(q->done == 0)
|
||||||
if(wakeup(&q->r))
|
if(wakeup(q->z))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
unlock(m);
|
unlock(m);
|
||||||
|
@ -934,6 +935,7 @@ void
|
||||||
mountmux(Mnt *m, Mntrpc *r)
|
mountmux(Mnt *m, Mntrpc *r)
|
||||||
{
|
{
|
||||||
Mntrpc **l, *q;
|
Mntrpc **l, *q;
|
||||||
|
Rendez *z;
|
||||||
|
|
||||||
lock(m);
|
lock(m);
|
||||||
l = &m->queue;
|
l = &m->queue;
|
||||||
|
@ -941,6 +943,10 @@ mountmux(Mnt *m, Mntrpc *r)
|
||||||
/* look for a reply to a message */
|
/* look for a reply to a message */
|
||||||
if(q->request.tag == r->reply.tag) {
|
if(q->request.tag == r->reply.tag) {
|
||||||
*l = q->list;
|
*l = q->list;
|
||||||
|
if(mntstats != nil)
|
||||||
|
(*mntstats)(q->request.type,
|
||||||
|
m->c, q->stime,
|
||||||
|
q->reqlen + r->replen);
|
||||||
if(q != r) {
|
if(q != r) {
|
||||||
/*
|
/*
|
||||||
* Completed someone else.
|
* Completed someone else.
|
||||||
|
@ -949,15 +955,13 @@ mountmux(Mnt *m, Mntrpc *r)
|
||||||
q->reply = r->reply;
|
q->reply = r->reply;
|
||||||
q->b = r->b;
|
q->b = r->b;
|
||||||
r->b = nil;
|
r->b = nil;
|
||||||
}
|
z = q->z;
|
||||||
q->done = 1;
|
} else
|
||||||
|
z = nil;
|
||||||
|
q->done = 1; /* hands off */
|
||||||
|
if(z != nil)
|
||||||
|
wakeup(z);
|
||||||
unlock(m);
|
unlock(m);
|
||||||
if(mntstats != nil)
|
|
||||||
(*mntstats)(q->request.type,
|
|
||||||
m->c, q->stime,
|
|
||||||
q->reqlen + r->replen);
|
|
||||||
if(q != r)
|
|
||||||
wakeup(&q->r);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
l = &q->list;
|
l = &q->list;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue