Blob
1 /* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */2 /* See COPYRIGHT */4 #include <u.h>5 #include <libc.h>6 #include <fcall.h>7 #include <9pclient.h>8 #include <thread.h>9 #include "fsimpl.h"11 static int _fssend(Mux*, void*);12 static void *_fsrecv(Mux*);13 static int _fsgettag(Mux*, void*);14 static int _fssettag(Mux*, void*, uint);16 enum17 {18 CFidchunk = 3219 };21 CFsys*22 fsinit(int fd)23 {24 CFsys *fs;26 fmtinstall('F', fcallfmt);27 fmtinstall('D', dirfmt);28 fmtinstall('M', dirmodefmt);30 fs = mallocz(sizeof(CFsys), 1);31 if(fs == nil)32 return nil;33 fs->fd = fd;34 fs->ref = 1;35 fs->mux.aux = fs;36 fs->mux.mintag = 0;37 fs->mux.maxtag = 256;38 fs->mux.send = _fssend;39 fs->mux.recv = _fsrecv;40 fs->mux.gettag = _fsgettag;41 fs->mux.settag = _fssettag;42 fs->iorecv = ioproc();43 fs->iosend = ioproc();44 muxinit(&fs->mux);45 return fs;46 }48 CFid*49 fsroot(CFsys *fs)50 {51 /* N.B. no incref */52 return fs->root;53 }55 CFsys*56 fsmount(int fd, char *aname)57 {58 int n;59 CFsys *fs;60 CFid *fid;62 fs = fsinit(fd);63 if(fs == nil)64 return nil;65 strcpy(fs->version, "9P2000");66 if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){67 Error:68 fs->fd = -1;69 fsunmount(fs);70 return nil;71 }72 fs->msize = n;74 if((fid = fsattach(fs, nil, getuser(), aname)) == nil)75 goto Error;76 fssetroot(fs, fid);77 return fs;78 }80 void81 fsunmount(CFsys *fs)82 {83 fsclose(fs->root);84 fs->root = nil;85 _fsdecref(fs);86 }88 void89 _fsdecref(CFsys *fs)90 {91 CFid *f, **l, *next;93 qlock(&fs->lk);94 --fs->ref;95 //fprint(2, "fsdecref %p to %d\n", fs, fs->ref);96 if(fs->ref == 0){97 if(fs->fd >= 0)98 close(fs->fd);99 /* trim the list down to just the first in each chunk */100 for(l=&fs->freefid; *l; ){101 if((*l)->fid%CFidchunk == 0)102 l = &(*l)->next;103 else104 *l = (*l)->next;105 }106 /* now free the list */107 for(f=fs->freefid; f; f=next){108 next = f->next;109 free(f);110 }111 closeioproc(fs->iorecv);112 closeioproc(fs->iosend);113 free(fs);114 return;115 }116 qunlock(&fs->lk);117 }119 int120 fsversion(CFsys *fs, int msize, char *version, int nversion)121 {122 void *freep;123 int r, oldmintag, oldmaxtag;124 Fcall tx, rx;126 tx.tag = 0;127 tx.type = Tversion;128 tx.version = version;129 tx.msize = msize;131 /*132 * bit of a clumsy hack -- force libmux to use NOTAG as tag.133 * version can only be sent when there are no other messages134 * outstanding on the wire, so this is more reasonable than it looks.135 */136 oldmintag = fs->mux.mintag;137 oldmaxtag = fs->mux.maxtag;138 fs->mux.mintag = NOTAG;139 fs->mux.maxtag = NOTAG+1;140 r = _fsrpc(fs, &tx, &rx, &freep);141 fs->mux.mintag = oldmintag;142 fs->mux.maxtag = oldmaxtag;143 if(r < 0)144 return -1;146 strecpy(version, version+nversion, rx.version);147 free(freep);148 fs->msize = rx.msize;149 return rx.msize;150 }152 CFid*153 fsattach(CFsys *fs, CFid *afid, char *user, char *aname)154 {155 Fcall tx, rx;156 CFid *fid;158 if(aname == nil)159 aname = "";161 if((fid = _fsgetfid(fs)) == nil)162 return nil;164 tx.tag = 0;165 tx.type = Tattach;166 tx.afid = afid ? afid->fid : NOFID;167 tx.fid = fid->fid;168 tx.uname = user;169 tx.aname = aname;171 if(_fsrpc(fs, &tx, &rx, 0) < 0){172 _fsputfid(fid);173 return nil;174 }175 fid->qid = rx.qid;176 return fid;177 }179 void180 fssetroot(CFsys *fs, CFid *fid)181 {182 if(fs->root)183 _fsputfid(fs->root);184 fs->root = fid;185 }187 int188 _fsrpc(CFsys *fs, Fcall *tx, Fcall *rx, void **freep)189 {190 int n, nn;191 void *tpkt, *rpkt;193 n = sizeS2M(tx);194 tpkt = malloc(n);195 if(freep)196 *freep = nil;197 if(tpkt == nil)198 return -1;199 //fprint(2, "<- %F\n", tx);200 nn = convS2M(tx, tpkt, n);201 if(nn != n){202 free(tpkt);203 werrstr("libfs: sizeS2M convS2M mismatch");204 fprint(2, "%r\n");205 return -1;206 }207 rpkt = muxrpc(&fs->mux, tpkt);208 free(tpkt);209 if(rpkt == nil)210 return -1;211 n = GBIT32((uchar*)rpkt);212 nn = convM2S(rpkt, n, rx);213 if(nn != n){214 free(rpkt);215 werrstr("libfs: convM2S packet size mismatch %d %d", n, nn);216 fprint(2, "%r\n");217 return -1;218 }219 //fprint(2, "-> %F\n", rx);220 if(rx->type == Rerror){221 werrstr("%s", rx->ename);222 free(rpkt);223 return -1;224 }225 if(rx->type != tx->type+1){226 werrstr("packet type mismatch -- tx %d rx %d",227 tx->type, rx->type);228 free(rpkt);229 return -1;230 }231 if(freep)232 *freep = rpkt;233 else234 free(rpkt);235 return 0;236 }238 CFid*239 _fsgetfid(CFsys *fs)240 {241 int i;242 CFid *f;244 qlock(&fs->lk);245 if(fs->freefid == nil){246 f = mallocz(sizeof(CFid)*CFidchunk, 1);247 if(f == nil){248 qunlock(&fs->lk);249 return nil;250 }251 for(i=0; i<CFidchunk; i++){252 f[i].fid = fs->nextfid++;253 f[i].next = &f[i+1];254 f[i].fs = fs;255 }256 f[i-1].next = nil;257 fs->freefid = f;258 }259 f = fs->freefid;260 fs->freefid = f->next;261 fs->ref++;262 qunlock(&fs->lk);263 f->offset = 0;264 f->mode = -1;265 f->qid.path = 0;266 f->qid.vers = 0;267 f->qid.type = 0;268 return f;269 }271 void272 _fsputfid(CFid *f)273 {274 CFsys *fs;276 fs = f->fs;277 qlock(&fs->lk);278 f->next = fs->freefid;279 fs->freefid = f;280 qunlock(&fs->lk);281 _fsdecref(fs);282 }284 static int285 _fsgettag(Mux *mux, void *pkt)286 {287 return GBIT16((uchar*)pkt+5);288 }290 static int291 _fssettag(Mux *mux, void *pkt, uint tag)292 {293 PBIT16((uchar*)pkt+5, tag);294 return 0;295 }297 static int298 _fssend(Mux *mux, void *pkt)299 {300 CFsys *fs;302 fs = mux->aux;303 return iowrite(fs->iosend, fs->fd, pkt, GBIT32((uchar*)pkt));304 }306 static void*307 _fsrecv(Mux *mux)308 {309 uchar *pkt;310 uchar buf[4];311 int n, nfd;312 CFsys *fs;314 fs = mux->aux;315 n = ioreadn(fs->iorecv, fs->fd, buf, 4);316 if(n != 4)317 return nil;318 n = GBIT32(buf);319 pkt = malloc(n+4);320 if(pkt == nil){321 fprint(2, "libfs out of memory reading 9p packet; here comes trouble\n");322 return nil;323 }324 PBIT32(pkt, n);325 if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){326 free(pkt);327 return nil;328 }329 if(pkt[4] == Ropenfd){330 if((nfd=iorecvfd(fs->iorecv, fs->fd)) < 0){331 fprint(2, "recv fd error: %r\n");332 free(pkt);333 return nil;334 }335 PBIT32(pkt+n-4, nfd);336 }337 return pkt;338 }