git: 9front

Download patch

ref: cf64c553959ac75f45f28a9b5879240ecb35230b
parent: e4878ad8a758ee30a459607841d95b5e9f275464
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Fri Nov 1 14:57:11 EDT 2013

rio: properly handle follow up flushes (fixes unexpected reply tag)

when multiple flushes are send, they need to be replied
in order. we ensure this by having the flush xfid taking
over the flushtag (synchronized with a new fs->csyncflush
channel) so the next flush will flush the previous flush.

--- a/sys/src/cmd/rio/dat.h
+++ b/sys/src/cmd/rio/dat.h
@@ -285,6 +285,7 @@
 		int		pid;
 		char		*user;
 		Channel	*cxfidalloc;	/* chan(Xfid*) */
+		Channel	*csyncflush;	/* chan(int) */
 		Fid		*fids[Nhash];
 };
 
@@ -357,3 +358,4 @@
 int		snarfversion;	/* updated each time it is written */
 int		messagesize;		/* negotiated in 9P version setup */
 int		shiftdown;
+int		debug;
--- a/sys/src/cmd/rio/fsys.c
+++ b/sys/src/cmd/rio/fsys.c
@@ -18,10 +18,6 @@
 
 int	messagesize = 8192+IOHDRSZ;	/* good start */
 
-enum{
-	DEBUG = 0
-};
-
 Dirtab dirtab[]=
 {
 	{ ".",			QTDIR,	Qdir,			0500|DMDIR },
@@ -142,6 +138,9 @@
 		close(fd);
 	}
 	fs->user = estrdup(buf);
+	fs->csyncflush = chancreate(sizeof(int), 0);
+	if(fs->csyncflush == nil)
+		error("chancreate syncflush");
 	fs->cxfidalloc = cxfidalloc;
 	pid = getpid();
 
@@ -210,7 +209,7 @@
 		x->buf = buf;
 		if(convM2S(buf, n, x) != n)
 			error("convert error in convM2S");
-		if(DEBUG)
+		if(debug)
 			fprint(2, "rio:<-%F\n", &x->Fcall);
 		if(fcall[x->type] == nil)
 			x = filsysrespond(fs, x, &t, Ebadfcall);
@@ -266,7 +265,7 @@
 		error("convert error in convS2M");
 	if(write(fs->sfd, x->buf, n) != n)
 		error("write error in respond");
-	if(DEBUG)
+	if(debug)
 		fprint(2, "rio:->%F\n", t);
 	free(x->buf);
 	x->buf = nil;
@@ -307,14 +306,21 @@
 {
 	Fcall t;
 
-		return filsysrespond(fs, x, &t, "rio: authentication not required");
+	return filsysrespond(fs, x, &t, "rio: authentication not required");
 }
 
 static
 Xfid*
-filsysflush(Filsys*, Xfid *x, Fid*)
+filsysflush(Filsys *fs, Xfid *x, Fid*)
 {
 	sendp(x->c, xfidflush);
+
+	/*
+	 * flushes need to be replied in order. xfidflush() will
+	 * awaken us when the flush has been queued.
+	 */
+	recv(fs->csyncflush, nil);
+
 	return nil;
 }
 
--- a/sys/src/cmd/rio/rio.c
+++ b/sys/src/cmd/rio/rio.c
@@ -156,6 +156,11 @@
 	case 's':
 		scrolling = TRUE;
 		break;
+	case 'D':
+		debug++;
+		break;
+	default:
+		usage();
 	}ARGEND
 
 	if(getwd(buf, sizeof buf) == nil)
--- a/sys/src/cmd/rio/xfid.c
+++ b/sys/src/cmd/rio/xfid.c
@@ -124,24 +124,44 @@
 
 	for(xf=xfid; xf; xf=xf->next)
 		if(xf->flushtag == x->oldtag){
-			xf->flushtag = -1;
-			xf->flushing = TRUE;
 			incref(xf);	/* to hold data structures up at tail of synchronization */
 			if(xf->ref == 1)
 				error("ref 1 in flush");
-			if(canqlock(&xf->active)){
-				qunlock(&xf->active);
-				sendul(xf->flushc, 0);
-			}else{
-				qlock(&xf->active);	/* wait for him to finish */
-				qunlock(&xf->active);
-			}
-			xf->flushing = FALSE;
-			if(decref(xf) == 0)
-				sendp(cxfidfree, xf);
+			/* take over flushtag so follow up flushes wait for us */
+			x->flushtag = x->oldtag;
+			xf->flushtag = -1;
 			break;
 		}
+
+	/*
+	 * wakeup filsysflush() in the filsysproc so the next
+	 * flush can come in.
+	 */
+	sendul(x->fs->csyncflush, 0);
+
+	if(xf){
+		qlock(&xf->active);
+		if(xf->buf){	/* not responded yet? */
+			xf->flushing = TRUE;
+			qunlock(&xf->active);
+			sendul(xf->flushc, 0);
+			xf->flushing = FALSE;
+		}else{
+			qunlock(&xf->active);
+		}
+		if(decref(xf) == 0)
+			sendp(cxfidfree, xf);
+	}
+
+	qlock(&x->active);
+	if(x->flushing){
+		qunlock(&x->active);
+		recv(x->flushc, nil);	/* wakeup flushing xfid */
+		filsyscancel(x);
+		return;
+	}
 	filsysrespond(x->fs, x, &t, nil);
+	qunlock(&x->active);
 }
 
 void
--