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