From 37da2899f40661e3e9631e497da8dc59b971cbd0 Mon Sep 17 00:00:00 2001 From: "Charles.Forsyth" Date: Fri, 22 Dec 2006 17:07:39 +0000 Subject: 20060303a --- liblogfs/log.c | 270 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 liblogfs/log.c (limited to 'liblogfs/log.c') diff --git a/liblogfs/log.c b/liblogfs/log.c new file mode 100644 index 00000000..83217152 --- /dev/null +++ b/liblogfs/log.c @@ -0,0 +1,270 @@ +#include "lib9.h" +#include "logfs.h" +#include "local.h" +#include "fcall.h" + +void +logfsflashaddr2spo(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; +} + +u32int +logfsspo2flashaddr(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; +} + +void +logfsflashaddr2o(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; +} + +void +logfslogsegmentfree(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 void +logdirty(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; +} + +int +lognicesizeforwrite(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; +} + -- cgit v1.2.3