Charles.Forsyth20060303a828770d19 years agoHistory
270 lines · 6.5 KB · C
RawDownload
#include "lib9.h"#include "logfs.h"#include "local.h"#include "fcall.h" voidlogfsflashaddr2spo(LogfsServer *server, u32int flashaddr, long *seq, int *page, int *offset){	LogfsLowLevel *ll = server->ll;	flashaddr &= ~LogAddr;	*offset = flashaddr & ((1 << ll->l2pagesize) - 1);	flashaddr >>= ll->l2pagesize;	*page = flashaddr & ((1 << ll->l2pagesperblock) - 1);	flashaddr >>= ll->l2pagesperblock;	*seq = flashaddr;} u32intlogfsspo2flashaddr(LogfsServer *server, long seq, int page, int offset){//print("logfsspo2flashaddr(%ld, %d, %d)\n", seq, page, offset);	return (((seq << server->ll->l2pagesperblock) + page) << server->ll->l2pagesize) + offset;} voidlogfsflashaddr2o(LogfsServer *server, u32int flashaddr, int *offset){	LogfsLowLevel *ll = server->ll;	flashaddr &= ~LogAddr;	*offset = flashaddr & ((1 << ll->l2pagesize) - 1);} char *logfslogsegmentnew(LogfsServer *server, int gen, LogSegment **segp){	LogSegment *seg;	seg = logfsrealloc(nil, sizeof(LogSegment) + (server->ll->blocks - 1) * sizeof(long));	if(seg == nil)		return Enomem;	seg->pagebuf = logfsrealloc(nil, 1 << server->ll->l2pagesize);	if(seg->pagebuf == nil) {		logfsfreemem(seg);		return Enomem;	}	seg->curpage = -1;	seg->curblockindex = -1;	seg->gen = gen;	*segp = seg;	return nil;} voidlogfslogsegmentfree(LogSegment **segp){	LogSegment *seg = *segp;	if(seg) {		logfsfreemem(seg->pagebuf);		logfsfreemem(seg);		*segp = nil;	}} char *logfslogsegmentflush(LogfsServer *server, int active){	LogSegment *seg;	seg = active ? server->activelog : server->sweptlog;	if(seg == nil)		return nil;	if(seg->curpage >= 0 && seg->nbytes) {		char *errmsg;		LogfsLowLevel *ll = server->ll;		int pagesize = 1 << ll->l2pagesize;//print("curblockindex %ld curpage %d nbytes %d\n", seg->curblockindex, seg->curpage, seg->nbytes);		if(seg->nbytes < pagesize)			seg->pagebuf[seg->nbytes++] = LogfsLogTend;		memset(seg->pagebuf + seg->nbytes, 0xff, pagesize - seg->nbytes);		for(;;) {			errmsg = (*ll->writepage)(ll, seg->pagebuf,				seg->blockmap[seg->curblockindex], seg->curpage);			if(errmsg == nil)				break;			if(strcmp(errmsg, Eio) != 0)				return errmsg;			errmsg = logfsserverreplacelogblock(server, seg, seg->curblockindex);			if(errmsg)				return errmsg;		}		seg->curpage++;		if(seg->curpage == (1 << ll->l2pagesperblock))			seg->curpage = -1;		seg->nbytes = 0;	}	return nil;} static char *logspace(LogfsServer *server, int active, int takearisk, int nbytes, uchar **where, u32int *flashaddr){	char *errmsg;	LogfsLowLevel *ll = server->ll;	int pagesize = 1 << ll->l2pagesize;	LogSegment *seg; 	if(nbytes > pagesize)		return logfselogmsgtoobig;retry:	seg = active ? server->activelog : server->sweptlog;	for(;;) {//print("curpage %d nbytes %d\n", seg->curpage, seg->nbytes);		if(seg->curpage >= 0) {			if(seg->nbytes + nbytes < pagesize)				break;			errmsg = logfslogsegmentflush(server, active);			if(errmsg)				return errmsg;		}		if(seg->curpage < 0) {			long block;			long path;			block = logfsfindfreeblock(ll,				active ? (takearisk ? AllocReasonLogExtend : AllocReasonDataExtend) : AllocReasonTransfer);			if(block < 0) {				if(active) {					int didsomething;					errmsg = logfsserverlogsweep(server, 0, &didsomething);					if(errmsg)						return errmsg;					if(didsomething)						goto retry;				}				return logfselogfull;			}			seg->blockmap[++seg->curblockindex] = block;			path = mklogpath(seg->curblockindex, seg->gen, 0);			(*ll->setblocktag)(ll, block, LogfsTlog);			(*ll->setblockpath)(ll, block, path);			seg->curpage = 0;#ifdef FUTURE			/* TODO - do we need one of these if the underlying system supports erase counting? */			seg->pagebuf[0] = LogfsLogTstart;			PBIT16(seg->pagebuf + 1, 8);			PBIT32(seg->pagebuf + 3, path);	/* TODO duplicate information */			PBIT32(seg->pagebuf + 7, 0);		/* TODO don't have this - discuss with forsyth */			seg->nbytes = 11;#else			seg->nbytes = 0;#endif		}	}	*where = seg->pagebuf + seg->nbytes;	if(flashaddr)		*flashaddr = logfsspo2flashaddr(server, seg->curblockindex, seg->curpage, seg->nbytes);	seg->nbytes += nbytes;	return nil;} static voidlogdirty(LogfsServer *server, int active){	if(active)		server->activelog->dirty = 1;	else		server->sweptlog->dirty = 1;} char *logfslogbytes(LogfsServer *server, int active, uchar *msg, uint size){	char *errmsg;	uchar *p; 	errmsg = logspace(server, active, 0, size, &p, nil);	if(errmsg)		return errmsg;	memcpy(p, msg, size);	logdirty(server, active);	return nil;} char *logfslog(LogfsServer *server, int active, LogMessage *s){	uint size = logfssizeS2M(s);	char *errmsg;	uchar *p;	int takearisk; 	if(server->trace > 1) {		print("%c<< ", active ? 'A' : 'S');		logfsdumpS(s);		print("\n");	}	if(active) {		switch(s->type) {		case LogfsLogTremove:		case LogfsLogTtrunc:			takearisk = 1;			break;		default:			takearisk = 0;		}	}	else		takearisk = 0;	errmsg = logspace(server, active, takearisk, size, &p, nil);	if(errmsg)		return errmsg;	if(logfsconvS2M(s, p, size) != size)		return "bad conversion";	logdirty(server, active);	return nil;} intlognicesizeforwrite(LogfsServer *server, int active, u32int count, int muidlen){	int rawspace;	LogSegment *seg;	if(count > LogDataLimit)		return 0;	seg = active ? server->activelog : server->sweptlog;	if(seg->curpage < 0)		return LogDataLimit;	rawspace = (1 << server->ll->l2pagesize) - seg->nbytes;	if(rawspace < 5 * 4 + 2 + muidlen + 1)		return LogDataLimit;	return 5 * 4 + 2 + muidlen - rawspace;} char *logfslogwrite(LogfsServer *server, int active, u32int path, u32int offset, int count, u32int mtime, u32int cvers,	char *muid, uchar *data, u32int *flashaddr){	/* 'w' size[2] path[4] offset[4] count[2] mtime[4] cvers[4] muid[s] flashaddr[4] [data[n]] */	LogMessage s;	uint size;	char *errmsg;	uchar *p;	u32int faddr;	uint asize; 	s.type = LogfsLogTwrite;	s.path = path;	s.u.write.offset = offset;	s.u.write.count = count;	s.u.write.mtime = mtime;	s.u.write.cvers = cvers;	s.u.write.muid = muid;	s.u.write.data = data;	size = logfssizeS2M(&s);	errmsg = logspace(server, active, 0, size, &p, &faddr);	if(errmsg)		return errmsg;	if(data)		*flashaddr = (faddr + size - count) | LogAddr;	s.u.write.flashaddr = *flashaddr;	if(server->trace > 1) {		print("%c<< ", active ? 'A' : 'S');		logfsdumpS(&s);		print("\n");	}	if((asize = logfsconvS2M(&s, p, size)) != size) {		print("expected %d actual %d\n", size, asize);		return "bad conversion";	}	logdirty(server, active);	return nil;}