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