shithub: riscv

Download patch

ref: a0d4c5e208405f84076891faaa43235bb2b87fc2
parent: a840b597cad282e837560b65dad89aa0cfd4af77
author: cinap_lenrek <[email protected]>
date: Sat Jul 23 22:21:32 EDT 2016

make error handling in 9p service loops consistent

when we get eof, stop the loop immidiately and do not
rely on the read to eventually return an error.

when convM2S() fails to decode the message, error out
and stop the loop. there is no point in continuing.

--- a/sys/src/cmd/9660srv/main.c
+++ b/sys/src/cmd/9660srv/main.c
@@ -164,22 +164,11 @@
 	pid = getpid();
 	fmtinstall('F', fcallfmt);
 
-	for(;;){
-		/*
-		 * reading from a pipe or a network device
-		 * will give an error after a few eof reads.
-		 * however, we cannot tell the difference
-		 * between a zero-length read and an interrupt
-		 * on the processes writing to us,
-		 * so we wait for the error.
-		 */
-		n = read9pmsg(srvfd, mdata, sizeof mdata);
+	while((n = read9pmsg(srvfd, mdata, sizeof mdata)) != 0){
 		if(n < 0)
-			break;
-		if(n == 0)
-			continue;
-		if(convM2S(mdata, n, req) == 0)
-			continue;
+			panic(1, "mount read");
+		if(convM2S(mdata, n, req) != n)
+			panic(1, "convM2S format error");
 
 		if(chatty)
 			fprint(2, "9660srv %d:<-%F\n", pid, req);
--- a/sys/src/cmd/9nfs/9p.c
+++ b/sys/src/cmd/9nfs/9p.c
@@ -40,13 +40,13 @@
 	}
 again:
 	n = read9pmsg(s->fd, s->data, messagesize);
+	if(n == 0)
+		return -1;
 	if(n < 0){
 		clog("xmesg read error: %r\n");
 		return -1;
 	}
-	if(n == 0)
-		goto again;
-	if(convM2S(s->data, n, &s->f) <= 0){
+	if(convM2S(s->data, n, &s->f) != n){
 		clog("xmesg bad convM2S %d %.2x %.2x %.2x %.2x\n",
 			n, ((uchar*)s->data)[0], ((uchar*)s->data)[1],
 			((uchar*)s->data)[2], ((uchar*)s->data)[3]);
--- a/sys/src/cmd/acme/fsys.c
+++ b/sys/src/cmd/acme/fsys.c
@@ -148,8 +148,7 @@
 	x = nil;
 	for(;;){
 		buf = emalloc(messagesize+UTFmax);	/* overflow for appending partial rune in xfidwrite */
-		while((n = read9pmsg(sfd, buf, messagesize)) == 0 && !closing)
-			;
+		n = read9pmsg(sfd, buf, messagesize);
 		if(n <= 0){
 			if(closing)
 				break;
--- a/sys/src/cmd/auth/keyfs.c
+++ b/sys/src/cmd/auth/keyfs.c
@@ -1038,14 +1038,11 @@
 	/* after restart, let the system settle for 5 mins before warning */
 	lastwarning = time(0) - 24*60*60 + 5*60;
 
-	for(;;){
-		n = read9pmsg(in, mdata, messagesize);
-		if(n == 0)
-			continue;
+	while((n = read9pmsg(in, mdata, messagesize)) != 0){
 		if(n < 0)
-			error("mount read %d", n);
-		if(convM2S(mdata, n, &rhdr) == 0)
-			continue;
+			error("mount read: %r");
+		if(convM2S(mdata, n, &rhdr) != n)
+			error("convM2S format error: %r");
 
 		if(newkeys())
 			readusers();
--- a/sys/src/cmd/aux/9pcon.c
+++ b/sys/src/cmd/aux/9pcon.c
@@ -49,7 +49,7 @@
 		sysfatal("out of memory");
 
 	while((n = read9pmsg(fd, buf, messagesize)) > 0){
-		if(convM2S(buf, n, &f) == 0){
+		if(convM2S(buf, n, &f) != n){
 			print("convM2S: %r\n");
 			continue;
 		}
--- a/sys/src/cmd/aux/consolefs.c
+++ b/sys/src/cmd/aux/consolefs.c
@@ -681,18 +681,13 @@
 		}
 		free(d);
 		r = allocreq(fs, messagesize);
-		while((n = read9pmsg(fs->fd, r->buf, messagesize)) == 0)
-			;
+		n = read9pmsg(fs->fd, r->buf, messagesize);
+		if(n == 0)
+			threadexitsall("unmounted");
 		if(n < 0)
-			fatal("unmounted");
-
-		if(convM2S(r->buf, n, &r->f) == 0){
-			fprint(2, "can't convert %ux %ux %ux\n", r->buf[0],
-				r->buf[1], r->buf[2]);
-			free(r);
-			continue;
-		}
-
+			fatal("mount read: %r");
+		if(convM2S(r->buf, n, &r->f) != n)
+			fatal("convM2S format error: %r");
 
 		f = fsgetfid(fs, r->f.fid);
 		r->fid = f;
--- a/sys/src/cmd/aux/depend.c
+++ b/sys/src/cmd/aux/depend.c
@@ -365,19 +365,15 @@
 	for(;;){
 		r = allocreq(messagesize);
 		qlock(&iolock);
-		while((n = read9pmsg(fs->fd, r->buf, messagesize)) == 0)
-			;
-		qunlock(&iolock);
+		n = read9pmsg(fs->fd, r->buf, messagesize);
+		if(n == 0)
+			threadexitsall("unmounted");
 		if(n < 0)
-			fatal("read9pmsg error: %r");
+			fatal("mount read: %r");
+		if(convM2S(r->buf, n, &r->f) != n)
+			fatal("convM2S format error: %r");
+		qunlock(&iolock);
 
-		if(convM2S(r->buf, n, &r->f) == 0){
-			fprint(2, "can't convert %ux %ux %ux\n", r->buf[0],
-				r->buf[1], r->buf[2]);
-			free(r);
-			continue;
-		}
-
 		f = fsgetfid(fs, r->f.fid);
 		r->fid = f;
 		if(debug)
@@ -388,7 +384,6 @@
 		(*fcall[t])(fs, r, f);
 		fsputfid(fs, f);
 	}
-
 }
 
 /*
--- a/sys/src/cmd/aux/searchfs.c
+++ b/sys/src/cmd/aux/searchfs.c
@@ -592,26 +592,12 @@
 	int n;
 
 	buf = emalloc(messagesize);
-	for(;;){
-		/*
-		 * reading from a pipe or a network device
-		 * will give an error after a few eof reads
-		 * however, we cannot tell the difference
-		 * between a zero-length read and an interrupt
-		 * on the processes writing to us,
-		 * so we wait for the error
-		 */
-		n = read9pmsg(fd, buf, messagesize);
-		if(n == 0)
-			continue;
+	while((n = read9pmsg(fd, buf, messagesize)) != 0){
 		if(n < 0)
-			fatal("mount read");
-
+			fatal("mount read: %r");
 		rpc.data = (char*)buf + IOHDRSZ;
-		if(convM2S(buf, n, &rpc) == 0)
-			continue;
-		// fprint(2, "recv: %F\n", &rpc);
-
+		if(convM2S(buf, n, &rpc) != n)
+			fatal("convM2S format error: %r");
 
 		/*
 		 * flushes are way too hard.
--- a/sys/src/cmd/bzfs/oramfs.c
+++ b/sys/src/cmd/bzfs/oramfs.c
@@ -743,22 +743,11 @@
 
 	pid = getpid();
 
-	for(;;){
-		/*
-		 * reading from a pipe or a network device
-		 * will give an error after a few eof reads.
-		 * however, we cannot tell the difference
-		 * between a zero-length read and an interrupt
-		 * on the processes writing to us,
-		 * so we wait for the error.
-		 */
-		n = read9pmsg(mfd[0], mdata, messagesize);
+	while((n = read9pmsg(mfd[0], mdata, messagesize)) != 0){
 		if(n < 0)
 			error("mount read: %r");
-		if(n == 0)
-			continue;
-		if(convM2S(mdata, n, &thdr) == 0)
-			continue;
+		if(convM2S(mdata, n, &thdr) != n)
+			error("convM2S format error: %r");
 
 		if(debug)
 			fprint(2, "ramfs %d:<-%F\n", pid, &thdr);
--- a/sys/src/cmd/cfs/cfs.c
+++ b/sys/src/cmd/cfs/cfs.c
@@ -808,14 +808,14 @@
 	char buf[128];
 
 	olen = p->len;
-	while((p->len = read9pmsg(p->fd[0], datarcv, sizeof(datarcv))) == 0)
-		;
+	p->len = read9pmsg(p->fd[0], datarcv, sizeof(datarcv));
+	if(p->len == 0)
+		exits("");
 	if(p->len < 0){
 		snprint(buf, sizeof buf, "read9pmsg(%d)->%ld: %r",
 			p->fd[0], p->len);
 		error(buf);
 	}
-
 	if((rlen = convM2S(datarcv, p->len, f)) != p->len)
 		error("rcvmsg format error, expected length %d, got %d",
 			rlen, p->len);
--- a/sys/src/cmd/cpu.c
+++ b/sys/src/cmd/cpu.c
@@ -1028,14 +1028,7 @@
 	ncpunote = 0;
 	for(;;){
 		n = read9pmsg(fd, buf, sizeof(buf));
-		if(n < 0){
-			if(dbg)
-				fprint(2, "read9pmsg(%d) returns %d: %r\n", fd, n);
-			break;
-		}
-		if(n == 0)
-			continue;
-		if(convM2S(buf, n, &f) <= BIT16SZ)
+		if(n <= 0 || convM2S(buf, n, &f) != n)
 			break;
 		if(dbg)
 			fprint(2, "notefs: ->%F\n", &f);
--- a/sys/src/cmd/cwfs/srv.c
+++ b/sys/src/cmd/cwfs/srv.c
@@ -104,8 +104,9 @@
 	Msgbuf *mb, *ms;
 	uchar *b, *p, *e;
 	int n, m;
-	char buf[ERRMAX];
+	char err[ERRMAX];
 
+	err[0] = 0;
 	chan = aux;
 	srv = chan->pdata;
 
@@ -116,13 +117,13 @@
 	e = b + mb->count;
 
 Read:
-	while((n = read(srv->fd, p, e - p)) >= 0){
+	while((n = read(srv->fd, p, e - p)) > 0){
 		p += n;
 		while((p - b) >= BIT32SZ){
 			m = GBIT32(b);
 			if((m < BIT32SZ) || (m > mb->count)){
-				werrstr("bad length in 9P2000 message header");
-				goto Error;
+				strcpy(err, "bad length in 9P2000 message header");
+				goto Hangup;
 			}
 			if((n = (p - b) - m) < 0){
 				e = b + m;
@@ -149,12 +150,11 @@
 		e = b + mb->count;
 	}
 
-Error:
-	rerrstr(buf, sizeof(buf));
-	if(strstr(buf, "interrupt"))
-		goto Read;
+	if(n < 0)
+		errstr(err, sizeof(err));
 
-	chanhangup(chan, buf);
+Hangup:
+	chanhangup(chan, err);
 	srvput(srv);
 
 	mbfree(mb);
--- a/sys/src/cmd/dossrv/xfssrv.c
+++ b/sys/src/cmd/dossrv/xfssrv.c
@@ -135,22 +135,11 @@
 	pid = getpid();
 
 	fmtinstall('F', fcallfmt);
-	for(;;){
-		/*
-		 * reading from a pipe or a network device
-		 * will give an error after a few eof reads.
-		 * however, we cannot tell the difference
-		 * between a zero-length read and an interrupt
-		 * on the processes writing to us,
-		 * so we wait for the error.
-		 */
-		n = read9pmsg(srvfd, mdata, sizeof mdata);
+	while((n = read9pmsg(srvfd, mdata, sizeof mdata)) != 0){
 		if(n < 0)
-			break;
-		if(n == 0)
-			continue;
-		if(convM2S(mdata, n, req) == 0)
-			continue;
+			panic("mount read");
+		if(convM2S(mdata, n, req) != n)
+			panic("convM2S format error");
 
 		if(chatty)
 			fprint(2, "dossrv %d:<-%F\n", pid, req);
--- a/sys/src/cmd/exportfs/exportfs.c
+++ b/sys/src/cmd/exportfs/exportfs.c
@@ -408,12 +408,11 @@
 	 */
 	for(;;) {
 		r = getsbuf();
-		while((n = read9pmsg(0, r->buf, messagesize)) == 0)
-			;
+		n = read9pmsg(0, r->buf, messagesize);
 		if(n <= 0)
 			fatal(nil);
 	Message:
-		if(convM2S(r->buf, n, &r->work) == 0)
+		if(convM2S(r->buf, n, &r->work) != n)
 			fatal("convM2S format error");
 
 		DEBUG(DFD, "%F\n", &r->work);
--- a/sys/src/cmd/ip/ftpfs/ftpfs.c
+++ b/sys/src/cmd/ip/ftpfs/ftpfs.c
@@ -255,7 +255,7 @@
 void
 io(void)
 {
-	char *err, buf[ERRMAX];
+	char *err;
 	int n;
 
 	kapid = kaproc();
@@ -262,16 +262,12 @@
 
 	while(!dying){
 		n = read9pmsg(mfd, mdata, messagesize);
-		if(n < 0){
-			errstr(buf, sizeof buf);
-			if(buf[0]=='\0' || strstr(buf, "hungup"))
-				exits("");
-			fatal("mount read: %s\n", buf);
-		}
 		if(n == 0)
-			continue;
-		if(convM2S(mdata, n, &thdr) == 0)
-			continue;
+			break;
+		if(n < 0)
+			fatal("mount read: %r");
+		if(convM2S(mdata, n, &thdr) != n)
+			fatal("convM2S format error: %r");
 
 		if(debug)
 			fprint(2, "<-%F\n", &thdr);/**/
--- a/sys/src/cmd/lnfs.c
+++ b/sys/src/cmd/lnfs.c
@@ -526,22 +526,11 @@
 
 	pid = getpid();
 
-	for(;;){
-		/*
-		 * reading from a pipe or a network device
-		 * will give an error after a few eof reads.
-		 * however, we cannot tell the difference
-		 * between a zero-length read and an interrupt
-		 * on the processes writing to us,
-		 * so we wait for the error.
-		 */
-		n = read9pmsg(mfd[0], mdata, messagesize);
+	while((n = read9pmsg(mfd[0], mdata, messagesize)) != 0){
 		if(n < 0)
-			sysfatal("mount read");
-		if(n == 0)
-			continue;
-		if(convM2S(mdata, n, &thdr) == 0)
-			continue;
+			sysfatal("mount read: %r");
+		if(convM2S(mdata, n, &thdr) != n)
+			sysfatal("convM2S format error: %r");
 
 		if(debug)
 			fprint(2, "%s %d:<-%F\n", argv0, pid, &thdr);
--- a/sys/src/cmd/ndb/cs.c
+++ b/sys/src/cmd/ndb/cs.c
@@ -321,7 +321,7 @@
 		procsetname("%s", mntpt);
 		break;
 	case -1:
-		error("fork failed\n");
+		error("fork failed");
 	default:
 		/*
 		 *  put ourselves into the file system
@@ -328,7 +328,7 @@
 		 */
 		close(p[0]);
 		if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
-			error("mount failed\n");
+			error("mount failed");
 		_exits(0);
 	}
 	mfd[0] = mfd[1] = p[0];
@@ -447,13 +447,13 @@
 		if(n < 0)
 			error("mount read");
 		if(n == 0)
-			continue;
+			break;
 		job = newjob();
 		if(convM2S(mdata, n, &job->request) != n){
 			syslog(1, logfile, "format error %ux %ux %ux %ux %ux",
 				mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]);
 			freejob(job);
-			continue;
+			break;
 		}
 		qlock(&dblock);
 		mf = newfid(job->request.fid);
--- a/sys/src/cmd/paqfs/paqfs.c
+++ b/sys/src/cmd/paqfs/paqfs.c
@@ -812,14 +812,11 @@
 
 	pid = getpid();
 
-	for(;;){
-		n = read9pmsg(fd, mdata, mesgsize);
+	while((n = read9pmsg(fd, mdata, mesgsize)) != 0){
 		if(n < 0)
-			sysfatal("mount read");
-		if(n == 0)
-			continue;
-		if(convM2S(mdata, n, &rhdr) == 0)
-			continue;
+			sysfatal("mount read: %r");
+		if(convM2S(mdata, n, &rhdr) != n)
+			sysfatal("convM2S format error: %r");
 
 		if(debug)
 			fprint(2, "paqfs %d:<-%F\n", pid, &rhdr);
--- a/sys/src/cmd/plumb/fsys.c
+++ b/sys/src/cmd/plumb/fsys.c
@@ -237,10 +237,11 @@
 		if(buf == nil)
 			error("malloc failed: %r");
 		qlock(&readlock);
-		while((n = read9pmsg(srvfd, buf, messagesize)) == 0)
-			;
-		if(n < 0)
+		n = read9pmsg(srvfd, buf, messagesize);
+		if(n == 0)
 			threadexitsall("unmounted");
+		if(n < 0)
+			error("mount read: %r");
 		if(readlock.head == nil)	/* no other processes waiting to read; start one */
 			proccreate(fsysproc, nil, Stack);
 		qunlock(&readlock);
--- a/sys/src/cmd/ratfs/proto.c
+++ b/sys/src/cmd/ratfs/proto.c
@@ -56,16 +56,14 @@
 	Fcall	rhdr;
 	int n;
 	
-	for(;;){
-		n = read9pmsg(srvfd, rbuf, sizeof rbuf-1);
-		if(n <= 0)
-			fatal("mount read");
-		if(convM2S(rbuf, n, &rhdr) == 0){
+	while((n = read9pmsg(srvfd, rbuf, sizeof rbuf-1)) != 0){
+		if(n < 0)
+			fatal("mount read: %r");
+		if(convM2S(rbuf, n, &rhdr) != n){
 			if(debugfd >= 0)
 				fprint(2, "%s: malformed message\n", argv0);
-			continue;
+			fatal("convM2S format error: %r");
 		}
-		
 		if(debugfd >= 0)
 			fprint(debugfd, "<-%F\n", &rhdr);/**/
 
@@ -94,9 +92,9 @@
 		fprint(debugfd, "->%F\n", r);/**/
 	n = convS2M(r, rbuf, sizeof rbuf);
 	if(n == 0)
-		sysfatal("convS2M: %r");
+		fatal("convS2M: %r");
 	if(write(srvfd, rbuf, n) < 0)
-		sysfatal("reply: %r");
+		fatal("reply: %r");
 }
 
 
--- a/sys/src/cmd/rio/fsys.c
+++ b/sys/src/cmd/rio/fsys.c
@@ -195,9 +195,8 @@
 		buf = malloc(messagesize+UTFmax);	/* UTFmax for appending partial rune in xfidwrite */
 		if(buf == nil)
 			error(Enomem);
-		while((n = read9pmsg(fs->sfd, buf, messagesize)) == 0)
-			yield();
-		if(n < 0){
+		n = read9pmsg(fs->sfd, buf, messagesize);
+		if(n <= 0){
 			yield();	/* if threadexitsall'ing, will not return */
 			fprint(2, "rio: %d: read9pmsg: %d %r\n", getpid(), n);
 			errorshouldabort = 0;
--- a/sys/src/cmd/tapefs/fs.c
+++ b/sys/src/cmd/tapefs/fs.c
@@ -491,35 +491,15 @@
 io(void)
 {
 	char *err;
-	int n, nerr;
-	char buf[ERRMAX];
+	int n;
 
-	errstr(buf, sizeof buf);
-	for(nerr=0, buf[0]='\0'; nerr<100; nerr++){
-		/*
-		 * reading from a pipe or a network device
-		 * will give an error after a few eof reads
-		 * however, we cannot tell the difference
-		 * between a zero-length read and an interrupt
-		 * on the processes writing to us,
-		 * so we wait for the error
-		 */
-		n = read9pmsg(mfd[0], mdata, sizeof mdata);
-		if(n==0)
-			continue;
-		if(n < 0){
-			if(buf[0]=='\0')
-				errstr(buf, sizeof buf);
-			continue;
-		}
-		nerr = 0;
-		buf[0] = '\0';
+	while((n = read9pmsg(mfd[0], mdata, sizeof mdata)) != 0){
+		if(n < 0)
+			error("mount read");
 		if(convM2S(mdata, n, &rhdr) != n)
 			error("convert error in convM2S");
-
 		if(verbose)
 			fprint(2, "tapefs: <=%F\n", &rhdr);/**/
-
 		thdr.data = (char*)mdata + IOHDRSZ;
 		thdr.stat = mdata + IOHDRSZ;
 		if(!fcalls[rhdr.type])
@@ -542,10 +522,6 @@
 		if(write(mfd[1], mdata, n) != n)
 			error("mount write");
 	}
-	if(buf[0]=='\0' || strstr(buf, "hungup"))
-		exits("");
-	fprint(2, "%s: mount read: %s\n", argv0, buf);
-	exits(buf);
 }
 
 int
--- a/sys/src/cmd/telco/telco.c
+++ b/sys/src/cmd/telco/telco.c
@@ -914,18 +914,7 @@
 	char *err;
 	int n;
 
-	for(;;){
-		/*
-		 * reading from a pipe or a network device
-		 * will give an error after a few eof reads
-		 * however, we cannot tell the difference
-		 * between a zero-length read and an interrupt
-		 * on the processes writing to us,
-		 * so we wait for the error
-		 */
-		n = read9pmsg(mfd[0], mdata, messagesize);
-		if(n == 0)
-			continue;
+	while((n = read9pmsg(mfd[0], mdata, messagesize)) != 0){
 		if(n < 0)
 			error("mount read");
 		if(convM2S(mdata, n, &thdr) != n)
--- a/sys/src/cmd/vac/vacfs.c
+++ b/sys/src/cmd/vac/vacfs.c
@@ -704,12 +704,9 @@
 	char *err;
 	int n;
 
-	for(;;){
-		n = read9pmsg(mfd[0], mdata, sizeof mdata);
+	while((n = read9pmsg(mfd[0], mdata, sizeof mdata)) != 0){
 		if(n < 0)
-			break;
-		if(n == 0)
-			continue;
+			sysfatal("mount read: %r");
 		if(convM2Su(mdata, n, &rhdr, dotu) != n)
 			sysfatal("convM2S conversion error");
 
@@ -733,7 +730,7 @@
 			fprint(2, "vacfs:->%F\n", &thdr);
 		n = convS2Mu(&thdr, mdata, messagesize, dotu);
 		if(n <= BIT16SZ)
-			sysfatal("convS2Mu conversion error");
+			sysfatal("convS2M conversion error");
 		if(err)
 			vtfree(err);
 
--- a/sys/src/cmd/vnc/exportfs.c
+++ b/sys/src/cmd/vnc/exportfs.c
@@ -149,10 +149,9 @@
 		errdepth(ed);
 		q = smalloc(sizeof(Exq));
 
-		while((n = read9pmsg(fs->io, q->buf, Maxrpc)) == 0)
-			;
-		if(n < 0 || convM2S(q->buf, n, &q->rpc) != n)
-			goto bad;
+		n = read9pmsg(fs->io, q->buf, Maxrpc);
+		if(n <= 0 || convM2S(q->buf, n, &q->rpc) != n)
+			break;
 
 		if(exdebug)
 			print("export %d <- %F\n", getpid(), &q->rpc);
@@ -181,7 +180,6 @@
 			kproc("exportfs", exslave, nil);
 		rendwakeup(&exq.rwait);
 	}
-bad:
 	free(q);
 	if(exdebug)
 		fprint(2, "export proc shutting down: %r\n");
--- a/sys/src/games/music/jukefs/fs.c
+++ b/sys/src/games/music/jukefs/fs.c
@@ -684,7 +684,7 @@
 void
 io(void *)
 {
-	char *err, e[32];
+	char *err;
 	int n;
 	extern int p[];
 	Fid *f;
@@ -691,28 +691,18 @@
 
 	threadsetname("file server");
 	close(p[1]);
-	for(;;){
-		/*
-		 * reading from a pipe or a network device
-		 * will give an error after a few eof reads
-		 * however, we cannot tell the difference
-		 * between a zero-length read and an interrupt
-		 * on the processes writing to us,
-		 * so we wait for the error
-		 */
-		n = read9pmsg(mfd[0], mdata, messagesize);
-		if(n == 0)
-			continue;
+	while((n = read9pmsg(mfd[0], mdata, messagesize)) != 0){
 		if(n < 0){
+			char e[32];
 			rerrstr(e, sizeof e);
 			if (strcmp(e, "interrupted") == 0){
 				if (debug & DbgFs) fprint(2, "read9pmsg interrupted\n");
 				continue;
 			}
-			return;
+			sysfatal("mount read: %s", e);
 		}
-		if(convM2S(mdata, n, &thdr) == 0)
-			continue;
+		if(convM2S(mdata, n, &thdr) != n)
+			sysfatal("convM2S format error: %r");
 
 		if(debug & DbgFs)
 			fprint(2, "io:<-%F\n", &thdr);
--- a/sys/src/games/music/playlistfs/fs.c
+++ b/sys/src/games/music/playlistfs/fs.c
@@ -725,7 +725,6 @@
 void
 srvio(void *arg)
 {
-	char e[32];
 	int n;
 	Req *r;
 	Channel *dispatchc;
@@ -734,28 +733,18 @@
 	dispatchc = arg;
 
 	r = reqalloc();
-	for(;;){
-		/*
-		 * reading from a pipe or a network device
-		 * will give an error after a few eof reads
-		 * however, we cannot tell the difference
-		 * between a zero-length read and an interrupt
-		 * on the processes writing to us,
-		 * so we wait for the error
-		 */
-		n = read9pmsg(srvfd[0], r->indata, messagesize);
-		if(n == 0)
-			continue;
+	while((n = read9pmsg(srvfd[0], r->indata, messagesize)) != 0){
 		if(n < 0){
+			char e[32];
 			rerrstr(e, sizeof e);
 			if (strcmp(e, "interrupted") == 0){
 				if (debug & DbgFs) fprint(2, "read9pmsg interrupted\n");
 				continue;
 			}
-			sysfatal("srvio: %s", e);
+			sysfatal("srvio: read: %s", e);
 		}
-		if(convM2S(r->indata, n, &r->ifcall) == 0)
-			continue;
+		if(convM2S(r->indata, n, &r->ifcall) != n)
+			sysfatal("srvio: convM2S: %r");
 
 		if(debug & DbgFs)
 			fprint(2, "io:<-%F\n", &r->ifcall);
@@ -762,6 +751,7 @@
 		sendp(dispatchc, r);
 		r = reqalloc();
 	}
+	threadexitsall(nil);
 }
 
 char *
--- a/sys/src/lib9p/srv.c
+++ b/sys/src/lib9p/srv.c
@@ -59,9 +59,8 @@
 	Req *r;
 
 	qlock(&s->rlock);
-	while((n = read9pmsg(s->infd, s->rbuf, s->msize)) == 0)
-		;
-	if(n < 0){
+	n = read9pmsg(s->infd, s->rbuf, s->msize);
+	if(n <= 0){
 		qunlock(&s->rlock);
 		return nil;
 	}