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);
}