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 <fs.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 Fidchunk = 3219 };21 Fsys*22 fsinit(int fd)23 {24 Fsys *fs;26 fmtinstall('F', fcallfmt);27 fmtinstall('D', dirfmt);28 fmtinstall('M', dirmodefmt);30 fs = mallocz(sizeof(Fsys), 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 Fid*49 fsroot(Fsys *fs)50 {51 /* N.B. no incref */52 return fs->root;53 }55 Fsys*56 fsmount(int fd, char *aname)57 {58 int n;59 char *user;60 Fsys *fs;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 user = getuser();75 if((fs->root = fsattach(fs, nil, getuser(), aname)) == nil)76 goto Error;77 return fs;78 }80 void81 fsunmount(Fsys *fs)82 {83 fsclose(fs->root);84 fs->root = nil;85 _fsdecref(fs);86 }88 void89 _fsdecref(Fsys *fs)90 {91 Fid *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 close(fs->fd);98 /* trim the list down to just the first in each chunk */99 for(l=&fs->freefid; *l; ){100 if((*l)->fid%Fidchunk == 0)101 l = &(*l)->next;102 else103 *l = (*l)->next;104 }105 /* now free the list */106 for(f=fs->freefid; f; f=next){107 next = f->next;108 free(f);109 }110 closeioproc(fs->iorecv);111 closeioproc(fs->iosend);112 free(fs);113 return;114 }115 qunlock(&fs->lk);116 }118 int119 fsversion(Fsys *fs, int msize, char *version, int nversion)120 {121 void *freep;122 Fcall tx, rx;124 tx.tag = 0;125 tx.type = Tversion;126 tx.version = version;127 tx.msize = msize;129 if(fsrpc(fs, &tx, &rx, &freep) < 0)130 return -1;131 strecpy(version, version+nversion, rx.version);132 free(freep);133 return rx.msize;134 }136 Fid*137 fsattach(Fsys *fs, Fid *afid, char *user, char *aname)138 {139 Fcall tx, rx;140 Fid *fid;142 if(aname == nil)143 aname = "";145 if((fid = _fsgetfid(fs)) == nil)146 return nil;148 tx.tag = 0;149 tx.type = Tattach;150 tx.afid = afid ? afid->fid : NOFID;151 tx.fid = fid->fid;152 tx.uname = user;153 tx.aname = aname;155 if(fsrpc(fs, &tx, &rx, 0) < 0){156 _fsputfid(fid);157 return nil;158 }159 fid->qid = rx.qid;160 return fid;161 }163 int164 fsrpc(Fsys *fs, Fcall *tx, Fcall *rx, void **freep)165 {166 int n, nn;167 void *tpkt, *rpkt;169 n = sizeS2M(tx);170 tpkt = malloc(n);171 if(freep)172 *freep = nil;173 if(tpkt == nil)174 return -1;175 //fprint(2, "<- %F\n", tx);176 nn = convS2M(tx, tpkt, n);177 if(nn != n){178 free(tpkt);179 werrstr("libfs: sizeS2M convS2M mismatch");180 fprint(2, "%r\n");181 return -1;182 }183 rpkt = muxrpc(&fs->mux, tpkt);184 free(tpkt);185 if(rpkt == nil)186 return -1;187 n = GBIT32((uchar*)rpkt);188 nn = convM2S(rpkt, n, rx);189 if(nn != n){190 free(rpkt);191 werrstr("libfs: convM2S packet size mismatch %d %d", n, nn);192 fprint(2, "%r\n");193 return -1;194 }195 //fprint(2, "-> %F\n", rx);196 if(rx->type == Rerror){197 werrstr("%s", rx->ename);198 free(rpkt);199 return -1;200 }201 if(rx->type != tx->type+1){202 werrstr("packet type mismatch -- tx %d rx %d",203 tx->type, rx->type);204 free(rpkt);205 return -1;206 }207 if(freep)208 *freep = rpkt;209 else210 free(rpkt);211 return 0;212 }214 Fid*215 _fsgetfid(Fsys *fs)216 {217 int i;218 Fid *f;220 qlock(&fs->lk);221 if(fs->freefid == nil){222 f = mallocz(sizeof(Fid)*Fidchunk, 1);223 if(f == nil){224 qunlock(&fs->lk);225 return nil;226 }227 for(i=0; i<Fidchunk; i++){228 f[i].fid = fs->nextfid++;229 f[i].next = &f[i+1];230 f[i].fs = fs;231 }232 f[i-1].next = nil;233 fs->freefid = f;234 }235 f = fs->freefid;236 fs->freefid = f->next;237 fs->ref++;238 qunlock(&fs->lk);239 return f;240 }242 void243 _fsputfid(Fid *f)244 {245 Fsys *fs;247 fs = f->fs;248 qlock(&fs->lk);249 f->next = fs->freefid;250 fs->freefid = f;251 qunlock(&fs->lk);252 _fsdecref(fs);253 }255 static int256 _fsgettag(Mux *mux, void *pkt)257 {258 return GBIT16((uchar*)pkt+5);259 }261 static int262 _fssettag(Mux *mux, void *pkt, uint tag)263 {264 PBIT16((uchar*)pkt+5, tag);265 return 0;266 }268 static int269 _fssend(Mux *mux, void *pkt)270 {271 Fsys *fs;273 fs = mux->aux;274 return iowrite(fs->iosend, fs->fd, pkt, GBIT32((uchar*)pkt));275 }277 static void*278 _fsrecv(Mux *mux)279 {280 uchar *pkt;281 uchar buf[4];282 int n, nfd;283 Fsys *fs;285 fs = mux->aux;286 n = ioreadn(fs->iorecv, fs->fd, buf, 4);287 if(n != 4)288 return nil;289 n = GBIT32(buf);290 pkt = malloc(n+4);291 if(pkt == nil){292 fprint(2, "libfs out of memory reading 9p packet; here comes trouble\n");293 return nil;294 }295 PBIT32(pkt, n);296 if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){297 free(pkt);298 return nil;299 }300 if(pkt[4] == Ropenfd){301 if((nfd=iorecvfd(fs->iorecv, fs->fd)) < 0){302 fprint(2, "recv fd error: %r\n");303 free(pkt);304 return nil;305 }306 PBIT32(pkt+n-4, nfd);307 }308 return pkt;309 }