1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 6 #include "cformat.h" 7 #include "lru.h" 8 #include "bcache.h" 9 #include "disk.h" 10 #include "inode.h" 11 #include "file.h" 12 13 enum 14 { 15 Nfid= 1024, 16 }; 17 18 19 typedef struct Mfile Mfile; 20 typedef struct Ram Ram; 21 typedef struct P9fs P9fs; 22 23 struct Mfile 24 { 25 Qid qid; 26 short oldfid; 27 char needclone; 28 char busy; 29 }; 30 31 Mfile mfile[Nfid]; 32 char user[NAMELEN]; 33 Icache ic; 34 int debug; 35 36 struct P9fs 37 { 38 int fd[2]; 39 Fcall rhdr; 40 Fcall thdr; 41 long len; 42 char *name; 43 }; 44 45 P9fs c; /* client conversation */ 46 P9fs s; /* server conversation */ 47 48 char datasnd[MAXFDATA + MAXMSG]; 49 char datarcv[MAXFDATA + MAXMSG]; 50 51 void rsession(void); 52 void rflush(void); 53 void rattach(Mfile*); 54 void rclone(Mfile*); 55 void rwalk(Mfile*); 56 void rclwalk(Mfile*); 57 void ropen(Mfile*); 58 void rcreate(Mfile*); 59 void rread(Mfile*); 60 void rwrite(Mfile*); 61 void rclunk(Mfile*); 62 void rremove(Mfile*); 63 void rstat(Mfile*); 64 void rwstat(Mfile*); 65 void error(char*); 66 void warning(char*); 67 void mountinit(char*, char*); 68 void io(void); 69 void sendreply(char*); 70 void sendmsg(P9fs*, Fcall*); 71 void rcvmsg(P9fs*, Fcall*); 72 int delegate(void); 73 int askserver(void); 74 void cachesetup(int, char*); 75 int doclone(Mfile*); 76 void doclwalk(Mfile*, char*); 77 78 #define PREFACE(m) if(doclone(m) < 0) return 79 80 char *mname[]={ 81 [Tnop] "Tnop", 82 [Tsession] "Tsession", 83 [Tflush] "Tflush", 84 [Tattach] "Tattach", 85 [Tclone] "Tclone", 86 [Twalk] "Twalk", 87 [Topen] "Topen", 88 [Tcreate] "Tcreate", 89 [Tclunk] "Tclunk", 90 [Tread] "Tread", 91 [Twrite] "Twrite", 92 [Tremove] "Tremove", 93 [Tstat] "Tstat", 94 [Twstat] "Twstat", 95 [Tclwalk] "Tclwalk", 96 [Rnop] "Rnop", 97 [Rsession] "Rsession", 98 [Rerror] "Rerror", 99 [Rflush] "Rflush", 100 [Rattach] "Rattach", 101 [Rclone] "Rclone", 102 [Rwalk] "Rwalk", 103 [Ropen] "Ropen", 104 [Rcreate] "Rcreate", 105 [Rclunk] "Rclunk", 106 [Rread] "Rread", 107 [Rwrite] "Rwrite", 108 [Rremove] "Rremove", 109 [Rstat] "Rstat", 110 [Rwstat] "Rwstat", 111 [Rclwalk] "Rclwalk", 112 [Rauth] "Rauth", 113 0, 114 }; 115 116 void 117 usage(void) 118 { 119 fprint(2, "usage:\tcfs -s [-rd] [-f partition]"); 120 fprint(2, "\tcfs [-rd] [-f partition] [-a netaddr] [mt-pt]\n"); 121 } 122 123 void 124 main(int argc, char *argv[]) 125 { 126 int std; 127 int format; 128 char *part; 129 char *server; 130 char *mtpt; 131 132 std = 0; 133 format = 0; 134 part = "/dev/hd0cache"; 135 server = "dk!bootes"; 136 mtpt = "/tmp"; 137 138 ARGBEGIN{ 139 case 'a': 140 server = ARGF(); 141 if(server == 0) 142 usage(); 143 break; 144 case 's': 145 std = 1; 146 break; 147 case 'r': 148 format = 1; 149 break; 150 case 'f': 151 part = ARGF(); 152 if(part == 0) 153 usage(); 154 break; 155 case 'd': 156 debug = 1; 157 break; 158 default: 159 usage(); 160 }ARGEND 161 if(argc && *argv) 162 mtpt = *argv; 163 164 cachesetup(format, part); 165 166 c.name = "client"; 167 s.name = "server"; 168 if(std){ 169 c.fd[0] = c.fd[1] = 1; 170 s.fd[0] = s.fd[1] = 0; 171 }else 172 mountinit(server, mtpt); 173 174 switch(fork()){ 175 case 0: 176 io(); 177 exits(""); 178 case -1: 179 error("fork"); 180 default: 181 exits(""); 182 } 183 } 184 185 void 186 cachesetup(int format, char *partition) 187 { 188 int f; 189 int secsize; 190 int inodes; 191 int blocksize; 192 193 secsize = 512; 194 inodes = 1024; 195 blocksize = 4*1024; 196 197 f = open(partition, ORDWR); 198 if(f < 0) 199 error("opening partition"); 200 201 if(format || iinit(&ic, f, secsize)<0){ 202 if(iformat(&ic, f, inodes, "bootes", blocksize, secsize) < 0) 203 error("formatting failed"); 204 } 205 } 206 207 void 208 mountinit(char *server, char *mountpoint) 209 { 210 int p[2]; 211 212 /* 213 * grab a channel and call up the file server 214 */ 215 s.fd[0] = s.fd[1] = dial(netmkaddr(server, 0, 0), 0, 0, 0); 216 if(s.fd[0] < 0) 217 error("opening data"); 218 219 /* 220 * mount onto name space 221 */ 222 if(pipe(p) < 0) 223 error("pipe failed"); 224 switch(fork()){ 225 case 0: 226 break; 227 default: 228 if(amount(p[1], mountpoint, MREPL|MCREATE, "") < 0) 229 error("mount failed"); 230 exits(0); 231 case -1: 232 error("fork failed\n"); 233 /*BUG: no wait!*/ 234 } 235 c.fd[0] = c.fd[1] = p[0]; 236 } 237 238 void 239 io(void) 240 { 241 Mfile *mf; 242 loop: 243 rcvmsg(&c, &c.thdr); 244 mf = &mfile[c.thdr.fid]; 245 switch(c.thdr.type){ 246 default: 247 error("type"); 248 break; 249 case Tsession: 250 rsession(); 251 break; 252 case Tnop: 253 rflush(); 254 break; 255 case Tflush: 256 rflush(); 257 break; 258 case Tattach: 259 rattach(mf); 260 break; 261 case Tclone: 262 rclone(mf); 263 break; 264 case Twalk: 265 rwalk(mf); 266 break; 267 case Topen: 268 ropen(mf); 269 break; 270 case Tcreate: 271 rcreate(mf); 272 break; 273 case Tread: 274 rread(mf); 275 break; 276 case Twrite: 277 rwrite(mf); 278 break; 279 case Tclunk: 280 rclunk(mf); 281 break; 282 case Tremove: 283 rremove(mf); 284 break; 285 case Tstat: 286 rstat(mf); 287 break; 288 case Twstat: 289 rwstat(mf); 290 break; 291 } 292 goto loop; 293 } 294 295 void 296 rsession(void) 297 { 298 delegate(); 299 } 300 301 void 302 rflush(void) /* synchronous so easy */ 303 { 304 sendreply(0); 305 } 306 307 void 308 rattach(Mfile *mf) 309 { 310 if(delegate() == 0){ 311 mf->qid = s.rhdr.qid; 312 mf->busy = 1; 313 mf->needclone = 0; 314 } 315 } 316 317 /* 318 * check consistency and perform a delayed clone 319 */ 320 int 321 doclone(Mfile *mf) 322 { 323 Mfile *omf; 324 325 if(!mf->busy) 326 error("bad fid"); 327 if(!mf->needclone) 328 return 0; 329 omf = &mfile[mf->oldfid]; 330 if(!omf->busy) 331 error("bad old fid"); 332 333 s.thdr.type = Tclone; 334 s.thdr.fid = mf->oldfid; 335 s.thdr.newfid = mf - mfile; 336 mf->needclone = 0; 337 if(askserver() == 0) 338 return 0; 339 sendreply(s.rhdr.ename); 340 return -1; 341 } 342 343 /* 344 * don't send clone to server, just reply to client 345 */ 346 void 347 rclone(Mfile *mf) 348 { 349 Mfile *nmf; 350 351 PREFACE(mf); 352 if(c.thdr.newfid<0 || Nfid<=c.thdr.newfid) 353 error("clone nfid out of range"); 354 nmf = &mfile[c.thdr.newfid]; 355 if(nmf->busy) 356 error("clone to used channel"); 357 nmf = &mfile[c.thdr.newfid]; 358 nmf->qid = mf->qid; 359 nmf->needclone = 1; 360 nmf->oldfid = mf - mfile; 361 nmf->busy = 1; 362 sendreply(0); 363 } 364 365 /* 366 * do a combined clone and walk. An error implies a clunk. A reply with 367 * the wrong fid implies a "directory entry not found". 368 */ 369 void 370 doclwalk(Mfile *mf, char *name) 371 { 372 s.thdr.type = Tclwalk; 373 s.thdr.fid = mf->oldfid; 374 s.thdr.newfid = mf - mfile; 375 memmove(s.thdr.name, name, sizeof s.thdr.name); 376 if(askserver() == 0){ 377 if(s.rhdr.fid == s.thdr.fid){ 378 /* 379 * this is really a short form of 380 * Terror "directory entry not found" 381 */ 382 mf->busy = 0; 383 sendreply("directory entry not found"); 384 return; 385 } 386 mf->qid = s.rhdr.qid; 387 c.rhdr.qid = s.rhdr.qid; 388 mf->needclone = 0; 389 sendreply(0); 390 } else { 391 mf->busy = 0; 392 sendreply(s.rhdr.ename); 393 } 394 } 395 396 void 397 rwalk(Mfile *mf) 398 { 399 if(mf->needclone){ 400 doclwalk(mf, c.thdr.name); 401 return; 402 } 403 if(delegate() == 0) 404 mf->qid = s.rhdr.qid; 405 } 406 407 void 408 rclwalk(Mfile *mf) 409 { 410 if(delegate() == 0) 411 mf->qid = s.rhdr.qid; 412 } 413 414 void 415 ropen(Mfile *mf) 416 { 417 PREFACE(mf); 418 if(delegate() == 0){ 419 mf->qid = s.rhdr.qid; 420 if(c.thdr.mode & OTRUNC){ 421 mf->qid.vers++; 422 iget(&ic, mf->qid); 423 } 424 } 425 } 426 427 void 428 rcreate(Mfile *mf) 429 { 430 PREFACE(mf); 431 if(delegate() == 0){ 432 mf->qid = s.rhdr.qid; 433 mf->qid.vers++; 434 } 435 } 436 437 void 438 rclunk(Mfile *mf) 439 { 440 if(!mf->busy){ 441 sendreply(0); 442 return; 443 } 444 mf->busy = 0; 445 mf->needclone = 0; 446 delegate(); 447 } 448 449 void 450 rremove(Mfile *mf) 451 { 452 PREFACE(mf); 453 mf->busy = 0; 454 delegate(); 455 } 456 457 void 458 rread(Mfile *mf) 459 { 460 int cnt; 461 long off, first; 462 char *cp; 463 Ibuf *b; 464 long n; 465 char data[MAXFDATA]; 466 int done; 467 468 PREFACE(mf); 469 first = off = c.thdr.offset; 470 cnt = c.thdr.count; 471 472 if(mf->qid.path & CHDIR){ 473 delegate(); 474 return; 475 } 476 477 b = iget(&ic, mf->qid); 478 if(b == 0){ 479 delegate(); 480 return; 481 } 482 483 cp = data; 484 done = 0; 485 while(cnt>0 && !done){ 486 n = fread(&ic, b, cp, off, cnt); 487 if(n <= 0){ 488 n = -n; 489 if(n==0 || n>cnt) 490 n = cnt; 491 s.thdr.type = c.thdr.type; 492 s.thdr.fid = c.thdr.fid; 493 s.thdr.tag = c.thdr.tag; 494 s.thdr.offset = off; 495 s.thdr.count = n; 496 if(askserver() < 0) 497 sendreply(s.rhdr.ename); 498 if(s.rhdr.count != n) 499 done = 1; 500 n = s.rhdr.count; 501 memmove(cp, s.rhdr.data, n); 502 fwrite(&ic, b, cp, off, n); 503 } 504 cnt -= n; 505 off += n; 506 cp += n; 507 } 508 c.rhdr.data = data; 509 c.rhdr.count = off - first; 510 sendreply(0); 511 } 512 513 void 514 rwrite(Mfile *mf) 515 { 516 Ibuf *b; 517 char buf[MAXFDATA]; 518 519 PREFACE(mf); 520 if(mf->qid.path & CHDIR){ 521 delegate(); 522 return; 523 } 524 525 memmove(buf, c.thdr.data, c.thdr.count); 526 if(delegate() < 0) 527 return; 528 529 b = iget(&ic, mf->qid); 530 if(b == 0) 531 return; 532 mf->qid.vers++; 533 if(fwrite(&ic, b, buf, c.thdr.offset, c.thdr.count) == c.thdr.count) 534 iinc(&ic, b); 535 } 536 537 void 538 rstat(Mfile *mf) 539 { 540 PREFACE(mf); 541 delegate(); 542 } 543 544 void 545 rwstat(Mfile *mf) 546 { 547 PREFACE(mf); 548 delegate(); 549 } 550 551 void 552 error(char *s) 553 { 554 fprint(2, "cfs: %s: ", s); 555 perror(""); 556 exits(s); 557 } 558 559 void 560 warning(char *s) 561 { 562 char buf[ERRLEN]; 563 564 errstr(buf); 565 fprint(2, "cfs: %s: %s\n", s, buf); 566 if(strstr(buf, "illegal network address")) 567 exits("death"); 568 } 569 570 /* 571 * send a reply to the client 572 */ 573 void 574 sendreply(char *err) 575 { 576 577 if(err){ 578 c.rhdr.type = Rerror; 579 strncpy(c.rhdr.ename, err, ERRLEN); 580 }else{ 581 c.rhdr.type = c.thdr.type+1; 582 c.rhdr.fid = c.thdr.fid; 583 } 584 c.rhdr.tag = c.thdr.tag; 585 sendmsg(&c, &c.rhdr); 586 } 587 588 /* 589 * send a request to the server, get the reply, and send that to 590 * the client 591 */ 592 int 593 delegate(void) 594 { 595 sendmsg(&s, &c.thdr); 596 rcvmsg(&s, &s.rhdr); 597 sendmsg(&c, &s.rhdr); 598 return c.thdr.type+1 == s.rhdr.type ? 0 : -1; 599 } 600 601 /* 602 * send a request to the server and get a reply 603 */ 604 int 605 askserver(void) 606 { 607 s.thdr.tag = c.thdr.tag; 608 sendmsg(&s, &s.thdr); 609 rcvmsg(&s, &s.rhdr); 610 return s.thdr.type+1 == s.rhdr.type ? 0 : -1; 611 } 612 613 /* 614 * send/receive messages with logging 615 */ 616 void 617 sendmsg(P9fs *p, Fcall *f) 618 { 619 DPRINT(2, "->%s: %d %s on %d\n", p->name, f->type, 620 mname[f->type]? mname[f->type] : "mystery", 621 f->fid); 622 623 p->len = convS2M(f, datasnd); 624 if(write9p(p->fd[1], datasnd, p->len)!=p->len) 625 error("smdmsg"); 626 } 627 628 void 629 dump(uchar *p, int len) 630 { 631 fprint(2, "%d bytes", len); 632 while(len > 0){ 633 fprint(2, " %.2ux", *p++); 634 len--; 635 } 636 fprint(2, "\n"); 637 } 638 639 void 640 rcvmsg(P9fs *p, Fcall *f) 641 { 642 int olen; 643 644 olen = p->len; 645 retry: 646 p->len = read9p(p->fd[0], datarcv, sizeof(datarcv)); 647 if(p->len <= 0) 648 error("rcvmsg"); 649 if(p->len==2 && datarcv[0]=='O' && datarcv[1]=='K') 650 goto retry; 651 if(convM2S(datarcv, f, p->len) == 0) 652 error("rcvmsg format error"); 653 if(f->type != Rauth && (f->fid<0 || Nfid<=f->fid)){ 654 fprint(2, "<-%s: %d %s on %d\n", p->name, f->type, 655 mname[f->type]? mname[f->type] : "mystery", 656 f->fid); 657 dump((uchar*)datasnd, olen); 658 dump((uchar*)datarcv, p->len); 659 error("rcvmsg fid out of range"); 660 } 661 DPRINT(2, "<-%s: %d %s on %d\n", p->name, f->type, 662 mname[f->type]? mname[f->type] : "mystery", 663 f->fid); 664 } 665