shithub: riscv

Download patch

ref: 825ab5d286bfbf959fef678afcdf0c887a5eb91c
parent: 31ff4f925d10428361076b3849dbe609cb7580c0
author: aiju <devnull@localhost>
date: Fri Apr 28 14:21:03 EDT 2017

sshfs: don't cache directory contents

--- a/sys/src/cmd/sshfs.c
+++ b/sys/src/cmd/sshfs.c
@@ -93,8 +93,9 @@
 	uchar *hand;
 	int handn;
 	Qid qid;
+	int dirreads;
 	Dir *dirent;
-	int ndirent;
+	int ndirent, dirpos;
 	uchar direof;
 };
 
@@ -366,14 +367,11 @@
 }
 
 void
-putsfid(SFid *s)
+freedir(SFid *s)
 {
 	int i;
 	Dir *d;
 
-	if(s == nil) return;
-	free(s->fn);
-	free(s->hand);
 	for(i = 0; i < s->ndirent; i++){
 		d = &s->dirent[i];
 		free(d->name);
@@ -382,6 +380,19 @@
 		free(d->muid);
 	}
 	free(s->dirent);
+	s->dirent = nil;
+	s->ndirent = 0;
+	s->dirpos = 0;
+}
+
+
+void
+putsfid(SFid *s)
+{
+	if(s == nil) return;
+	free(s->fn);
+	free(s->hand);
+	freedir(s);
 	free(s);
 }
 
@@ -595,8 +606,9 @@
 
 	if(unpack(rxpkt, rxlen, "_____u", &c) < 0) return -1;
 	wlock(sf);
-	sf->dirent = erealloc9p(sf->dirent, (sf->ndirent + c) * sizeof(Dir));
-	d = sf->dirent + sf->ndirent;
+	freedir(sf);
+	sf->dirent = emalloc9p(c * sizeof(Dir));
+	d = sf->dirent;
 	p = rxpkt + 9;
 	ep = rxpkt + rxlen;
 	for(i = 0; i < c; i++){
@@ -624,51 +636,71 @@
 	return -1;
 }
 
