sshfs: don't cache directory contents

This commit is contained in:
aiju 2017-04-28 18:21:03 +00:00
parent 31ff4f925d
commit 825ab5d286

View file

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