#include "logfsos.h"#include "logfs.h"#include "local.h"#include "fcall.h" struct DirReadState { u32int offset; u32int lastoffset; u32int limit; uchar *data;}; typedef struct ReaderState { uchar *buf; u32int maxoffset; LogfsServer *server; char *errmsg;} ReaderState; static DirReadState *drsinit(LogfsIdentityStore *is, Entry *list, uchar *buf, u32int buflen, u32int *rcount){ Entry *p, *q; DirReadState *drs; u32int k; /* * stash as many entries as will fit in the read buffer */ *rcount = 0; for(p = list; p; p = p->next) { uint len = logfsflattenentry(is, buf, buflen, p); if(len == 0) break; *rcount += len; buf += len; buflen -= len; } drs = logfsrealloc(nil, sizeof(*drs)); if(drs == nil) return nil; drs->offset = *rcount; drs->lastoffset = drs->offset; k = 0; for(q = p; q; q = q->next) k += logfsflattenentry(is, nil, 0, q); if(k) { u32int k2;// print("drsinit: %ud bytes extra\n", k); drs->data = logfsrealloc(nil, k); if(drs->data == nil) { logfsfreemem(drs); return nil; } k2 = 0; for(q = p; q; q = q->next) k2 += logfsflattenentry(is, drs->data + k2, k - k2, q); drs->limit = drs->offset + k; }// print("drsinit: rcount %ud\n", *rcount); return drs;} static voiddrsread(DirReadState *drs, uchar *buf, u32int buflen, u32int *rcount){ uchar *p; *rcount = 0; p = drs->data + drs->lastoffset - drs->offset; while(drs->lastoffset < drs->limit) { /* * copy an entry, if it fits */ uint len = GBIT16(p) + BIT16SZ; if(len > buflen) break; memmove(buf, p, len); drs->lastoffset += len; *rcount += len; buf += len; buflen -= len; p += len; } if(drs->lastoffset >= drs->limit) { logfsfreemem(drs->data); drs->data = nil; }} voidlogfsdrsfree(DirReadState **drsp){ DirReadState *drs = *drsp; if(drs) { logfsfreemem(drs->data); logfsfreemem(drs); *drsp = nil; }} static intreader(void *magic, u32int baseoffset, u32int limitoffset, Extent *e, u32int extentoffset){ ReaderState *s = magic; LogfsServer *server; LogfsLowLevel *ll; LogfsLowLevelReadResult llrr; long seq; int page; int offset; long block; int pagesize; LogSegment *seg; int replace; if(e == nil) {//print("fill(%d, %d)\n", baseoffset, limitoffset); memset(s->buf + baseoffset, 0, limitoffset - baseoffset); if(limitoffset > s->maxoffset) s->maxoffset = limitoffset; return 1; } server = s->server; ll = server->ll; /* * extentoffset is how much to trim off the front of the extent */ logfsflashaddr2spo(server, e->flashaddr + extentoffset, &seq, &page, &offset); /* * offset is the offset within the page to where e->min is stored *///print("read(%d, %d, %c%ld/%ud/%ud)\n",// baseoffset, limitoffset, (e->flashaddr & LogAddr) ? 'L' : 'D', seq, page, offset); if(e->flashaddr & LogAddr) { if(seq >= server->activelog->unsweptblockindex && seq <= server->activelog->curblockindex) seg = server->activelog; else if(server->sweptlog && seq <= server->sweptlog->curblockindex) seg = server->sweptlog; else { print("logfsserverread: illegal log sequence number %ld (active=[%ld, %ld], swept=[%ld, %ld])\n", seq, server->activelog->unsweptblockindex, server->activelog->curblockindex, server->sweptlog ? 0L : -1L, server->sweptlog ? server->sweptlog->curblockindex : -1L); s->errmsg = logfseinternal; return -1; } if(seg->curpage == page && seg->curblockindex == seq) { /* * it hasn't made it to disk yet */ memmove(s->buf + baseoffset, seg->pagebuf + offset, limitoffset - baseoffset); goto done; } if(seq < seg->unsweptblockindex) { /* data already swept */ print("logfsserverread: log address has been swept\n"); s->errmsg = logfseinternal; return -1; } block = seg->blockmap[seq]; } else { seg = nil; if(seq >= server->ndatablocks) block = -1; else block = server->datablock[seq].block; if(block < 0) { print("logfsserveread: data address does not exist\n"); s->errmsg = logfseinternal; return -1; } } /* * read as many pages as necessary to get to the limitoffset */ pagesize = 1 << ll->l2pagesize; replace = 0; while(baseoffset < limitoffset) { u32int thistime; thistime = pagesize - offset; if(thistime > (limitoffset - baseoffset)) thistime = limitoffset - baseoffset; s->errmsg = (*ll->readpagerange)(ll, s->buf + baseoffset, block, page, offset, thistime, &llrr); if(s->errmsg) return -1; if(llrr != LogfsLowLevelReadResultOk) { replace = 1; } baseoffset += thistime; page++; offset = 0; } if(replace) { s->errmsg = logfsserverreplaceblock(server, seg, seq); if(s->errmsg) return -1; }done: if(limitoffset > s->maxoffset) s->maxoffset = limitoffset; return 1;} char *logfsserverread(LogfsServer *server, u32int fid, u32int offset, u32int count, uchar *buf, u32int buflen, u32int *rcount){ Fid *f; Entry *e; ReaderState s; int rv; if(server->trace > 1) print("logfsserverread(%ud, %ud, %ud)\n", fid, offset, count); f = logfsfidmapfindentry(server->fidmap, fid); if(f == nil) return logfsebadfid; if(f->openmode < 0) return logfsefidnotopen; if((f->openmode & 3) == OWRITE) return logfseaccess; if(count > buflen) return Etoobig; e = f->entry; if(e->deadandgone) return Eio; if(e->qid.type & QTDIR) { if(offset != 0) { if(f->drs == nil || f->drs->lastoffset != offset) return Eio; drsread(f->drs, buf, count, rcount); } else { logfsdrsfree(&f->drs); f->drs = drsinit(server->is, e->u.dir.list, buf, count, rcount); if(f->drs == nil) return Enomem; } return nil; } if(offset >= e->u.file.length) { *rcount = 0; return nil; } s.buf = buf; s.server = server; s.maxoffset = 0; rv = logfsextentlistwalkrange(e->u.file.extent, reader, &s, offset, offset + count); if(rv < 0) return s.errmsg; *rcount = s.maxoffset; return nil;}
#include "logfsos.h"
#include "logfs.h"
#include "local.h"
#include "fcall.h"
struct DirReadState {
u32int offset;
u32int lastoffset;
u32int limit;
uchar *data;
};
typedef struct ReaderState {
uchar *buf;
u32int maxoffset;
LogfsServer *server;
char *errmsg;
} ReaderState;
static DirReadState *
drsinit(LogfsIdentityStore *is, Entry *list, uchar *buf, u32int buflen, u32int *rcount)
{
Entry *p, *q;
DirReadState *drs;
u32int k;
/*
* stash as many entries as will fit in the read buffer
*/
*rcount = 0;
for(p = list; p; p = p->next) {
uint len = logfsflattenentry(is, buf, buflen, p);
if(len == 0)
break;
*rcount += len;
buf += len;
buflen -= len;
}
drs = logfsrealloc(nil, sizeof(*drs));
if(drs == nil)
return nil;
drs->offset = *rcount;
drs->lastoffset = drs->offset;
k = 0;
for(q = p; q; q = q->next)
k += logfsflattenentry(is, nil, 0, q);
if(k) {
u32int k2;
// print("drsinit: %ud bytes extra\n", k);
drs->data = logfsrealloc(nil, k);
if(drs->data == nil) {
logfsfreemem(drs);
return nil;
}
k2 = 0;
for(q = p; q; q = q->next)
k2 += logfsflattenentry(is, drs->data + k2, k - k2, q);
drs->limit = drs->offset + k;
}
// print("drsinit: rcount %ud\n", *rcount);
return drs;
}
static void
drsread(DirReadState *drs, uchar *buf, u32int buflen, u32int *rcount)
{
uchar *p;
*rcount = 0;
p = drs->data + drs->lastoffset - drs->offset;
while(drs->lastoffset < drs->limit) {
/*
* copy an entry, if it fits
*/
uint len = GBIT16(p) + BIT16SZ;
if(len > buflen)
break;
memmove(buf, p, len);
drs->lastoffset += len;
*rcount += len;
buf += len;
buflen -= len;
p += len;
}
if(drs->lastoffset >= drs->limit) {
logfsfreemem(drs->data);
drs->data = nil;
}
}
void
logfsdrsfree(DirReadState **drsp)
{
DirReadState *drs = *drsp;
if(drs) {
logfsfreemem(drs->data);
logfsfreemem(drs);
*drsp = nil;
}
}
static int
reader(void *magic, u32int baseoffset, u32int limitoffset, Extent *e, u32int extentoffset)
{
ReaderState *s = magic;
LogfsServer *server;
LogfsLowLevel *ll;
LogfsLowLevelReadResult llrr;
long seq;
int page;
int offset;
long block;
int pagesize;
LogSegment *seg;
int replace;
if(e == nil) {
//print("fill(%d, %d)\n", baseoffset, limitoffset);
memset(s->buf + baseoffset, 0, limitoffset - baseoffset);
if(limitoffset > s->maxoffset)
s->maxoffset = limitoffset;
return 1;
}
server = s->server;
ll = server->ll;
/*
* extentoffset is how much to trim off the front of the extent
*/
logfsflashaddr2spo(server, e->flashaddr + extentoffset, &seq, &page, &offset);
/*
* offset is the offset within the page to where e->min is stored
*/
//print("read(%d, %d, %c%ld/%ud/%ud)\n",
// baseoffset, limitoffset, (e->flashaddr & LogAddr) ? 'L' : 'D', seq, page, offset);
if(e->flashaddr & LogAddr) {
if(seq >= server->activelog->unsweptblockindex && seq <= server->activelog->curblockindex)
seg = server->activelog;
else if(server->sweptlog && seq <= server->sweptlog->curblockindex)
seg = server->sweptlog;
else {
print("logfsserverread: illegal log sequence number %ld (active=[%ld, %ld], swept=[%ld, %ld])\n",
seq, server->activelog->unsweptblockindex, server->activelog->curblockindex,
server->sweptlog ? 0L : -1L, server->sweptlog ? server->sweptlog->curblockindex : -1L);
s->errmsg = logfseinternal;
return -1;
}
if(seg->curpage == page && seg->curblockindex == seq) {
/*
* it hasn't made it to disk yet
*/
memmove(s->buf + baseoffset, seg->pagebuf + offset, limitoffset - baseoffset);
goto done;
}
if(seq < seg->unsweptblockindex) {
/* data already swept */
print("logfsserverread: log address has been swept\n");
s->errmsg = logfseinternal;
return -1;
}
block = seg->blockmap[seq];
}
else {
seg = nil;
if(seq >= server->ndatablocks)
block = -1;
else
block = server->datablock[seq].block;
if(block < 0) {
print("logfsserveread: data address does not exist\n");
s->errmsg = logfseinternal;
return -1;
}
}
/*
* read as many pages as necessary to get to the limitoffset
*/
pagesize = 1 << ll->l2pagesize;
replace = 0;
while(baseoffset < limitoffset) {
u32int thistime;
thistime = pagesize - offset;
if(thistime > (limitoffset - baseoffset))
thistime = limitoffset - baseoffset;
s->errmsg = (*ll->readpagerange)(ll, s->buf + baseoffset, block, page,
offset, thistime, &llrr);
if(s->errmsg)
return -1;
if(llrr != LogfsLowLevelReadResultOk) {
replace = 1;
}
baseoffset += thistime;
page++;
offset = 0;
}
if(replace) {
s->errmsg = logfsserverreplaceblock(server, seg, seq);
if(s->errmsg)
return -1;
}
done:
if(limitoffset > s->maxoffset)
s->maxoffset = limitoffset;
return 1;
}
char *
logfsserverread(LogfsServer *server, u32int fid, u32int offset, u32int count, uchar *buf, u32int buflen, u32int *rcount)
{
Fid *f;
Entry *e;
ReaderState s;
int rv;
if(server->trace > 1)
print("logfsserverread(%ud, %ud, %ud)\n", fid, offset, count);
f = logfsfidmapfindentry(server->fidmap, fid);
if(f == nil)
return logfsebadfid;
if(f->openmode < 0)
return logfsefidnotopen;
if((f->openmode & 3) == OWRITE)
return logfseaccess;
if(count > buflen)
return Etoobig;
e = f->entry;
if(e->deadandgone)
return Eio;
if(e->qid.type & QTDIR) {
if(offset != 0) {
if(f->drs == nil || f->drs->lastoffset != offset)
return Eio;
drsread(f->drs, buf, count, rcount);
}
else {
logfsdrsfree(&f->drs);
f->drs = drsinit(server->is, e->u.dir.list, buf, count, rcount);
if(f->drs == nil)
return Enomem;
}
return nil;
}
if(offset >= e->u.file.length) {
*rcount = 0;
return nil;
}
s.buf = buf;
s.server = server;
s.maxoffset = 0;
rv = logfsextentlistwalkrange(e->u.file.extent, reader, &s, offset, offset + count);
if(rv < 0)
return s.errmsg;
*rcount = s.maxoffset;
return nil;
}