ref: d3d1b3b47ff80f451c6c9f8b7f1262fef6545f2b
dir: /liblogfs/log.c/
#include "logfsos.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;
memmove(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;
}