+
 void
 readprocess(Req *r)
 {
-	int start;
+	int i;
 	uchar *p, *ep;
 	uint rv;
 	SFid *sf;
-
-	if((r->fid->qid.type & QTDIR) == 0){
-		submitreq(r);
+	
+	sf = r->fid->aux;
+	wlock(sf);
+	if(sf->direof){
+		wunlock(sf);
+		respond(r, nil);
 		return;
 	}
-
-	if(r->ifcall.offset == 0)
-		start = 0;
-	else
-		start = r->fid->dirindex;
-
-	p = (uchar*)r->ofcall.data;
-	ep = p+r->ifcall.count;
-	sf = r->fid->aux;
-
-	rlock(sf);
+	i = sf->dirpos;
+	p = (uchar*)r->ofcall.data + r->ofcall.count;
+	ep = (uchar*)r->ofcall.data + r->ifcall.count;
+	rv = ep - p;
 	while(p < ep){
-		if(start >= sf->ndirent)
-			if(sf->direof)
-				break;
-			else{
-				runlock(sf);
-				submitreq(r);
-				return;
-			}
-		rv = convD2M(&sf->dirent[start], p, ep-p);
+		if(i >= sf->ndirent)
+			break;
+		rv = convD2M(&sf->dirent[i], p, ep-p);
 		if(rv <= BIT16SZ)
 			break;
 		p += rv;
-		start++;
+		i++;
 	}
-	runlock(sf);
-	r->fid->dirindex = start;
+	sf->dirpos = i;
+	if(i >= sf->ndirent)
+		freedir(sf);
+	wunlock(sf);
 	r->ofcall.count = p - (uchar*)r->ofcall.data;
-	respond(r, nil);
+	if(rv <= BIT16SZ)
+		respond(r, nil);
+	else
+		submitreq(r);
 }
 
 void
+sshfsread(Req *r)
+{
+	SFid *sf;
+
+	if((r->fid->qid.type & QTDIR) == 0){
+		submitreq(r);
+		return;
+	}
+	sf = r->fid->aux;	
+	if(r->ifcall.offset == 0){
+		wlock(sf);
+		freedir(sf);
+		if(sf->dirreads > 0){
+			r->aux = (void*)-1;
+			submitreq(r);
+			wunlock(sf);
+			return;
+		}
+		wunlock(sf);
+	}
+	readprocess(r);
+}
+
+void
 sshfsattach(Req *r)
 {
 	SFid *sf;
@@ -790,13 +822,28 @@
 			free(s);
 			break;
 		case Tread:
-			rlock(sf);
-			if((r->req->fid->qid.type & QTDIR) != 0)
-				sendpkt("bus", SSH_FXP_READDIR, r->reqid, sf->hand, sf->handn);
-			else
+			if((r->req->fid->qid.type & QTDIR) != 0){
+				wlock(sf);
+				if(r->req->aux == (void*)-1){
+					sendpkt("bus", SSH_FXP_CLOSE, r->reqid, sf->hand, sf->handn);
+					free(sf->hand);
+					sf->hand = nil;
+					sf->handn = 0;
+					sf->direof = 0;
+					sf->dirreads = 0;
+				}else if(r->req->aux == (void*)-2){
+					sendpkt("bus", SSH_FXP_OPENDIR, r->reqid, sf->fn, strlen(sf->fn));
+				}else{
+					sendpkt("bus", SSH_FXP_READDIR, r->reqid, sf->hand, sf->handn);
+					sf->dirreads++;
+				}
+				wunlock(sf);
+			}else{
+				rlock(sf);
 				sendpkt("busvuu", SSH_FXP_READ, r->reqid, sf->hand, sf->handn,
 					r->req->ifcall.offset, r->req->ifcall.count);
-			runlock(sf);
+				runlock(sf);
+			}
 			break;
 		case Twrite:
 			x = r->req->ifcall.count - r->req->ofcall.count;
@@ -870,6 +917,7 @@
 	u32int code;
 	char *msg, *lang, *hand;
 	int msgn, langn, handn;
+	int okresp;
 	uchar *p;
 	char *e;
 	
@@ -912,6 +960,7 @@
 			sysfatal("recvproc: r->req == nil");
 
 		sf = r->req->fid != nil ? r->req->fid->aux : nil;
+		okresp = rxlen >= 9 && t == SSH_FXP_STATUS && GET4(rxpkt+5) == SSH_FX_OK;
 		switch(r->req->ifcall.type){
 		case Tattach:
 			if(t != SSH_FXP_ATTRS) goto common;
@@ -946,14 +995,12 @@
 			walkprocess(r->req, GET4(p) & 0040000, nil);
 			break;
 		case Tcreate:
-			if(t == SSH_FXP_STATUS && r->req->aux == (void*)-1){
-				if(unpack(rxpkt, rxlen, "_____u", &code) < 0) goto garbage;
-				if(code != SSH_FX_OK) goto common;
+			if(okresp && r->req->aux == (void*)-1){
 				submitreq(r->req);
 				break;
 			}
 			/* wet floor */
-		case Topen:
+		case Topen: opendir:
 			if(t != SSH_FXP_HANDLE) goto common;
 			if(unpack(rxpkt, rxlen, "_____s", &hand, &handn) < 0) goto garbage;
 			wlock(sf);
@@ -961,13 +1008,26 @@
 			sf->hand = emalloc9p(sf->handn);
 			memcpy(sf->hand, hand, sf->handn);
 			wunlock(sf);
-			respond(r->req, nil);
+			if(r->req->ifcall.type == Tread){
+				r->req->aux = nil;
+				readprocess(r->req);
+			}else
+				respond(r->req, nil);
 			break;
 		case Tread:
 			if((r->req->fid->qid.type & QTDIR) != 0){
-				if(t != SSH_FXP_NAME) goto common;
-				if(parsedir(sf) < 0) goto garbage;
-				readprocess(r->req);
+				if(r->req->aux == (void*)-1){
+					if(t != SSH_FXP_STATUS) goto common;
+					/* reopen even if close failed */
+					r->req->aux = (void*)-2;
+					submitreq(r->req);
+				}else if(r->req->aux == (void*)-2)
+					goto opendir;
+				else{
+					if(t != SSH_FXP_NAME) goto common;
+					if(parsedir(sf) < 0) goto garbage;
+					readprocess(r->req);
+				}
 				break;
 			}
 			if(t != SSH_FXP_DATA) goto common;
@@ -979,8 +1039,7 @@
 			break;
 		case Twrite:
 			if(t != SSH_FXP_STATUS) goto common;
-			if(unpack(rxpkt, rxlen, "_____u", &code) < 0) goto garbage;
-			if(code == SSH_FX_OK){
+			if(okresp){
 				r->req->ofcall.count += r->req->ofcall.offset;
 				if(r->req->ofcall.count == r->req->ifcall.count)
 					respond(r->req, nil);
@@ -997,9 +1056,7 @@
 			respond(r->req, nil);
 			break;
 		case Twstat:
-			if(t != SSH_FXP_STATUS || r->req->d.name == nil || *r->req->d.name == 0) goto common;
-			if(unpack(rxpkt, rxlen, "_____u", &code) < 0) goto garbage;
-			if(code != SSH_FX_OK) goto common;
+			if(!okresp) goto common;
 			if(r->req->aux == nil){
 				r->req->aux = (void *) -1;
 				submitreq(r->req);
@@ -1135,7 +1192,7 @@
 	.walk sshfswalk,
 	.open submitreq,
 	.create submitreq,
-	.read readprocess,
+	.read sshfsread,
 	.write submitreq,
 	.stat submitreq,
 	.wstat submitreq,