1 #ifndef EMU 2 #include "u.h" 3 #include "../port/lib.h" 4 #include "../port/error.h" 5 #include "mem.h" 6 #else 7 #include "error.h" 8 #endif 9 #include "dat.h" 10 #include "fns.h" 11 #include "kernel.h" 12 #include "logfs.h" 13 #include "nandfs.h" 14 15 #ifndef EMU 16 #define Sleep sleep 17 #define Wakeup wakeup 18 #endif 19 20 typedef struct Devlogfs Devlogfs; 21 typedef struct DevlogfsSession DevlogfsSession; 22 23 //#define CALLTRACE 24 25 enum { 26 DEVLOGFSDEBUG = 0, 27 DEVLOGFSIODEBUG = 0, 28 DEVLOGFSBAD = 1, 29 }; 30 31 enum { 32 Qdir, 33 Qctl, 34 Qusers, 35 Qdump, 36 Qfs, 37 Qfsboot, 38 Qend, 39 }; 40 41 typedef enum DevlogfsServerState { Closed, BootOpen, NeedVersion, NeedAttach, Attached, Hungup } DevlogfsServerState; 42 43 struct Devlogfs { 44 QLock qlock; 45 QLock rlock; 46 QLock wlock; 47 Ref ref; 48 int instance; 49 int trace; /* (debugging) trace of read/write actions */ 50 int nand; 51 char *name; 52 char *device; 53 char *filename[Qend - Qfs]; 54 LogfsLowLevel *ll; 55 Chan *flash, *flashctl; 56 QLock bootqlock; 57 int logfstrace; 58 LogfsBoot *lb; 59 /* stuff for server */ 60 ulong openflags; 61 Fcall in; 62 Fcall out; 63 int reading; 64 DevlogfsServerState state; 65 Rendez readrendez; 66 Rendez writerendez; 67 uint readcount; 68 ulong readbufsize; 69 uchar *readbuf; 70 uchar *readp; 71 LogfsServer *server; 72 Devlogfs *next; 73 }; 74 75 #define MAXMSIZE 8192 76 77 static struct { 78 RWlock rwlock; /* rlock when walking, wlock when changing */ 79 QLock configqlock; /* serialises addition of new configurations */ 80 Devlogfs *head; 81 char *defname; 82 } devlogfslist; 83 84 static LogfsIdentityStore *is; 85 86 #ifndef EMU 87 char Eunknown[] = "unknown user or group id"; 88 #endif 89 90 static void devlogfsfree(Devlogfs*); 91 92 #define SPLITPATH(path, qtype, instance, qid, qt) { instance = path >> 4; qid = path & 0xf; qt = qtype & QTDIR; } 93 #define DATAQID(q, qt) (!(qt) && (q) >= Qfs && (q) < Qend) 94 #define MKPATH(instance, qid) ((instance << 4) | qid) 95 96 #define PREFIX "logfs" 97 98 static char *devlogfsprefix = PREFIX; 99 static char *devlogfsctlname = PREFIX "ctl"; 100 static char *devlogfsusersname = PREFIX "users"; 101 static char *devlogfsdumpname = PREFIX "dump"; 102 static char *devlogfsbootsuffix = "boot"; 103 static char *devlogfs9pversion = "9P2000"; 104 105 static void 106 errorany(char *errmsg) 107 { 108 if (errmsg) 109 error(errmsg); 110 } 111 112 static void * 113 emalloc(ulong size) 114 { 115 void *p; 116 p = logfsrealloc(nil, size); 117 if (p == nil) 118 error(Enomem); 119 return p; 120 } 121 122 static char * 123 estrdup(char *q) 124 { 125 void *p; 126 if (q == nil) 127 return nil; 128 p = logfsrealloc(nil, strlen(q) + 1); 129 if (p == nil) 130 error(Enomem); 131 return strcpy(p, q); 132 } 133 134 static char * 135 estrconcat(char *a, ...) 136 { 137 va_list l; 138 char *p, *r; 139 int t; 140 141 t = strlen(a); 142 va_start(l, a); 143 while ((p = va_arg(l, char *)) != nil) 144 t += strlen(p); 145 146 r = logfsrealloc(nil, t + 1); 147 if (r == nil) 148 error(Enomem); 149 150 strcpy(r, a); 151 va_start(l, a); 152 while ((p = va_arg(l, char *)) != nil) 153 strcat(r, p); 154 155 va_end(l); 156 157 return r; 158 } 159 160 static int 161 gen(Chan *c, int i, Dir *dp, int lockit) 162 { 163 Devlogfs *l; 164 long size; 165 Qid qid; 166 qid.vers = 0; 167 qid.type = 0; 168 169 if (i + Qctl < Qfs) { 170 switch (i + Qctl) { 171 case Qctl: 172 qid.path = Qctl; 173 devdir(c, qid, devlogfsctlname, 0, eve, 0666, dp); 174 return 1; 175 case Qusers: 176 qid.path = Qusers; 177 devdir(c, qid, devlogfsusersname, 0, eve, 0444, dp); 178 return 1; 179 case Qdump: 180 qid.path = Qdump; 181 devdir(c, qid, devlogfsdumpname, 0, eve, 0444, dp); 182 return 1; 183 } 184 } 185 186 i -= Qfs - Qctl; 187 188 if (lockit) 189 rlock(&devlogfslist.rwlock); 190 191 if (waserror()) { 192 if (lockit) 193 runlock(&devlogfslist.rwlock); 194 nexterror(); 195 } 196 197 for (l = devlogfslist.head; l; l = l->next) { 198 if (i < Qend - Qfs) 199 break; 200 i -= Qend - Qfs; 201 } 202 203 if (l == nil) { 204 poperror(); 205 if (lockit) 206 runlock(&devlogfslist.rwlock); 207 return -1; 208 } 209 210 switch (Qfs + i) { 211 case Qfsboot: 212 size = l->lb ? logfsbootgetsize(l->lb) : 0; 213 break; 214 default: 215 size = 0; 216 break; 217 } 218 /* perhaps the user id should come from the underlying file */ 219 qid.path = MKPATH(l->instance, Qfs + i); 220 devdir(c, qid, l->filename[i], size, eve, 0666, dp); 221 222 poperror(); 223 if (lockit) 224 runlock(&devlogfslist.rwlock); 225 226 return 1; 227 } 228 229 static int 230 devlogfsgen(Chan *c, char *n, Dirtab *tab, int ntab, int i, Dir *dp) 231 { 232 USED(n); 233 USED(tab); 234 USED(ntab); 235 return gen(c, i, dp, 1); 236 } 237 238 static int 239 devlogfsgennolock(Chan *c, char *n, Dirtab *tab, int ntab, int i, Dir *dp) 240 { 241 USED(n); 242 USED(tab); 243 USED(ntab); 244 return gen(c, i, dp, 0); 245 } 246 247 /* called under lock */ 248 static Devlogfs * 249 devlogfsfind(int instance) 250 { 251 Devlogfs *l; 252 253 for (l = devlogfslist.head; l; l = l->next) 254 if (l->instance == instance) 255 break; 256 return l; 257 } 258 259 static Devlogfs * 260 devlogfsget(int instance) 261 { 262 Devlogfs *l; 263 rlock(&devlogfslist.rwlock); 264 for (l = devlogfslist.head; l; l = l->next) 265 if (l->instance == instance) 266 break; 267 if (l) 268 incref(&l->ref); 269 runlock(&devlogfslist.rwlock); 270 return l; 271 } 272 273 static Devlogfs * 274 devlogfsfindbyname(char *name) 275 { 276 Devlogfs *l; 277 278 rlock(&devlogfslist.rwlock); 279 for (l = devlogfslist.head; l; l = l->next) 280 if (strcmp(l->name, name) == 0) 281 break; 282 runlock(&devlogfslist.rwlock); 283 return l; 284 } 285 286 static Devlogfs * 287 devlogfssetdefname(char *name) 288 { 289 Devlogfs *l; 290 char *searchname; 291 wlock(&devlogfslist.rwlock); 292 if (waserror()) { 293 wunlock(&devlogfslist.rwlock); 294 nexterror(); 295 } 296 if (name == nil) 297 searchname = devlogfslist.defname; 298 else 299 searchname = name; 300 for (l = devlogfslist.head; l; l = l->next) 301 if (strcmp(l->name, searchname) == 0) 302 break; 303 if (l == nil) { 304 logfsfreemem(devlogfslist.defname); 305 devlogfslist.defname = nil; 306 } 307 else if (name) { 308 if (devlogfslist.defname) { 309 logfsfreemem(devlogfslist.defname); 310 devlogfslist.defname = nil; 311 } 312 devlogfslist.defname = estrdup(name); 313 } 314 poperror(); 315 wunlock(&devlogfslist.rwlock); 316 return l; 317 } 318 319 static Chan * 320 devlogfskopen(char *name, char *suffix, int mode) 321 { 322 Chan *c; 323 char *fn; 324 int fd; 325 326 fn = estrconcat(name, suffix, 0); 327 fd = kopen(fn, mode); 328 logfsfreemem(fn); 329 if (fd < 0) 330 error(up->env->errstr); 331 c = fdtochan(up->env->fgrp, fd, mode, 0, 1); 332 kclose(fd); 333 return c; 334 } 335 336 static char * 337 xread(void *a, void *buf, long nbytes, ulong offset) 338 { 339 Devlogfs *l = a; 340 long rv; 341 342 if (DEVLOGFSIODEBUG || l->trace) 343 print("devlogfs: %s: read(0x%lux, %ld)\n", l->device, offset, nbytes); 344 l->flash->offset = offset; 345 rv = kchanio(l->flash, buf, nbytes, OREAD); 346 if (rv < 0) { 347 print("devlogfs: %s: flash read error: %s\n", l->device, up->env->errstr); 348 return up->env->errstr; 349 } 350 if (rv != nbytes) { 351 print("devlogfs: %s: short flash read: offset %lud, %ld not %ld\n", l->device, offset, rv, nbytes); 352 return "short read"; 353 } 354 return nil; 355 } 356 357 static char * 358 xwrite(void *a, void *buf, long nbytes, ulong offset) 359 { 360 Devlogfs *l = a; 361 long rv; 362 363 if (DEVLOGFSIODEBUG || l->trace) 364 print("devlogfs: %s: write(0x%lux, %ld)\n", l->device, offset, nbytes); 365 l->flash->offset = offset; 366 rv = kchanio(l->flash, buf, nbytes, OWRITE); 367 if (rv < 0) { 368 print("devlogfs: %s: flash write error: %s\n", l->device, up->env->errstr); 369 return up->env->errstr; 370 } 371 if (rv != nbytes) { 372 print("devlogfs: %s: short flash write: offset %lud, %ld not %ld\n", l->device, offset, rv, nbytes); 373 return "short write"; 374 } 375 return nil; 376 } 377 378 static char * 379 xerase(void *a, long address) 380 { 381 Devlogfs *l = a; 382 char cmd[40]; 383 384 if (DEVLOGFSIODEBUG || l->trace) 385 print("devlogfs: %s: erase(0x%lux)\n", l->device, address); 386 snprint(cmd, sizeof(cmd), "erase 0x%8.8lux", address); 387 if (kchanio(l->flashctl, cmd, strlen(cmd), OWRITE) <= 0) { 388 print("devlogfs: %s: flash erase error: %s\n", l->device, up->env->errstr); 389 return up->env->errstr; 390 } 391 return nil; 392 } 393 394 static char * 395 xsync(void *a) 396 { 397 Devlogfs *l = a; 398 399 if (DEVLOGFSIODEBUG || l->trace) 400 print("devlogfs: %s: sync()\n", l->device); 401 if (kchanio(l->flashctl, "sync", 4, OWRITE) <= 0){ 402 print("devlogfs: %s: flash sync error: %s\n", l->device, up->env->errstr); 403 return up->env->errstr; 404 } 405 return nil; 406 } 407 408 //#define LEAKHUNT 409 #ifdef LEAKHUNT 410 #define MAXLIVE 2000 411 typedef struct Live { 412 void *p; 413 int freed; 414 ulong callerpc; 415 } Live; 416 417 static Live livemem[MAXLIVE]; 418 419 static void 420 leakalloc(void *p, ulong callerpc) 421 { 422 int x; 423 int use = -1; 424 for (x = 0; x < MAXLIVE; x++) { 425 if (livemem[x].p == p) { 426 if (!livemem[x].freed) 427 print("leakalloc: unexpected realloc of 0x%.8lux from 0x%.8lux\n", p, callerpc); 428 // else 429 // print("leakalloc: reusing address 0x%.8lux from 0x%.8lux\n", p, callerpc); 430 livemem[x].freed = 0; 431 livemem[x].callerpc = callerpc; 432 return; 433 } 434 else if (use < 0 && livemem[x].p == 0) 435 use = x; 436 } 437 if (use < 0) 438 panic("leakalloc: too many live entries"); 439 livemem[use].p = p; 440 livemem[use].freed = 0; 441 livemem[use].callerpc = callerpc; 442 } 443 444 static void 445 leakaudit(void) 446 { 447 int x; 448 for (x = 0; x < MAXLIVE; x++) { 449 if (livemem[x].p && !livemem[x].freed) 450 print("leakaudit: 0x%.8lux from 0x%.8lux\n", livemem[x].p, livemem[x].callerpc); 451 } 452 } 453 454 static void 455 leakfree(void *p, ulong callerpc) 456 { 457 int x; 458 if (p == nil) 459 return; 460 for (x = 0; x < MAXLIVE; x++) { 461 if (livemem[x].p == p) { 462 if (livemem[x].freed) 463 print("leakfree: double free of 0x%.8lux from 0x%.8lux, originally by 0x%.8lux\n", 464 p, callerpc, livemem[x].callerpc); 465 livemem[x].freed = 1; 466 livemem[x].callerpc = callerpc; 467 return; 468 } 469 } 470 print("leakfree: free of unalloced address 0x%.8lux from 0x%.8lux\n", p, callerpc); 471 leakaudit(); 472 } 473 474 static void 475 leakrealloc(void *newp, void *oldp, ulong callerpc) 476 { 477 leakfree(oldp, callerpc); 478 leakalloc(newp, callerpc); 479 } 480 #endif 481 482 483 #ifdef LEAKHUNT 484 static void *_realloc(void *p, ulong size, ulong callerpc) 485 #else 486 void * 487 logfsrealloc(void *p, ulong size) 488 #endif 489 { 490 void *q; 491 ulong osize; 492 if (waserror()) { 493 print("wobbly thrown in memory allocator: %s\n", up->env->errstr); 494 nexterror(); 495 } 496 if (p == nil) { 497 q = smalloc(size); 498 poperror(); 499 #ifdef LEAKHUNT 500 leakrealloc(q, nil, callerpc); 501 #endif 502 return q; 503 } 504 q = realloc(p, size); 505 if (q) { 506 poperror(); 507 #ifdef LEAKHUNT 508 leakrealloc(q, p, callerpc); 509 #endif 510 return q; 511 } 512 q = smalloc(size); 513 osize = msize(p); 514 if (osize > size) 515 osize = size; 516 memmove(q, p, osize); 517 free(p); 518 poperror(); 519 #ifdef LEAKHUNT 520 leakrealloc(q, p, callerpc); 521 #endif 522 return q; 523 } 524 525 #ifdef LEAKHUNT 526 void * 527 logfsrealloc(void *p, ulong size) 528 { 529 return _realloc(p, size, getcallerpc(&p)); 530 } 531 532 void * 533 nandfsrealloc(void *p, ulong size) 534 { 535 return _realloc(p, size, getcallerpc(&p)); 536 } 537 #else 538 void * 539 nandfsrealloc(void *p, ulong size) 540 { 541 return logfsrealloc(p, size); 542 } 543 #endif 544 545 void 546 logfsfreemem(void *p) 547 { 548 #ifdef LEAKHUNT 549 leakfree(p, getcallerpc(&p)); 550 #endif 551 free(p); 552 } 553 554 void 555 nandfsfreemem(void *p) 556 { 557 #ifdef LEAKHUNT 558 leakfree(p, getcallerpc(&p)); 559 #endif 560 free(p); 561 } 562 563 static Devlogfs * 564 devlogfsconfig(char *name, char *device) 565 { 566 Devlogfs *newl, *l; 567 int i; 568 int n; 569 char buf[100], *fields[12]; 570 long rawblocksize, rawsize; 571 572 newl = nil; 573 574 qlock(&devlogfslist.configqlock); 575 576 if (waserror()) { 577 qunlock(&devlogfslist.configqlock); 578 devlogfsfree(newl); 579 nexterror(); 580 } 581 582 rlock(&devlogfslist.rwlock); 583 for (l = devlogfslist.head; l; l = l->next) 584 if (strcmp(l->name, name) == 0) { 585 runlock(&devlogfslist.rwlock); 586 error(Einuse); 587 } 588 589 /* horrid n^2 solution to finding a unique instance number */ 590 591 for (i = 0;; i++) { 592 for (l = devlogfslist.head; l; l = l->next) 593 if (l->instance == i) 594 break; 595 if (l == nil) 596 break; 597 } 598 runlock(&devlogfslist.rwlock); 599 600 newl = emalloc(sizeof(Devlogfs)); 601 newl->instance = i; 602 newl->name = estrdup(name); 603 newl->device = estrdup(device); 604 newl->filename[Qfs - Qfs] = estrconcat(devlogfsprefix, name, nil); 605 newl->filename[Qfsboot - Qfs] = estrconcat(devlogfsprefix, name, devlogfsbootsuffix, nil); 606 newl->flash = devlogfskopen(device, nil, ORDWR); 607 newl->flashctl = devlogfskopen(device, "ctl", ORDWR); 608 newl->flashctl->offset = 0; 609 if ((n = kchanio(newl->flashctl, buf, sizeof(buf), OREAD)) <= 0) { 610 print("devlogfsconfig: read ctl failed: %s\n", up->env->errstr); 611 error(up->env->errstr); 612 } 613 614 if (n >= sizeof(buf)) 615 n = sizeof(buf) - 1; 616 buf[n] = 0; 617 n = tokenize(buf, fields, nelem(fields)); 618 if(n < 7) 619 error("unexpected flashctl format"); 620 newl->nand = strcmp(fields[3], "nand") == 0; 621 rawblocksize = strtol(fields[6], nil, 0); 622 rawsize = strtol(fields[5], nil, 0)-strtol(fields[4], nil, 0); 623 if(newl->nand == 0) 624 error("only NAND supported at the moment"); 625 errorany(nandfsinit(newl, rawsize, rawblocksize, xread, xwrite, xerase, xsync, &newl->ll)); 626 wlock(&devlogfslist.rwlock); 627 newl->next = devlogfslist.head; 628 devlogfslist.head = newl; 629 logfsfreemem(devlogfslist.defname); 630 devlogfslist.defname = nil; 631 if (!waserror()){ 632 devlogfslist.defname = estrdup(name); 633 poperror(); 634 } 635 wunlock(&devlogfslist.rwlock); 636 poperror(); 637 qunlock(&devlogfslist.configqlock); 638 return newl; 639 } 640 641 static void 642 devlogfsunconfig(Devlogfs *devlogfs) 643 { 644 Devlogfs **lp; 645 646 qlock(&devlogfslist.configqlock); 647 648 if (waserror()) { 649 qunlock(&devlogfslist.configqlock); 650 nexterror(); 651 } 652 653 wlock(&devlogfslist.rwlock); 654 655 if (waserror()) { 656 wunlock(&devlogfslist.rwlock); 657 nexterror(); 658 } 659 660 for (lp = &devlogfslist.head; *lp && (*lp) != devlogfs; lp = &(*lp)->next) 661 ; 662 if (*lp == nil) { 663 if (DEVLOGFSBAD) 664 print("devlogfsunconfig: not in list\n"); 665 } 666 else 667 *lp = devlogfs->next; 668 669 poperror(); 670 wunlock(&devlogfslist.rwlock); 671 672 /* now invisible to the naked eye */ 673 devlogfsfree(devlogfs); 674 poperror(); 675 qunlock(&devlogfslist.configqlock); 676 } 677 678 static void 679 devlogfsllopen(Devlogfs *l) 680 { 681 qlock(&l->qlock); 682 if (waserror()) { 683 qunlock(&l->qlock); 684 nexterror(); 685 } 686 if (l->lb == nil) 687 errorany(logfsbootopen(l->ll, 0, 0, l->logfstrace, 1, &l->lb)); 688 l->state = BootOpen; 689 poperror(); 690 qunlock(&l->qlock); 691 } 692 693 static void 694 devlogfsllformat(Devlogfs *l, long bootsize) 695 { 696 qlock(&l->qlock); 697 if (waserror()) { 698 qunlock(&l->qlock); 699 nexterror(); 700 } 701 if (l->lb == nil) 702 errorany(logfsformat(l->ll, 0, 0, bootsize, l->logfstrace)); 703 poperror(); 704 qunlock(&l->qlock); 705 } 706 707 static Chan * 708 devlogfsattach(char *spec) 709 { 710 Chan *c; 711 #ifdef CALLTRACE 712 print("devlogfsattach(spec = %s) - start\n", spec); 713 #endif 714 /* create the identity store on first attach */ 715 if (is == nil) 716 errorany(logfsisnew(&is)); 717 c = devattach(0x29f, spec); 718 // c = devattach(L'ʟ', spec); 719 #ifdef CALLTRACE 720 print("devlogfsattach(spec = %s) - return %.8lux\n", spec, (ulong)c); 721 #endif 722 return c; 723 } 724 725 static Walkqid* 726 devlogfswalk(Chan *c, Chan *nc, char **name, int nname) 727 { 728 int instance, qid, qt, clone; 729 Walkqid *wq; 730 731 #ifdef CALLTRACE 732 print("devlogfswalk(c = 0x%.8lux, nc = 0x%.8lux, name = 0x%.8lux, nname = %d) - start\n", 733 (ulong)c, (ulong)nc, (ulong)name, nname); 734 #endif 735 clone = 0; 736 if(nc == nil){ 737 nc = devclone(c); 738 nc->type = 0; 739 SPLITPATH(c->qid.path, c->qid.type, instance, qid, qt); 740 if(DATAQID(qid, qt)) 741 nc->aux = devlogfsget(instance); 742 clone = 1; 743 } 744 wq = devwalk(c, nc, name, nname, 0, 0, devlogfsgen); 745 if (wq == nil || wq->nqid < nname) { 746 if(clone) 747 cclose(nc); 748 } 749 else if (clone) { 750 wq->clone = nc; 751 nc->type = c->type; 752 } 753 #ifdef CALLTRACE 754 print("devlogfswalk(c = 0x%.8lux, nc = 0x%.8lux, name = 0x%.8lux, nname = %d) - return\n", 755 (ulong)c, (ulong)nc, (ulong)name, nname); 756 #endif 757 return wq; 758 } 759 760 static int 761 devlogfsstat(Chan *c, uchar *dp, int n) 762 { 763 #ifdef CALLTRACE 764 print("devlogfsstat(c = 0x%.8lux, dp = 0x%.8lux n= %d)\n", 765 (ulong)c, (ulong)dp, n); 766 #endif 767 return devstat(c, dp, n, 0, 0, devlogfsgen); 768 } 769 770 static Chan* 771 devlogfsopen(Chan *c, int omode) 772 { 773 int instance, qid, qt; 774 775 omode = openmode(omode); 776 SPLITPATH(c->qid.path, c->qid.type, instance, qid, qt); 777 #ifdef CALLTRACE 778 print("devlogfsopen(c = 0x%.8lux, omode = %o, instance = %d, qid = %d, qt = %d)\n", 779 (ulong)c, omode, instance, qid, qt); 780 #endif 781 782 783 rlock(&devlogfslist.rwlock); 784 if (waserror()) { 785 runlock(&devlogfslist.rwlock); 786 #ifdef CALLTRACE 787 print("devlogfsopen(c = 0x%.8lux, omode = %o) - error %s\n", (ulong)c, omode, up->env->errstr); 788 #endif 789 nexterror(); 790 } 791 792 if (DATAQID(qid, qt)) { 793 Devlogfs *d; 794 d = devlogfsfind(instance); 795 if (d == nil) 796 error(Enodev); 797 if (strcmp(up->env->user, eve) != 0) 798 error(Eperm); 799 if (qid == Qfs && d->state != BootOpen) 800 error(Eperm); 801 if (d->server == nil) { 802 errorany(logfsservernew(d->lb, d->ll, is, d->openflags, d->logfstrace, &d->server)); 803 d->state = NeedVersion; 804 } 805 c = devopen(c, omode, 0, 0, devlogfsgennolock); 806 incref(&d->ref); 807 c->aux = d; 808 } 809 else if (qid == Qctl || qid == Qusers) { 810 if (strcmp(up->env->user, eve) != 0) 811 error(Eperm); 812 c = devopen(c, omode, 0, 0, devlogfsgennolock); 813 } 814 else 815 c = devopen(c, omode, 0, 0, devlogfsgennolock); 816 poperror(); 817 runlock(&devlogfslist.rwlock); 818 #ifdef CALLTRACE 819 print("devlogfsopen(c = 0x%.8lux, omode = %o) - return\n", (ulong)c, omode); 820 #endif 821 return c; 822 } 823 824 static void 825 devlogfsclose(Chan *c) 826 { 827 int instance, qid, qt; 828 #ifdef CALLTRACE 829 print("devlogfsclose(c = 0x%.8lux)\n", (ulong)c); 830 #endif 831 SPLITPATH(c->qid.path, c->qid.type, instance, qid, qt); 832 USED(instance); 833 if(DATAQID(qid, qt) && (c->flag & COPEN) != 0) { 834 Devlogfs *d; 835 d = c->aux; 836 qlock(&d->qlock); 837 if (qid == Qfs && d->state == Attached) { 838 logfsserverflush(d->server); 839 logfsserverfree(&d->server); 840 d->state = BootOpen; 841 } 842 qunlock(&d->qlock); 843 decref(&d->ref); 844 } 845 #ifdef CALLTRACE 846 print("devlogfsclose(c = 0x%.8lux) - return\n", (ulong)c); 847 #endif 848 } 849 850 typedef char *(SMARTIOFN)(void *magic, void *buf, long n, ulong offset, int write); 851 852 static void 853 smartio(SMARTIOFN *io, void *magic, void *buf, long n, ulong offset, long blocksize, int write) 854 { 855 void *tmp = nil; 856 ulong blocks, toread; 857 858 if (waserror()) { 859 logfsfreemem(tmp); 860 nexterror(); 861 } 862 if (offset % blocksize) { 863 ulong aoffset; 864 int tmpoffset; 865 int tocopy; 866 867 if (tmp == nil) 868 tmp = emalloc(blocksize); 869 aoffset = offset / blocksize; 870 aoffset *= blocksize; 871 errorany((*io)(magic, tmp, blocksize, aoffset, 0)); 872 tmpoffset = offset - aoffset; 873 tocopy = blocksize - tmpoffset; 874 if (tocopy > n) 875 tocopy = n; 876 if (write) { 877 memmove((uchar *)tmp + tmpoffset, buf, tocopy); 878 errorany((*io)(magic, tmp, blocksize, aoffset, 1)); 879 } 880 else 881 memmove(buf, (uchar *)tmp + tmpoffset, tocopy); 882 buf = (uchar *)buf + tocopy; 883 n -= tocopy; 884 offset = aoffset + blocksize; 885 } 886 blocks = n / blocksize; 887 toread = blocks * blocksize; 888 errorany((*io)(magic, buf, toread, offset, write)); 889 buf = (uchar *)buf + toread; 890 n -= toread; 891 offset += toread; 892 if (n) { 893 if (tmp == nil) 894 tmp = emalloc(blocksize); 895 errorany((*io)(magic, tmp, blocksize, offset, 0)); 896 if (write) { 897 memmove(tmp, buf, n); 898 errorany((*io)(magic, tmp, blocksize, offset, 1)); 899 } 900 memmove(buf, tmp, n); 901 } 902 poperror(); 903 logfsfreemem(tmp); 904 } 905 906 static int 907 readok(void *a) 908 { 909 Devlogfs *d = a; 910 return d->reading; 911 } 912 913 static int 914 writeok(void *a) 915 { 916 Devlogfs *d = a; 917 return !d->reading; 918 } 919 920 static long 921 lfsrvread(Devlogfs *d, void *buf, long n) 922 { 923 qlock(&d->rlock); 924 if(waserror()){ 925 qunlock(&d->rlock); 926 nexterror(); 927 } 928 if (d->state == Hungup) 929 error(Ehungup); 930 Sleep(&d->readrendez, readok, d); 931 if (n > d->readcount) 932 n = d->readcount; 933 memmove(buf, d->readp, n); 934 d->readp += n; 935 d->readcount -= n; 936 if (d->readcount == 0) { 937 d->reading = 0; 938 Wakeup(&d->writerendez); 939 } 940 poperror(); 941 qunlock(&d->rlock); 942 return n; 943 } 944 945 static void 946 reply(Devlogfs *d) 947 { 948 d->readp = d->readbuf; 949 d->readcount = convS2M(&d->out, d->readp, d->readbufsize); 950 //print("reply is %d bytes\n", d->readcount); 951 if (d->readcount == 0) 952 panic("logfs: reply: did not fit\n"); 953 d->reading = 1; 954 Wakeup(&d->readrendez); 955 } 956 957 static void 958 rerror(Devlogfs *d, char *ename) 959 { 960 d->out.type = Rerror; 961 d->out.ename = ename; 962 reply(d); 963 } 964 965 static struct { 966 QLock qlock; 967 int (*read)(void *magic, Devlogfs *d, int line, char *buf, int buflen); 968 void *magic; 969 Devlogfs *d; 970 int line; 971 } dump; 972 973 static void * 974 extentdumpinit(Devlogfs *d, int argc, char **argv) 975 { 976 int *p; 977 ulong path; 978 u32int flashaddr, length; 979 long block; 980 int page, offset; 981 982 if (argc != 1) 983 error(Ebadarg); 984 path = strtoul(argv[0], 0, 0); 985 errorany(logfsserverreadpathextent(d->server, path, 0, &flashaddr, &length, &block, &page, &offset)); 986 p = emalloc(sizeof(ulong)); 987 *p = path; 988 return p; 989 } 990 991 static int 992 extentdumpread(void *magic, Devlogfs *d, int line, char *buf, int buflen) 993 { 994 ulong *p = magic; 995 u32int flashaddr, length; 996 long block; 997 int page, offset; 998 USED(d); 999 errorany(logfsserverreadpathextent(d->server, *p, line, &flashaddr, &length, &block, &page, &offset)); 1000 if (length == 0) 1001 return 0; 1002 return snprint(buf, buflen, "%.8ux %ud %ld %d %d\n", flashaddr, length, block, page, offset); 1003 } 1004 1005 static void 1006 devlogfsdumpinit(Devlogfs *d, 1007 void *(*init)(Devlogfs *d, int argc, char **argv), 1008 int (*read)(void *magic, Devlogfs *d, int line, char *buf, int buflen), int argc, char **argv) 1009 { 1010 qlock(&dump.qlock); 1011 if (waserror()) { 1012 qunlock(&dump.qlock); 1013 nexterror(); 1014 } 1015 if (d) { 1016 if (d->state < NeedVersion) 1017 error("not mounted"); 1018 qlock(&d->qlock); 1019 if (waserror()) { 1020 qunlock(&d->qlock); 1021 nexterror(); 1022 } 1023 } 1024 if (dump.magic) { 1025 logfsfreemem(dump.magic); 1026 dump.magic = nil; 1027 } 1028 dump.d = d; 1029 dump.magic = (*init)(d, argc, argv); 1030 dump.read = read; 1031 dump.line = 0; 1032 if (d) { 1033 poperror(); 1034 qunlock(&d->qlock); 1035 } 1036 poperror(); 1037 qunlock(&dump.qlock); 1038 } 1039 1040 static long 1041 devlogfsdumpread(char *buf, int buflen) 1042 { 1043 char *tmp = nil; 1044 long n; 1045 qlock(&dump.qlock); 1046 if (waserror()) { 1047 logfsfreemem(tmp); 1048 qunlock(&dump.qlock); 1049 nexterror(); 1050 } 1051 if (dump.magic == nil) 1052 error(Eio); 1053 tmp = emalloc(READSTR); 1054 if (dump.d) { 1055 if (dump.d->state < NeedVersion) 1056 error("not mounted"); 1057 qlock(&dump.d->qlock); 1058 if (waserror()) { 1059 qunlock(&dump.d->qlock); 1060 nexterror(); 1061 } 1062 } 1063 n = (*dump.read)(dump.magic, dump.d, dump.line, tmp, READSTR); 1064 if (n) { 1065 dump.line++; 1066 n = readstr(0, buf, buflen, tmp); 1067 } 1068 if (dump.d) { 1069 poperror(); 1070 qunlock(&dump.d->qlock); 1071 } 1072 logfsfreemem(tmp); 1073 poperror(); 1074 qunlock(&dump.qlock); 1075 return n; 1076 } 1077 1078 static void 1079 devlogfsserverlogsweep(Devlogfs *d, int justone) 1080 { 1081 int didsomething; 1082 if (d->state < NeedVersion) 1083 error("not mounted"); 1084 qlock(&d->qlock); 1085 if (waserror()) { 1086 qunlock(&d->qlock); 1087 nexterror(); 1088 } 1089 errorany(logfsserverlogsweep(d->server, justone, &didsomething)); 1090 poperror(); 1091 qunlock(&d->qlock); 1092 } 1093 1094 static void 1095 devlogfsserversync(Devlogfs *d) 1096 { 1097 if (d->state < NeedVersion) 1098 return; 1099 qlock(&d->qlock); 1100 if (waserror()) { 1101 qunlock(&d->qlock); 1102 nexterror(); 1103 } 1104 errorany(logfsserverflush(d->server)); 1105 poperror(); 1106 qunlock(&d->qlock); 1107 } 1108 1109 static void 1110 lfssrvwrite(Devlogfs *d, void *buf, long n) 1111 { 1112 volatile int locked = 0; 1113 1114 qlock(&d->wlock); 1115 if(waserror()){ 1116 qunlock(&d->wlock); 1117 nexterror(); 1118 } 1119 if (d->state == Hungup) 1120 error(Ehungup); 1121 Sleep(&d->writerendez, writeok, d); 1122 if (convM2S(buf, n, &d->in) != n) { 1123 /* 1124 * someone is writing drivel; have nothing to do with them anymore 1125 * most common cause; trying to mount authenticated 1126 */ 1127 d->state = Hungup; 1128 error(Ehungup); 1129 } 1130 d->out.tag = d->in.tag; 1131 d->out.fid = d->in.fid; 1132 d->out.type = d->in.type + 1; 1133 if (waserror()) { 1134 if (locked) 1135 qunlock(&d->qlock); 1136 rerror(d, up->env->errstr); 1137 goto Replied; 1138 } 1139 if (d->in.type != Tversion && d->in.type != Tattach) { 1140 if (d->state != Attached) 1141 error("must be attached"); 1142 qlock(&d->qlock); 1143 locked = 1; 1144 } 1145 switch (d->in.type) { 1146 case Tauth: 1147 error("no authentication needed"); 1148 case Tversion: { 1149 char *rversion; 1150 if (d->state != NeedVersion) 1151 error("unexpected Tversion"); 1152 if (d->in.tag != NOTAG) 1153 error("protocol botch"); 1154 /* 1155 * check the version string 1156 */ 1157 if (strcmp(d->in.version, devlogfs9pversion) != 0) 1158 rversion = "unknown"; 1159 else 1160 rversion = devlogfs9pversion; 1161 /* 1162 * allocate the reply buffer 1163 */ 1164 d->readbufsize = d->in.msize; 1165 if (d->readbufsize > MAXMSIZE) 1166 d->readbufsize = MAXMSIZE; 1167 d->readbuf = emalloc(d->readbufsize); 1168 /* 1169 * compose the Rversion 1170 */ 1171 d->out.msize = d->readbufsize; 1172 d->out.version = rversion; 1173 d->state = NeedAttach; 1174 break; 1175 } 1176 case Tattach: 1177 if (d->state != NeedAttach) 1178 error("unexpected attach"); 1179 if (d->in.afid != NOFID) 1180 error("unexpected afid"); 1181 errorany(logfsserverattach(d->server, d->in.fid, d->in.uname, &d->out.qid)); 1182 d->state = Attached; 1183 break; 1184 case Tclunk: 1185 errorany(logfsserverclunk(d->server, d->in.fid)); 1186 break; 1187 case Tcreate: 1188 errorany(logfsservercreate(d->server, d->in.fid, d->in.name, d->in.perm, d->in.mode, &d->out.qid)); 1189 d->out.iounit = d->readbufsize - 11; 1190 break; 1191 case Tflush: 1192 break; 1193 case Topen: 1194 errorany(logfsserveropen(d->server, d->in.fid, d->in.mode, &d->out.qid)); 1195 d->out.iounit = d->readbufsize - 11; 1196 break; 1197 case Tread: 1198 d->out.data = (char *)d->readbuf + 11; 1199 /* TODO - avoid memmove */ 1200 errorany(logfsserverread(d->server, d->in.fid, d->in.offset, d->in.count, (uchar *)d->out.data, 1201 d->readbufsize - 11, &d->out.count)); 1202 break; 1203 case Tremove: 1204 errorany(logfsserverremove(d->server, d->in.fid)); 1205 break; 1206 case Tstat: 1207 d->out.stat = d->readbuf + 9; 1208 /* TODO - avoid memmove */ 1209 errorany(logfsserverstat(d->server, d->in.fid, d->out.stat, d->readbufsize - 9, &d->out.nstat)); 1210 // print("nstat %d\n", d->out.nstat); 1211 break; 1212 case Twalk: 1213 errorany(logfsserverwalk(d->server, d->in.fid, d->in.newfid, 1214 d->in.nwname, d->in.wname, &d->out.nwqid, d->out.wqid)); 1215 break; 1216 case Twrite: 1217 errorany(logfsserverwrite(d->server, d->in.fid, d->in.offset, d->in.count, (uchar *)d->in.data, 1218 &d->out.count)); 1219 break; 1220 case Twstat: 1221 errorany(logfsserverwstat(d->server, d->in.fid, d->in.stat, d->in.nstat)); 1222 break; 1223 default: 1224 print("lfssrvwrite: msg %d unimplemented\n", d->in.type); 1225 error("unimplemented"); 1226 } 1227 poperror(); 1228 if (locked) 1229 qunlock(&d->qlock); 1230 reply(d); 1231 Replied: 1232 poperror(); 1233 qunlock(&d->wlock); 1234 } 1235 1236 static long 1237 devlogfsread(Chan *c, void *buf, long n, vlong off) 1238 { 1239 int instance, qid, qt; 1240 1241 SPLITPATH(c->qid.path, c->qid.type, instance, qid, qt); 1242 USED(instance); 1243 #ifdef CALLTRACE 1244 print("devlogfsread(c = 0x%.8lux, buf = 0x%.8lux, n = %ld, instance = %d, qid = %d, qt = %d) - start\n", 1245 (ulong)c, (ulong)buf, n, instance, qid, qt); 1246 #endif 1247 if(qt & QTDIR) { 1248 #ifdef CALLTRACE 1249 print("devlogfsread(c = 0x%.8lux, buf = 0x%.8lux, n = %ld, instance = %d, qid = %d, qt = %d) - calling devdirread\n", 1250 (ulong)c, (ulong)buf, n, instance, qid, qt); 1251 #endif 1252 return devdirread(c, buf, n, 0, 0, devlogfsgen); 1253 } 1254 1255 if(DATAQID(qid, qt)) { 1256 if (qid == Qfsboot) { 1257 Devlogfs *l = c->aux; 1258 qlock(&l->bootqlock); 1259 if (waserror()) { 1260 qunlock(&l->bootqlock); 1261 nexterror(); 1262 } 1263 smartio((SMARTIOFN *)logfsbootio, l->lb, buf, n, off, logfsbootgetiosize(l->lb), 0); 1264 poperror(); 1265 qunlock(&l->bootqlock); 1266 return n; 1267 } 1268 else if (qid == Qfs) { 1269 Devlogfs *d = c->aux; 1270 return lfsrvread(d, buf, n); 1271 } 1272 error(Eio); 1273 } 1274 1275 if (qid == Qusers) { 1276 long nr; 1277 errorany(logfsisusersread(is, buf, n, (ulong)off, &nr)); 1278 return nr; 1279 } 1280 else if (qid == Qdump) 1281 return devlogfsdumpread(buf, n); 1282 1283 if (qid != Qctl) 1284 error(Egreg); 1285 1286 return 0; 1287 } 1288 1289 enum { 1290 CMconfig, 1291 CMformat, 1292 CMopen, 1293 CMsweep, 1294 CMtrace, 1295 CMunconfig, 1296 CMextent, 1297 CMsweepone, 1298 CMtest, 1299 CMleakaudit, 1300 CMsync 1301 }; 1302 1303 static Cmdtab fscmds[] = { 1304 {CMconfig, "config", 2}, 1305 {CMformat, "format", 2}, 1306 {CMopen, "open", 0}, 1307 {CMsweep, "sweep", 1}, 1308 {CMsweepone, "sweepone", 1}, 1309 {CMtrace, "trace", 0}, 1310 {CMunconfig, "unconfig", 1}, 1311 {CMextent, "extent", 0}, 1312 {CMtest, "test", 0}, 1313 {CMleakaudit, "leakaudit", 1}, 1314 {CMsync, "sync", 1}, 1315 }; 1316 1317 static long 1318 devlogfswrite(Chan *c, void *buf, long n, vlong off) 1319 { 1320 int instance, qid, qt, i; 1321 Cmdbuf *cmd; 1322 Cmdtab *ct; 1323 1324 if(n <= 0) 1325 return 0; 1326 SPLITPATH(c->qid.path, c->qid.type, instance, qid, qt); 1327 #ifdef CALLTRACE 1328 print("devlogfswrite(c = 0x%.8lux, buf = 0x%.8lux, n = %ld, instance = %d, qid = %d, qt = %d) - start\n", 1329 (ulong)c, (ulong)buf, n, instance, qid, qt); 1330 #endif 1331 USED(instance); 1332 if(DATAQID(qid, qt)){ 1333 if (qid == Qfsboot) { 1334 Devlogfs *l = c->aux; 1335 qlock(&l->bootqlock); 1336 if (waserror()) { 1337 qunlock(&l->bootqlock); 1338 nexterror(); 1339 } 1340 smartio((SMARTIOFN *)logfsbootio, l->lb, buf, n, off, logfsbootgetiosize(l->lb), 1); 1341 poperror(); 1342 qunlock(&l->bootqlock); 1343 return n; 1344 } 1345 else if (qid == Qfs) { 1346 Devlogfs *d = c->aux; 1347 lfssrvwrite(d, buf, n); 1348 return n; 1349 } 1350 error(Eio); 1351 } 1352 else if (qid == Qctl) { 1353 Devlogfs *l = nil; 1354 int a; 1355 1356 cmd = parsecmd(buf, n); 1357 if(waserror()){ 1358 free(cmd); 1359 nexterror(); 1360 } 1361 i = cmd->nf; 1362 if(0){print("i=%d", i); for(i=0; i<cmd->nf; i++)print(" %q", cmd->f[i]); print("\n");} 1363 if (i <= 0) 1364 error(Ebadarg); 1365 if (i == 3 && strcmp(cmd->f[0], "uname") == 0) { 1366 switch (cmd->f[2][0]) { 1367 default: 1368 errorany(logfsisgroupcreate(is, cmd->f[1], cmd->f[2])); 1369 break; 1370 case ':': 1371 errorany(logfsisgroupcreate(is, cmd->f[1], cmd->f[2] + 1)); 1372 break; 1373 case '%': 1374 errorany(logfsisgrouprename(is, cmd->f[1], cmd->f[2] + 1)); 1375 break; 1376 case '=': 1377 errorany(logfsisgroupsetleader(is, cmd->f[1], cmd->f[2] + 1)); 1378 break; 1379 case '+': 1380 errorany(logfsisgroupaddmember(is, cmd->f[1], cmd->f[2] + 1)); 1381 break; 1382 case '-': 1383 errorany(logfsisgroupremovemember(is, cmd->f[1], cmd->f[2] + 1)); 1384 break; 1385 } 1386 i = 0; 1387 } 1388 if (i == 4 && strcmp(cmd->f[0], "fsys") == 0 && strcmp(cmd->f[2], "config") == 0) { 1389 l = devlogfsconfig(cmd->f[1], cmd->f[3]); 1390 i = 0; 1391 } 1392 else if (i >= 2 && strcmp(cmd->f[0], "fsys") == 0) { 1393 l = devlogfssetdefname(cmd->f[1]); 1394 if (l == nil) 1395 errorf("file system %q not configured", cmd->f[1]); 1396 i -= 2; 1397 cmd->f += 2; 1398 cmd->nf = i; 1399 } 1400 if (i != 0) { 1401 ct = lookupcmd(cmd, fscmds, nelem(fscmds)); 1402 if (l == nil) 1403 l = devlogfssetdefname(nil); 1404 if(l == nil && ct->index != CMleakaudit) 1405 error("file system not configured"); 1406 switch(ct->index){ 1407 case CMopen: 1408 for (a = 1; a < i; a++) 1409 if (cmd->f[a][0] == '-') 1410 switch (cmd->f[a][1]) { 1411 case 'P': 1412 l->openflags |= LogfsOpenFlagNoPerm; 1413 break; 1414 case 'W': 1415 l->openflags |= LogfsOpenFlagWstatAllow; 1416 break; 1417 default: 1418 error(Ebadarg); 1419 } 1420 devlogfsllopen(l); 1421 break; 1422 case CMformat: 1423 devlogfsllformat(l, strtol(cmd->f[1], nil, 0)); 1424 break; 1425 case CMsweep: 1426 devlogfsserverlogsweep(l, 0); 1427 break; 1428 case CMsweepone: 1429 devlogfsserverlogsweep(l, 1); 1430 break; 1431 case CMtrace: 1432 l->logfstrace = i > 1 ? strtol(cmd->f[1], nil, 0) : 0; 1433 if (l->server) 1434 logfsservertrace(l->server, l->logfstrace); 1435 if (l->lb) 1436 logfsboottrace(l->lb, l->logfstrace); 1437 break; 1438 case CMunconfig: 1439 if (l->ref.ref > 0) 1440 error(Einuse); 1441 devlogfsunconfig(l); 1442 break; 1443 case CMextent: 1444 if(i < 2) 1445 error(Ebadarg); 1446 devlogfsdumpinit(l, extentdumpinit, extentdumpread, i - 1, cmd->f + 1); 1447 break; 1448 case CMtest: 1449 if(i < 2) 1450 error(Ebadarg); 1451 errorany(logfsservertestcmd(l->server, i - 1, cmd->f + 1)); 1452 break; 1453 case CMleakaudit: 1454 #ifdef LEAKHUNT 1455 leakaudit(); 1456 #endif 1457 break; 1458 case CMsync: 1459 devlogfsserversync(l); 1460 break; 1461 default: 1462 error(Ebadarg); 1463 } 1464 } 1465 poperror(); 1466 free(cmd); 1467 return n; 1468 } 1469 error(Egreg); 1470 return 0; /* not reached */ 1471 } 1472 1473 static void 1474 devlogfsfree(Devlogfs *devlogfs) 1475 { 1476 if (devlogfs != nil) { 1477 int i; 1478 logfsfreemem(devlogfs->device); 1479 logfsfreemem(devlogfs->name); 1480 for (i = 0; i < Qend - Qfs; i++) 1481 logfsfreemem(devlogfs->filename[i]); 1482 cclose(devlogfs->flash); 1483 cclose(devlogfs->flashctl); 1484 qlock(&devlogfs->qlock); 1485 logfsserverfree(&devlogfs->server); 1486 logfsbootfree(devlogfs->lb); 1487 if (devlogfs->ll) 1488 (*devlogfs->ll->free)(devlogfs->ll); 1489 logfsfreemem(devlogfs->readbuf); 1490 qunlock(&devlogfs->qlock); 1491 logfsfreemem(devlogfs); 1492 } 1493 } 1494 1495 #ifdef EMU 1496 ulong 1497 logfsnow(void) 1498 { 1499 extern vlong timeoffset; 1500 return (timeoffset + osusectime()) / 1000000; 1501 } 1502 #endif 1503 1504 Dev logfsdevtab = { 1505 0x29f, 1506 // L'ʟ', 1507 "logfs", 1508 1509 #ifndef EMU 1510 devreset, 1511 #endif 1512 devinit, 1513 #ifndef EMU 1514 devshutdown, 1515 #endif 1516 devlogfsattach, 1517 devlogfswalk, 1518 devlogfsstat, 1519 devlogfsopen, 1520 devcreate, 1521 devlogfsclose, 1522 devlogfsread, 1523 devbread, 1524 devlogfswrite, 1525 devbwrite, 1526 devremove, 1527 devwstat, 1528 }; 1529