Charles.Forsyth20060303a828770d19 years agoHistory
1522 lines · 31.4 KB · C
RawDownload
#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.