#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;}
#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;
}