git: 9front

Download patch

ref: dd2b536491fd56e9296df648d0fcb101cde24995
parent: b4e7116f3a55b1b228adef6b8f1a8887792c4a97
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Fri Aug 24 09:00:14 EDT 2012

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.

--- a/sys/src/9/port/devmnt.c
+++ b/sys/src/9/port/devmnt.c
@@ -25,15 +25,15 @@
 	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 @@
 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 @@
 	}
 
 	lock(m);
+	r->z = &up->sleep;
 	r->m = m;
 	r->list = m->queue;
 	m->queue = r;
@@ -806,7 +807,7 @@
 		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 @@
 	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 @@
 mountmux(Mnt *m, Mntrpc *r)
 {
 	Mntrpc **l, *q;
+	Rendez *z;
 
 	lock(m);
 	l = &m->queue;
@@ -941,6 +943,10 @@
 		/* 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 @@
 				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;
--