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