1 /* 2 * exportfs - Export a plan 9 name space across a network 3 */ 4 #include <u.h> 5 #include <libc.h> 6 #include <fcall.h> 7 #include <libsec.h> 8 #include "drawterm.h" 9 #define Extern 10 #include "exportfs.h" 11 12 /* #define QIDPATH ((1LL<<48)-1) */ 13 #define QIDPATH ((((vlong)1)<<48)-1) 14 vlong newqid = 0; 15 16 void (*fcalls[256])(Fsrpc*); 17 18 /* accounting and debugging counters */ 19 int filecnt; 20 int freecnt; 21 int qidcnt; 22 int qfreecnt; 23 int ncollision; 24 int netfd; 25 26 int 27 exportfs(int fd, int msgsz) 28 { 29 char buf[ERRMAX], ebuf[ERRMAX]; 30 Fsrpc *r; 31 int i, n; 32 33 fcalls[Tversion] = Xversion; 34 fcalls[Tauth] = Xauth; 35 fcalls[Tflush] = Xflush; 36 fcalls[Tattach] = Xattach; 37 fcalls[Twalk] = Xwalk; 38 fcalls[Topen] = slave; 39 fcalls[Tcreate] = Xcreate; 40 fcalls[Tclunk] = Xclunk; 41 fcalls[Tread] = slave; 42 fcalls[Twrite] = slave; 43 fcalls[Tremove] = Xremove; 44 fcalls[Tstat] = Xstat; 45 fcalls[Twstat] = Xwstat; 46 47 srvfd = -1; 48 netfd = fd; 49 //dbg = 1; 50 51 strcpy(buf, "this is buf"); 52 strcpy(ebuf, "this is ebuf"); 53 DEBUG(DFD, "exportfs: started\n"); 54 55 // rfork(RFNOTEG); 56 57 messagesize = msgsz; 58 if(messagesize == 0){ 59 messagesize = iounit(netfd); 60 if(messagesize == 0) 61 messagesize = 8192+IOHDRSZ; 62 } 63 64 Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs); 65 // for(i=0; i<Nr_workbufs; i++) 66 // Workq[i].buf = emallocz(messagesize); 67 fhash = emallocz(sizeof(Fid*)*FHASHSIZE); 68 69 fmtinstall('F', fcallfmt); 70 71 initroot(); 72 73 DEBUG(DFD, "exportfs: %s\n", buf); 74 75 /* 76 * Start serving file requests from the network 77 */ 78 for(;;) { 79 r = getsbuf(); 80 if(r == 0) 81 fatal("Out of service buffers"); 82 83 DEBUG(DFD, "read9p..."); 84 n = read9pmsg(netfd, r->buf, messagesize); 85 if(n <= 0) 86 fatal("eof: n=%d %r", n); 87 88 if(convM2S(r->buf, n, &r->work) == 0){ 89 iprint("convM2S %d byte message\n", n); 90 for(i=0; i<n; i++){ 91 iprint(" %.2ux", r->buf[i]); 92 if(i%16 == 15) 93 iprint("\n"); 94 } 95 if(i%16) 96 iprint("\n"); 97 fatal("convM2S format error"); 98 } 99 100 if(0) iprint("<- %F\n", &r->work); 101 DEBUG(DFD, "%F\n", &r->work); 102 (fcalls[r->work.type])(r); 103 } 104 } 105 106 void 107 reply(Fcall *r, Fcall *t, char *err) 108 { 109 uchar *data; 110 int m, n; 111 112 t->tag = r->tag; 113 t->fid = r->fid; 114 if(err) { 115 t->type = Rerror; 116 t->ename = err; 117 } 118 else 119 t->type = r->type + 1; 120 121 if(0) iprint("-> %F\n", t); 122 DEBUG(DFD, "\t%F\n", t); 123 124 data = malloc(messagesize); /* not mallocz; no need to clear */ 125 if(data == nil) 126 fatal(Enomem); 127 n = convS2M(t, data, messagesize); 128 if((m=write(netfd, data, n))!=n){ 129 iprint("wrote %d got %d (%r)\n", n, m); 130 fatal("write"); 131 } 132 free(data); 133 } 134 135 Fid * 136 getfid(int nr) 137 { 138 Fid *f; 139 140 for(f = fidhash(nr); f; f = f->next) 141 if(f->nr == nr) 142 return f; 143 144 return 0; 145 } 146 147 int 148 freefid(int nr) 149 { 150 Fid *f, **l; 151 char buf[128]; 152 153 l = &fidhash(nr); 154 for(f = *l; f; f = f->next) { 155 if(f->nr == nr) { 156 if(f->mid) { 157 sprint(buf, "/mnt/exportfs/%d", f->mid); 158 unmount(0, buf); 159 psmap[f->mid] = 0; 160 } 161 if(f->f) { 162 freefile(f->f); 163 f->f = nil; 164 } 165 *l = f->next; 166 f->next = fidfree; 167 fidfree = f; 168 return 1; 169 } 170 l = &f->next; 171 } 172 173 return 0; 174 } 175 176 Fid * 177 newfid(int nr) 178 { 179 Fid *new, **l; 180 int i; 181 182 l = &fidhash(nr); 183 for(new = *l; new; new = new->next) 184 if(new->nr == nr) 185 return 0; 186 187 if(fidfree == 0) { 188 fidfree = emallocz(sizeof(Fid) * Fidchunk); 189 190 for(i = 0; i < Fidchunk-1; i++) 191 fidfree[i].next = &fidfree[i+1]; 192 193 fidfree[Fidchunk-1].next = 0; 194 } 195 196 new = fidfree; 197 fidfree = new->next; 198 199 memset(new, 0, sizeof(Fid)); 200 new->next = *l; 201 *l = new; 202 new->nr = nr; 203 new->fid = -1; 204 new->mid = 0; 205 206 return new; 207 } 208 209 Fsrpc * 210 getsbuf(void) 211 { 212 static int ap; 213 int look, rounds; 214 Fsrpc *wb; 215 int small_instead_of_fast = 1; 216 217 if(small_instead_of_fast) 218 ap = 0; /* so we always start looking at the beginning and reuse buffers */ 219 220 for(rounds = 0; rounds < 10; rounds++) { 221 for(look = 0; look < Nr_workbufs; look++) { 222 if(++ap == Nr_workbufs) 223 ap = 0; 224 if(Workq[ap].busy == 0) 225 break; 226 } 227 228 if(look == Nr_workbufs){ 229 sleep(10 * rounds); 230 continue; 231 } 232 233 wb = &Workq[ap]; 234 wb->pid = 0; 235 wb->canint = 0; 236 wb->flushtag = NOTAG; 237 wb->busy = 1; 238 if(wb->buf == nil) /* allocate buffers dynamically to keep size down */ 239 wb->buf = emallocz(messagesize); 240 return wb; 241 } 242 fatal("No more work buffers"); 243 return nil; 244 } 245 246 void 247 freefile(File *f) 248 { 249 File *parent, *child; 250 251 Loop: 252 f->ref--; 253 if(f->ref > 0) 254 return; 255 freecnt++; 256 if(f->ref < 0) abort(); 257 DEBUG(DFD, "free %s\n", f->name); 258 /* delete from parent */ 259 parent = f->parent; 260 if(parent->child == f) 261 parent->child = f->childlist; 262 else{ 263 for(child=parent->child; child->childlist!=f; child=child->childlist) 264 if(child->childlist == nil) 265 fatal("bad child list"); 266 child->childlist = f->childlist; 267 } 268 freeqid(f->qidt); 269 free(f->name); 270 f->name = nil; 271 free(f); 272 f = parent; 273 if(f != nil) 274 goto Loop; 275 } 276 277 File * 278 file(File *parent, char *name) 279 { 280 Dir *dir; 281 char *path; 282 File *f; 283 284 DEBUG(DFD, "\tfile: 0x%p %s name %s\n", parent, parent->name, name); 285 286 path = makepath(parent, name); 287 dir = dirstat(path); 288 free(path); 289 if(dir == nil) 290 return nil; 291 292 for(f = parent->child; f; f = f->childlist) 293 if(strcmp(name, f->name) == 0) 294 break; 295 296 if(f == nil){ 297 f = emallocz(sizeof(File)); 298 f->name = estrdup(name); 299 300 f->parent = parent; 301 f->childlist = parent->child; 302 parent->child = f; 303 parent->ref++; 304 f->ref = 0; 305 filecnt++; 306 } 307 f->ref++; 308 f->qid.type = dir->qid.type; 309 f->qid.vers = dir->qid.vers; 310 f->qidt = uniqueqid(dir); 311 f->qid.path = f->qidt->uniqpath; 312 313 f->inval = 0; 314 315 free(dir); 316 317 return f; 318 } 319 320 void 321 initroot(void) 322 { 323 Dir *dir; 324 325 root = emallocz(sizeof(File)); 326 root->name = estrdup("."); 327 328 dir = dirstat(root->name); 329 if(dir == nil) 330 fatal("root stat"); 331 332 root->ref = 1; 333 root->qid.vers = dir->qid.vers; 334 root->qidt = uniqueqid(dir); 335 root->qid.path = root->qidt->uniqpath; 336 root->qid.type = QTDIR; 337 free(dir); 338 339 psmpt = emallocz(sizeof(File)); 340 psmpt->name = estrdup("/"); 341 342 dir = dirstat(psmpt->name); 343 if(dir == nil) 344 return; 345 346 psmpt->ref = 1; 347 psmpt->qid.vers = dir->qid.vers; 348 psmpt->qidt = uniqueqid(dir); 349 psmpt->qid.path = psmpt->qidt->uniqpath; 350 free(dir); 351 352 psmpt = file(psmpt, "mnt"); 353 if(psmpt == 0) 354 return; 355 psmpt = file(psmpt, "exportfs"); 356 } 357 358 char* 359 makepath(File *p, char *name) 360 { 361 int i, n; 362 char *c, *s, *path, *seg[256]; 363 364 seg[0] = name; 365 n = strlen(name)+2; 366 for(i = 1; i < 256 && p; i++, p = p->parent){ 367 seg[i] = p->name; 368 n += strlen(p->name)+1; 369 } 370 path = malloc(n); 371 if(path == nil) 372 fatal("out of memory"); 373 s = path; 374 375 while(i--) { 376 for(c = seg[i]; *c; c++) 377 *s++ = *c; 378 *s++ = '/'; 379 } 380 while(s[-1] == '/') 381 s--; 382 *s = '\0'; 383 384 return path; 385 } 386 387 int 388 qidhash(vlong path) 389 { 390 int h, n; 391 392 h = 0; 393 for(n=0; n<64; n+=Nqidbits){ 394 h ^= path; 395 path >>= Nqidbits; 396 } 397 return h & (Nqidtab-1); 398 } 399 400 void 401 freeqid(Qidtab *q) 402 { 403 ulong h; 404 Qidtab *l; 405 406 q->ref--; 407 if(q->ref > 0) 408 return; 409 qfreecnt++; 410 h = qidhash(q->path); 411 if(qidtab[h] == q) 412 qidtab[h] = q->next; 413 else{ 414 for(l=qidtab[h]; l->next!=q; l=l->next) 415 if(l->next == nil) 416 fatal("bad qid list"); 417 l->next = q->next; 418 } 419 free(q); 420 } 421 422 Qidtab* 423 qidlookup(Dir *d) 424 { 425 ulong h; 426 Qidtab *q; 427 428 h = qidhash(d->qid.path); 429 for(q=qidtab[h]; q!=nil; q=q->next) 430 if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path) 431 return q; 432 return nil; 433 } 434 435 int 436 qidexists(vlong path) 437 { 438 int h; 439 Qidtab *q; 440 441 for(h=0; h<Nqidtab; h++) 442 for(q=qidtab[h]; q!=nil; q=q->next) 443 if(q->uniqpath == path) 444 return 1; 445 return 0; 446 } 447 448 Qidtab* 449 uniqueqid(Dir *d) 450 { 451 ulong h; 452 vlong path; 453 Qidtab *q; 454 455 q = qidlookup(d); 456 if(q != nil){ 457 q->ref++; 458 return q; 459 } 460 path = d->qid.path; 461 while(qidexists(path)){ 462 DEBUG(DFD, "collision on %s\n", d->name); 463 /* collision: find a new one */ 464 ncollision++; 465 path &= QIDPATH; 466 ++newqid; 467 if(newqid >= (1<<16)){ 468 DEBUG(DFD, "collision wraparound\n"); 469 newqid = 1; 470 } 471 path |= newqid<<48; 472 DEBUG(DFD, "assign qid %.16llux\n", path); 473 } 474 q = mallocz(sizeof(Qidtab), 1); 475 if(q == nil) 476 fatal("no memory for qid table"); 477 qidcnt++; 478 q->ref = 1; 479 q->type = d->type; 480 q->dev = d->dev; 481 q->path = d->qid.path; 482 q->uniqpath = path; 483 h = qidhash(d->qid.path); 484 q->next = qidtab[h]; 485 qidtab[h] = q; 486 return q; 487 } 488 489 void 490 fatal(char *s, ...) 491 { 492 char buf[ERRMAX]; 493 va_list arg; 494 495 if (s) { 496 va_start(arg, s); 497 vsnprint(buf, ERRMAX, s, arg); 498 va_end(arg); 499 } 500 501 /* Clear away the slave children */ 502 // for(m = Proclist; m; m = m->next) 503 // postnote(PNPROC, m->pid, "kill"); 504 505 DEBUG(DFD, "%s\n", buf); 506 if (s) 507 sysfatal(buf); 508 else 509 sysfatal(""); 510 } 511 512