#ifndef EMU#include "u.h"#include "../port/lib.h"#include "../port/error.h"#else#include "error.h"#endif#include <dat.h>#include <fns.h>#include <kernel.h>#include <logfs.h>#include <nandfs.h> #ifndef EMU#define Sleep sleep#define Wakeup wakeup#endif #ifndef offsetof#define offsetof(T,X) ((ulong)&(((T*)0)->X))#endif typedef struct Devlogfs Devlogfs;typedef struct DevlogfsSession DevlogfsSession; //#define CALLTRACE enum { DEVLOGFSDEBUG = 0, DEVLOGFSIODEBUG = 0, DEVLOGFSBAD = 1,}; enum { Qdir, Qctl, Qusers, Qdump, Qfs, Qfsboot, Qend,}; typedef enum DevlogfsServerState { Closed, BootOpen, NeedVersion, NeedAttach, Attached, Hungup } DevlogfsServerState; struct Devlogfs { QLock qlock; Ref ref; int instance; int trace; /* (debugging) trace of read/write actions */ int nand; char *name; char *device; char *filename[Qend - Qfs]; LogfsLowLevel *ll; Chan *flash, *flashctl; QLock bootqlock; int logfstrace; LogfsBoot *lb; /* stuff for server */ ulong openflags; Fcall in; Fcall out; int reading; DevlogfsServerState state; Rendez readrendez; Rendez writerendez; uint readcount; ulong readbufsize; uchar *readbuf; uchar *readp; LogfsServer *server; Devlogfs *next;}; #define MAXMSIZE 8192 static struct { RWlock rwlock; /* rlock when walking, wlock when changing */ QLock configqlock; /* serialises addition of new configurations */ Devlogfs *head; char *defname;} devlogfslist; static LogfsIdentityStore *is; #ifndef EMUchar Eunknown[] = "unknown user or group id";#endif static void devlogfsfree(Devlogfs*); #define SPLITPATH(path, qtype, instance, qid, qt) { instance = path >> 4; qid = path & 0xf; qt = qtype & QTDIR; }#define DATAQID(q, qt) (!(qt) && (q) >= Qfs && (q) < Qend)#define MKPATH(instance, qid) ((instance << 4) | qid) #define PREFIX "logfs" static char *devlogfsprefix = PREFIX;static char *devlogfsctlname = PREFIX "ctl";static char *devlogfsusersname = PREFIX "users";static char *devlogfsdumpname = PREFIX "dump";static char *devlogfsbootsuffix = "boot";static char *devlogfs9pversion = "9P2000"; enum { Toshiba = 0x98, Samsung = 0xec,}; static struct { uchar manufacturer; uchar device;} nandtab[] = { { 0, 0xe6 }, { 0, 0xea }, { 0, 0xe3 }, { 0, 0xe5 }, { 0, 0x73 }, { 0, 0x75 }, { 0, 0x76 },}; static voiderrorany(char *errmsg){ if (errmsg) error(errmsg);} static void *emalloc(ulong size){ void *p; p = logfsrealloc(nil, size); if (p == nil) error(Enomem); return p;} static char *estrdup(char *q){ void *p; if (q == nil) return nil; p = logfsrealloc(nil, strlen(q) + 1); if (p == nil) error(Enomem); return strcpy(p, q);} static char *estrconcat(char *a, ...){ va_list l; char *p, *r; int t; t = strlen(a); va_start(l, a); while ((p = va_arg(l, char *)) != nil) t += strlen(p); r = logfsrealloc(nil, t + 1); if (r == nil) error(Enomem); strcpy(r, a); va_start(l, a); while ((p = va_arg(l, char *)) != nil) strcat(r, p); va_end(l); return r;} static intgen(Chan *c, int i, Dir *dp, int lockit){ Devlogfs *l; long size; Qid qid; qid.vers = 0; qid.type = 0; if (i + Qctl < Qfs) { switch (i + Qctl) { case Qctl: qid.path = Qctl; devdir(c, qid, devlogfsctlname, 0, eve, 0666, dp); return 1; case Qusers: qid.path = Qusers; devdir(c, qid, devlogfsusersname, 0, eve, 0444, dp); return 1; case Qdump: qid.path = Qdump; devdir(c, qid, devlogfsdumpname, 0, eve, 0444, dp); return 1; } } i -= Qfs - Qctl; if (lockit) rlock(&devlogfslist.rwlock); if (waserror()) { if (lockit) runlock(&devlogfslist.rwlock); nexterror(); } for (l = devlogfslist.head; l; l = l->next) { if (i < Qend - Qfs) break; i -= Qend - Qfs; } if (l == nil) { poperror(); if (lockit) runlock(&devlogfslist.rwlock); return -1; } switch (Qfs + i) { case Qfsboot: size = l->lb ? logfsbootgetsize(l->lb) : 0; break; default: size = 0; break; } /* perhaps the user id should come from the underlying file */ qid.path = MKPATH(l->instance, Qfs + i); devdir(c, qid, l->filename[i], size, eve, 0666, dp); poperror(); if (lockit) runlock(&devlogfslist.rwlock); return 1;} static intdevlogfsgen(Chan *c, char *n, Dirtab *tab, int ntab, int i, Dir *dp){ USED(n); USED(tab); USED(ntab); return gen(c, i, dp, 1);} static intdevlogfsgennolock(Chan *c, char *n, Dirtab *tab, int ntab, int i, Dir *dp){ USED(n); USED(tab); USED(ntab); return gen(c, i, dp, 0);} /* called under lock */static Devlogfs *devlogfsfind(int instance){ Devlogfs *l; for (l = devlogfslist.head; l; l = l->next) if (l->instance == instance) break; return l;} static Devlogfs *devlogfsget(int instance){ Devlogfs *l; rlock(&devlogfslist.rwlock); for (l = devlogfslist.head; l; l = l->next) if (l->instance == instance) break; if (l) incref(&l->ref); runlock(&devlogfslist.rwlock); return l;} static Devlogfs *devlogfsfindbyname(char *name){ Devlogfs *l; rlock(&devlogfslist.rwlock); for (l = devlogfslist.head; l; l = l->next) if (strcmp(l->name, name) == 0) break; runlock(&devlogfslist.rwlock); return l;} static Devlogfs *devlogfssetdefname(char *name){ Devlogfs *l; char *searchname; wlock(&devlogfslist.rwlock); if (waserror()) { wunlock(&devlogfslist.rwlock); nexterror(); } if (name == nil) searchname = devlogfslist.defname; else searchname = name; for (l = devlogfslist.head; l; l = l->next) if (strcmp(l->name, searchname) == 0) break; if (l == nil) { logfsfreemem(devlogfslist.defname); devlogfslist.defname = nil; } else if (name) { if (devlogfslist.defname) { logfsfreemem(devlogfslist.defname); devlogfslist.defname = nil; } devlogfslist.defname = estrdup(name); } poperror(); wunlock(&devlogfslist.rwlock); return l;} static Chan *devlogfskopen(char *name, char *suffix, int mode){ Chan *c; char *fn; int fd; fn = estrconcat(name, suffix, 0); fd = kopen(fn, mode); logfsfreemem(fn); if (fd < 0) error(up->env->errstr); c = fdtochan(up->env->fgrp, fd, mode, 0, 1); kclose(fd); return c;} static char *xread(void *a, void *buf, long nbytes, ulong offset){ Devlogfs *l = a; long rv; if (DEVLOGFSIODEBUG || l->trace) print("devlogfs: %s: read(0x%lux, %ld)\n", l->device, offset, nbytes); l->flash->offset = offset; rv = kchanio(l->flash, buf, nbytes, OREAD); if (rv < 0) { print("devlogfs: %s: flash read error: %s\n", l->device, up->env->errstr); return up->env->errstr; } if (rv != nbytes) { print("devlogfs: %s: short flash read: offset %lud, %ld not %ld\n", l->device, offset, rv, nbytes); return "short read"; } return nil;} static char *xwrite(void *a, void *buf, long nbytes, ulong offset){ Devlogfs *l = a; long rv; if (DEVLOGFSIODEBUG || l->trace) print("devlogfs: %s: write(0x%lux, %ld)\n", l->device, offset, nbytes); l->flash->offset = offset; rv = kchanio(l->flash, buf, nbytes, OWRITE); if (rv < 0) { print("devlogfs: %s: flash write error: %s\n", l->device, up->env->errstr); return up->env->errstr; } if (rv != nbytes) { print("devlogfs: %s: short flash write: offset %lud, %ld not %ld\n", l->device, offset, rv, nbytes); return "short write"; } return nil;} static char *xerase(void *a, long address){ Devlogfs *l = a; char cmd[40]; if (DEVLOGFSIODEBUG || l->trace) print("devlogfs: %s: erase(0x%lux)\n", l->device, address); snprint(cmd, sizeof(cmd), "erase 0x%8.8lux", address); if (kchanio(l->flashctl, cmd, strlen(cmd), OWRITE) <= 0) { print("devlogfs: %s: flash erase error: %s\n", l->device, up->env->errstr); return up->env->errstr; } return nil;} static char *xsync(void *a){ Devlogfs *l = a; uchar statbuf[STATFIXLEN]; if (DEVLOGFSIODEBUG || l->trace) print("devlogfs: %s: sync()\n", l->device); memset(statbuf, 0xff, sizeof(statbuf)); memset(statbuf + STATFIXLEN - 8, 0x00, 8); PBIT16(statbuf, sizeof(statbuf) - BIT16SZ); if (kwstat(l->device, statbuf, sizeof(statbuf)) < 0) return up->env->errstr; return nil;} //#define LEAKHUNT#ifdef LEAKHUNT#define MAXLIVE 2000typedef struct Live { void *p; int freed; ulong callerpc;} Live; static Live livemem[MAXLIVE]; static voidleakalloc(void *p, ulong callerpc){ int x; int use = -1; for (x = 0; x < MAXLIVE; x++) { if (livemem[x].p == p) { if (!livemem[x].freed) print("leakalloc: unexpected realloc of 0x%.8lux from 0x%.8lux\n", p, callerpc);// else// print("leakalloc: reusing address 0x%.8lux from 0x%.8lux\n", p, callerpc); livemem[x].freed = 0; livemem[x].callerpc = callerpc; return; } else if (use < 0 && livemem[x].p == 0) use = x; } if (use < 0) panic("leakalloc: too many live entries"); livemem[use].p = p; livemem[use].freed = 0; livemem[use].callerpc = callerpc;} static voidleakaudit(void){ int x; for (x = 0; x < MAXLIVE; x++) { if (livemem[x].p && !livemem[x].freed) print("leakaudit: 0x%.8lux from 0x%.8lux\n", livemem[x].p, livemem[x].callerpc); }} static voidleakfree(void *p, ulong callerpc){ int x; if (p == nil) return; for (x = 0; x < MAXLIVE; x++) { if (livemem[x].p == p) { if (livemem[x].freed) print("leakfree: double free of 0x%.8lux from 0x%.8lux, originally by 0x%.8lux\n", p, callerpc, livemem[x].callerpc); livemem[x].freed = 1; livemem[x].callerpc = callerpc; return; } } print("leakfree: free of unalloced address 0x%.8lux from 0x%.8lux\n", p, callerpc); leakaudit();} static voidleakrealloc(void *newp, void *oldp, ulong callerpc){ leakfree(oldp, callerpc); leakalloc(newp, callerpc);}Lines 1–500 of 1522. Load more
#ifndef EMU #include "u.h" #include "../port/lib.h" #include "../port/error.h" #else #include "error.h" #endif #include <dat.h> #include <fns.h> #include <kernel.h> #include <logfs.h> #include <nandfs.h> #ifndef EMU #define Sleep sleep #define Wakeup wakeup #endif #ifndef offsetof #define offsetof(T,X) ((ulong)&(((T*)0)->X)) #endif typedef struct Devlogfs Devlogfs; typedef struct DevlogfsSession DevlogfsSession; //#define CALLTRACE enum { DEVLOGFSDEBUG = 0, DEVLOGFSIODEBUG = 0, DEVLOGFSBAD = 1, }; enum { Qdir, Qctl, Qusers, Qdump, Qfs, Qfsboot, Qend, }; typedef enum DevlogfsServerState { Closed, BootOpen, NeedVersion, NeedAttach, Attached, Hungup } DevlogfsServerState; struct Devlogfs { QLock qlock; Ref ref; int instance; int trace; /* (debugging) trace of read/write actions */ int nand; char *name; char *device; char *filename[Qend - Qfs]; LogfsLowLevel *ll; Chan *flash, *flashctl; QLock bootqlock; int logfstrace; LogfsBoot *lb; /* stuff for server */ ulong openflags; Fcall in; Fcall out; int reading; DevlogfsServerState state; Rendez readrendez; Rendez writerendez; uint readcount; ulong readbufsize; uchar *readbuf; uchar *readp; LogfsServer *server; Devlogfs *next; }; #define MAXMSIZE 8192 static struct { RWlock rwlock; /* rlock when walking, wlock when changing */ QLock configqlock; /* serialises addition of new configurations */ Devlogfs *head; char *defname; } devlogfslist; static LogfsIdentityStore *is; #ifndef EMU char Eunknown[] = "unknown user or group id"; #endif static void devlogfsfree(Devlogfs*); #define SPLITPATH(path, qtype, instance, qid, qt) { instance = path >> 4; qid = path & 0xf; qt = qtype & QTDIR; } #define DATAQID(q, qt) (!(qt) && (q) >= Qfs && (q) < Qend) #define MKPATH(instance, qid) ((instance << 4) | qid) #define PREFIX "logfs" static char *devlogfsprefix = PREFIX; static char *devlogfsctlname = PREFIX "ctl"; static char *devlogfsusersname = PREFIX "users"; static char *devlogfsdumpname = PREFIX "dump"; static char *devlogfsbootsuffix = "boot"; static char *devlogfs9pversion = "9P2000"; enum { Toshiba = 0x98, Samsung = 0xec, }; static struct { uchar manufacturer; uchar device; } nandtab[] = { { 0, 0xe6 }, { 0, 0xea }, { 0, 0xe3 }, { 0, 0xe5 }, { 0, 0x73 }, { 0, 0x75 }, { 0, 0x76 }, }; static void errorany(char *errmsg) { if (errmsg) error(errmsg); } static void * emalloc(ulong size) { void *p; p = logfsrealloc(nil, size); if (p == nil) error(Enomem); return p; } static char * estrdup(char *q) { void *p; if (q == nil) return nil; p = logfsrealloc(nil, strlen(q) + 1); if (p == nil) error(Enomem); return strcpy(p, q); } static char * estrconcat(char *a, ...) { va_list l; char *p, *r; int t; t = strlen(a); va_start(l, a); while ((p = va_arg(l, char *)) != nil) t += strlen(p); r = logfsrealloc(nil, t + 1); if (r == nil) error(Enomem); strcpy(r, a); va_start(l, a); while ((p = va_arg(l, char *)) != nil) strcat(r, p); va_end(l); return r; } static int gen(Chan *c, int i, Dir *dp, int lockit) { Devlogfs *l; long size; Qid qid; qid.vers = 0; qid.type = 0; if (i + Qctl < Qfs) { switch (i + Qctl) { case Qctl: qid.path = Qctl; devdir(c, qid, devlogfsctlname, 0, eve, 0666, dp); return 1; case Qusers: qid.path = Qusers; devdir(c, qid, devlogfsusersname, 0, eve, 0444, dp); return 1; case Qdump: qid.path = Qdump; devdir(c, qid, devlogfsdumpname, 0, eve, 0444, dp); return 1; } } i -= Qfs - Qctl; if (lockit) rlock(&devlogfslist.rwlock); if (waserror()) { if (lockit) runlock(&devlogfslist.rwlock); nexterror(); } for (l = devlogfslist.head; l; l = l->next) { if (i < Qend - Qfs) break; i -= Qend - Qfs; } if (l == nil) { poperror(); if (lockit) runlock(&devlogfslist.rwlock); return -1; } switch (Qfs + i) { case Qfsboot: size = l->lb ? logfsbootgetsize(l->lb) : 0; break; default: size = 0; break; } /* perhaps the user id should come from the underlying file */ qid.path = MKPATH(l->instance, Qfs + i); devdir(c, qid, l->filename[i], size, eve, 0666, dp); poperror(); if (lockit) runlock(&devlogfslist.rwlock); return 1; } static int devlogfsgen(Chan *c, char *n, Dirtab *tab, int ntab, int i, Dir *dp) { USED(n); USED(tab); USED(ntab); return gen(c, i, dp, 1); } static int devlogfsgennolock(Chan *c, char *n, Dirtab *tab, int ntab, int i, Dir *dp) { USED(n); USED(tab); USED(ntab); return gen(c, i, dp, 0); } /* called under lock */ static Devlogfs * devlogfsfind(int instance) { Devlogfs *l; for (l = devlogfslist.head; l; l = l->next) if (l->instance == instance) break; return l; } static Devlogfs * devlogfsget(int instance) { Devlogfs *l; rlock(&devlogfslist.rwlock); for (l = devlogfslist.head; l; l = l->next) if (l->instance == instance) break; if (l) incref(&l->ref); runlock(&devlogfslist.rwlock); return l; } static Devlogfs * devlogfsfindbyname(char *name) { Devlogfs *l; rlock(&devlogfslist.rwlock); for (l = devlogfslist.head; l; l = l->next) if (strcmp(l->name, name) == 0) break; runlock(&devlogfslist.rwlock); return l; } static Devlogfs * devlogfssetdefname(char *name) { Devlogfs *l; char *searchname; wlock(&devlogfslist.rwlock); if (waserror()) { wunlock(&devlogfslist.rwlock); nexterror(); } if (name == nil) searchname = devlogfslist.defname; else searchname = name; for (l = devlogfslist.head; l; l = l->next) if (strcmp(l->name, searchname) == 0) break; if (l == nil) { logfsfreemem(devlogfslist.defname); devlogfslist.defname = nil; } else if (name) { if (devlogfslist.defname) { logfsfreemem(devlogfslist.defname); devlogfslist.defname = nil; } devlogfslist.defname = estrdup(name); } poperror(); wunlock(&devlogfslist.rwlock); return l; } static Chan * devlogfskopen(char *name, char *suffix, int mode) { Chan *c; char *fn; int fd; fn = estrconcat(name, suffix, 0); fd = kopen(fn, mode); logfsfreemem(fn); if (fd < 0) error(up->env->errstr); c = fdtochan(up->env->fgrp, fd, mode, 0, 1); kclose(fd); return c; } static char * xread(void *a, void *buf, long nbytes, ulong offset) { Devlogfs *l = a; long rv; if (DEVLOGFSIODEBUG || l->trace) print("devlogfs: %s: read(0x%lux, %ld)\n", l->device, offset, nbytes); l->flash->offset = offset; rv = kchanio(l->flash, buf, nbytes, OREAD); if (rv < 0) { print("devlogfs: %s: flash read error: %s\n", l->device, up->env->errstr); return up->env->errstr; } if (rv != nbytes) { print("devlogfs: %s: short flash read: offset %lud, %ld not %ld\n", l->device, offset, rv, nbytes); return "short read"; } return nil; } static char * xwrite(void *a, void *buf, long nbytes, ulong offset) { Devlogfs *l = a; long rv; if (DEVLOGFSIODEBUG || l->trace) print("devlogfs: %s: write(0x%lux, %ld)\n", l->device, offset, nbytes); l->flash->offset = offset; rv = kchanio(l->flash, buf, nbytes, OWRITE); if (rv < 0) { print("devlogfs: %s: flash write error: %s\n", l->device, up->env->errstr); return up->env->errstr; } if (rv != nbytes) { print("devlogfs: %s: short flash write: offset %lud, %ld not %ld\n", l->device, offset, rv, nbytes); return "short write"; } return nil; } static char * xerase(void *a, long address) { Devlogfs *l = a; char cmd[40]; if (DEVLOGFSIODEBUG || l->trace) print("devlogfs: %s: erase(0x%lux)\n", l->device, address); snprint(cmd, sizeof(cmd), "erase 0x%8.8lux", address); if (kchanio(l->flashctl, cmd, strlen(cmd), OWRITE) <= 0) { print("devlogfs: %s: flash erase error: %s\n", l->device, up->env->errstr); return up->env->errstr; } return nil; } static char * xsync(void *a) { Devlogfs *l = a; uchar statbuf[STATFIXLEN]; if (DEVLOGFSIODEBUG || l->trace) print("devlogfs: %s: sync()\n", l->device); memset(statbuf, 0xff, sizeof(statbuf)); memset(statbuf + STATFIXLEN - 8, 0x00, 8); PBIT16(statbuf, sizeof(statbuf) - BIT16SZ); if (kwstat(l->device, statbuf, sizeof(statbuf)) < 0) return up->env->errstr; return nil; } //#define LEAKHUNT #ifdef LEAKHUNT #define MAXLIVE 2000 typedef struct Live { void *p; int freed; ulong callerpc; } Live; static Live livemem[MAXLIVE]; static void leakalloc(void *p, ulong callerpc) { int x; int use = -1; for (x = 0; x < MAXLIVE; x++) { if (livemem[x].p == p) { if (!livemem[x].freed) print("leakalloc: unexpected realloc of 0x%.8lux from 0x%.8lux\n", p, callerpc); // else // print("leakalloc: reusing address 0x%.8lux from 0x%.8lux\n", p, callerpc); livemem[x].freed = 0; livemem[x].callerpc = callerpc; return; } else if (use < 0 && livemem[x].p == 0) use = x; } if (use < 0) panic("leakalloc: too many live entries"); livemem[use].p = p; livemem[use].freed = 0; livemem[use].callerpc = callerpc; } static void leakaudit(void) { int x; for (x = 0; x < MAXLIVE; x++) { if (livemem[x].p && !livemem[x].freed) print("leakaudit: 0x%.8lux from 0x%.8lux\n", livemem[x].p, livemem[x].callerpc); } } static void leakfree(void *p, ulong callerpc) { int x; if (p == nil) return; for (x = 0; x < MAXLIVE; x++) { if (livemem[x].p == p) { if (livemem[x].freed) print("leakfree: double free of 0x%.8lux from 0x%.8lux, originally by 0x%.8lux\n", p, callerpc, livemem[x].callerpc); livemem[x].freed = 1; livemem[x].callerpc = callerpc; return; } } print("leakfree: free of unalloced address 0x%.8lux from 0x%.8lux\n", p, callerpc); leakaudit(); } static void leakrealloc(void *newp, void *oldp, ulong callerpc) { leakfree(oldp, callerpc); leakalloc(newp, callerpc); }