shithub: riscv

Download patch

ref: fa5bd7121846bae31ede5d6851a5091e9c16683a
parent: 5c1feb0ef0b795e5de71e956f9ccddcd5c4b7f21
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Nov 5 14:26:12 EDT 2016

devmnt: avoid memory copies of I/O rpc buffer by using bwrite()

given that devmnt will almost always write into a pipe
or a network connection, which supports te bwrite routine,
we can avoid the memory copy that would have been done by
devbwrite(). this also means the i/o buffer for writes
will get freed sooner without having to wait for the 9p
rpc to get a response, saving memory.

theres one case where we have to keep the rpc arround and
that is when we write to a cached file, as we want to update
the cache with the data that was written, but the user buffer
cannot be trusted to stay the same during the rpc.

--- a/sys/src/9/port/devmnt.c
+++ b/sys/src/9/port/devmnt.c
@@ -26,8 +26,7 @@
 	Fcall 	reply;		/* Incoming reply */
 	Mnt*	m;		/* Mount device during rpc */
 	Rendez*	z;		/* Place to hang out */
-	uchar*	rpc;		/* I/O Data buffer */
-	uint	rpclen;		/* len of buffer */
+	Block*	w;		/* copy of write rpc for cache */
 	Block*	b;		/* reply blocks */
 	Mntrpc*	flushed;	/* message this one flushes */
 	char	done;		/* Rpc completed */
@@ -68,6 +67,8 @@
 static void	mountrpc(Mnt*, Mntrpc*);
 static int	rpcattn(void*);
 
+#define cachedchan(c) (((c)->flag & CCACHE) != 0 && (c)->mcp != nil)
+
 char	Esbadstat[] = "invalid directory entry received from server";
 char	Enoversion[] = "version not established for mount channel";
 
@@ -659,7 +660,7 @@
 	Chan *c;
 
 	c = r->c;
-	if((c->flag & CCACHE) == 0 || c->mcp == nil)
+	if(!cachedchan(c))
 		return;
 	off = r->request.offset;
 	switch(r->reply.type){
@@ -676,9 +677,13 @@
 		}
 		break;
 	case Rwrite:
-		if(convM2S(r->rpc, r->rpclen, &r->request) == 0)
+		b = r->w;
+		if(convM2S(b->rp, BLEN(b), &r->request) == 0)
 			panic("convM2S");
-		cwrite(c, (uchar*)r->request.data, r->request.count, off);
+		m = r->reply.count;
+		if(m > r->request.count)
+			m = r->request.count;
+		cwrite(c, (uchar*)r->request.data, m, off);
 		break;
 	}
 }
@@ -700,7 +705,7 @@
 		if(nreq > c->iounit)
 			nreq = c->iounit;
 
-		if(type == Tread && (c->flag&CCACHE) != 0) {
+		if(type == Tread && cachedchan(c)) {
 			nr = cread(c, (uchar*)uba, nreq, off);
 			if(nr > 0) {
 				nreq = nr;
@@ -992,6 +997,7 @@
 static void
 mountio(Mnt *m, Mntrpc *r)
 {
+	Block *b;
 	int n;
 
 	while(waserror()) {
@@ -1021,23 +1027,22 @@
 
 	/* Transmit a file system rpc */
 	n = sizeS2M(&r->request);
-	if(n > r->rpclen) {
-		free(r->rpc);
-		r->rpc = mallocz(((uint)n+127) & ~127, 0);
-		if(r->rpc == nil) {
-			r->rpclen = 0;
-			exhausted("mount rpc buffer");
-		}
-		r->rpclen = msize(r->rpc);
+	b = allocb(n);
+	if(waserror()){
+		freeb(b);
+		nexterror();
 	}
-	n = convS2M(&r->request, r->rpc, r->rpclen);
+	n = convS2M(&r->request, b->wp, n);
 	if(n <= 0 || n > m->msize) {
 		print("mountio: proc %s %lud: convS2M returned %d for tag %d fid %d T%d\n",
 			up->text, up->pid, n, r->request.tag, r->request.fid, r->request.type);
 		error(Emountrpc);
 	}
-	if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
-		error(Emountrpc);
+	b->wp += n;
+	if(r->request.type == Twrite && cachedchan(r->c))
+		r->w = copyblock(b, n);
+	poperror();
+	devtab[m->c->type]->bwrite(m->c, b, 0);
 
 	/* Gate readers onto the mount point one at a time */
 	for(;;) {
@@ -1288,8 +1293,6 @@
 		new = malloc(sizeof(Mntrpc));
 		if(new == nil)
 			exhausted("mount rpc header");
-		new->rpc = nil;
-		new->rpclen = 0;
 		lock(&mntalloc);
 		new->request.tag = alloctag();
 	} else {
@@ -1308,6 +1311,7 @@
 	new->done = 0;
 	new->flushed = nil;
 	new->b = nil;
+	new->w = nil;
 	return new;
 }
 
@@ -1314,6 +1318,7 @@
 static void
 mntfree(Mntrpc *r)
 {
+	freeb(r->w);
 	freeblist(r->b);
 	lock(&mntalloc);
 	mntalloc.nrpcused--;
@@ -1326,7 +1331,6 @@
 	}
 	freetag(r->request.tag);
 	unlock(&mntalloc);
-	free(r->rpc);
 	free(r);
 }