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
errorany(char * errmsg)125 errorany(char *errmsg)
126 {
127 if (errmsg)
128 error(errmsg);
129 }
130
131 static void *
emalloc(ulong size)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 *
estrdup(char * q)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 *
estrconcat(char * a,...)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
gen(Chan * c,int i,Dir * dp,int lockit)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
devlogfsgen(Chan * c,char * n,Dirtab * tab,int ntab,int i,Dir * dp)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
devlogfsgennolock(Chan * c,char * n,Dirtab * tab,int ntab,int i,Dir * dp)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 *
devlogfsfind(int instance)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 *
devlogfsget(int instance)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 *
devlogfsfindbyname(char * name)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 *
devlogfssetdefname(char * name)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 *
devlogfskopen(char * name,char * suffix,int mode)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 *
xread(void * a,void * buf,long nbytes,ulong offset)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 *
xwrite(void * a,void * buf,long nbytes,ulong offset)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 *
xerase(void * a,long address)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 *
xsync(void * a)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
leakalloc(void * p,ulong callerpc)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
leakaudit(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
leakfree(void * p,ulong callerpc)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
leakrealloc(void * newp,void * oldp,ulong callerpc)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
_realloc(void * p,ulong size,ulong callerpc)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 *
logfsrealloc(void * p,ulong size)548 logfsrealloc(void *p, ulong size)
549 {
550 return _realloc(p, size, getcallerpc(&p));
551 }
552
553 void *
nandfsrealloc(void * p,ulong size)554 nandfsrealloc(void *p, ulong size)
555 {
556 return _realloc(p, size, getcallerpc(&p));
557 }
558 #else
559 void *
nandfsrealloc(void * p,ulong size)560 nandfsrealloc(void *p, ulong size)
561 {
562 return logfsrealloc(p, size);
563 }
564 #endif
565
566 void
logfsfreemem(void * p)567 logfsfreemem(void *p)
568 {
569 #ifdef LEAKHUNT
570 leakfree(p, getcallerpc(&p));
571 #endif
572 free(p);
573 }
574
575 void
nandfsfreemem(void * p)576 nandfsfreemem(void *p)
577 {
578 #ifdef LEAKHUNT
579 leakfree(p, getcallerpc(&p));
580 #endif
581 free(p);
582 }
583
584 static Devlogfs *
devlogfsconfig(char * name,char * device)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
devlogfsunconfig(Devlogfs * devlogfs)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
devlogfsllopen(Devlogfs * l)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
devlogfsllformat(Devlogfs * l,long bootsize)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 *
devlogfsattach(char * spec)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*
devlogfswalk(Chan * c,Chan * nc,char ** name,int nname)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
devlogfsstat(Chan * c,uchar * dp,int n)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*
devlogfsopen(Chan * c,int omode)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
devlogfsclose(Chan * c)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
smartio(SMARTIOFN * io,void * magic,void * buf,long n,ulong offset,long blocksize,int write)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
readok(void * a)950 readok(void *a)
951 {
952 Devlogfs *d = a;
953 return d->reading;
954 }
955
956 static int
writeok(void * a)957 writeok(void *a)
958 {
959 Devlogfs *d = a;
960 return !d->reading;
961 }
962
963 long
devlogfsserverread(Devlogfs * d,void * buf,long n)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
reply(Devlogfs * d)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
rerror(Devlogfs * d,char * ename)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 *
extentdumpinit(Devlogfs * d,int argc,char ** argv)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
extentdumpread(void * magic,Devlogfs * d,int line,char * buf,int buflen)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
devlogfsdumpinit(Devlogfs * d,void * (* init)(Devlogfs * d,int argc,char ** argv),int (* read)(void * magic,Devlogfs * d,int line,char * buf,int buflen),int argc,char ** argv)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
devlogfsdumpread(char * buf,int buflen)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
devlogfsserverlogsweep(Devlogfs * d,int justone)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
devlogfsserverwrite(Devlogfs * d,void * buf,long n)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
devlogfsread(Chan * c,void * buf,long n,vlong off)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
devlogfswrite(Chan * c,void * buf,long n,vlong off)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
devlogfsfree(Devlogfs * devlogfs)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
logfsnow(void)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