enum { L2LogSweeps = 2, L2BlockCopies = 2, LogDataLimit = 128, LogAddr = (1 << 31), Replacements = 2, /* how much free space must be available for replacements */ Transfers = 2, /* how much additional space must be available for transfers */ LogSlack = 1, /* how much additional space must be available for data allocation */}; typedef struct Extent { u32int min, max; u32int flashaddr; /* encode block index, page number, and offset within page to min */} Extent; typedef struct ExtentList ExtentList; char *logfsextentlistnew(ExtentList **l);void logfsextentlistfree(ExtentList **l);char *logfsextentlistinsert(ExtentList *l, Extent *add, Extent **new);int logfsextentlistwalk(ExtentList *l, int (*func)(void *magic, Extent *e, int hole),void *magic);Extent *logfsextentlistmatch(ExtentList *l, Extent *e);int logfsextentlistwalkrange(ExtentList *l, int (*func)(void *magic, u32int baseoffset, u32int limitoffset, Extent *, u32int extentoffset), void *magic, u32int base, u32int limit);int logfsextentlistmatchall(ExtentList *l, int (*func)(void *magic, Extent *), void *magic, Extent *e);void logfsextentlistreset(ExtentList *l); typedef struct Entry { int inuse; int deadandgone; /* removed */ Qid qid; struct Entry *parent; char *name; char *uid; char *gid; ulong mtime; char *muid; u32int perm; struct Entry *next; struct { struct { ulong cvers; ulong length; ExtentList *extent; } file; struct { struct Entry *list; } dir; } u;} Entry; char *logfsentrynew(LogfsServer *server, int inuse, u32int path, Entry *parent, char *name, char *uid, char *gid, u32int mtime, char *muid, u32int perm, ulong cvers, ulong length, Entry **ep);void logfsentryclunk(Entry *e); typedef struct DirReadState DirReadState;void logfsdrsfree(DirReadState **drsp); typedef struct Fid { ulong fid; int openmode; Entry *entry; char *uname; DirReadState *drs;} Fid; typedef struct Map Map;typedef int LOGFSMAPWALKFN(void *magic, void *entry);char *logfsmapnew(int size, int (*hash)(void *key, int size), int (*compare)(void *entry, void *key), int (*allocsize)(void *key), void (*free)(void *), Map **mapp);void logfsmapfree(Map **mp);char *logfsmapnewentry(Map *m, void *key, void **entryp);void *logfsmapfindentry(Map *m, void *key);int logfsmapdeleteentry(Map *m, void *key);int logfsmapwalk(Map *m, LOGFSMAPWALKFN *func, void *magic); typedef struct Map FidMap; char *logfsfidmapnew(FidMap **fidmapmapp);#define logfsfidmapfree(mp) logfsmapfree(mp)char *logfsfidmapnewentry(FidMap *m, ulong fid, Fid **fidmapp);#define logfsfidmapfindentry(m, fid) logfsmapfindentry(m, (void *)fid)int logfsfidmapclunk(FidMap *m, ulong fid); struct Logfs { int trace;}; typedef struct Map Ust;char *logfsustnew(Ust **ustp);#define logfsustfree(m) logfsmapfree(m)char *logfsustadd(Ust *m, char *s); typedef struct GroupSet GroupSet; typedef struct Group Group;typedef struct Map GroupMap;typedef struct Uname Uname;typedef struct Map UnameMap; struct Group { char *uid; char *uname; Group *leader; GroupSet *members;}; struct Uname { char *uname; Group *g;}; struct LogfsIdentityStore { Ust *ids; GroupMap *groupmap; UnameMap *unamemap;}; char *logfsgroupmapnew(GroupMap **groupmapp, UnameMap **unamemapp);#define logfsgroupmapfree(mp) logfsmapfree(mp)#define logfsunamemapfree(mp) logfsmapfree(mp)char *logfsgroupmapnewentry(GroupMap *gm, UnameMap *um, char *uid, char *uname, Group **groupp, Uname **unamep);#define logfsgroupmapdeleteentry(m, uid) logfsmapdeleteentry(m, (void *)uid)#define logfsgroupmapfindentry(m, uid) logfsmapfindentry(m, uid)#define logfsunamemapfindentry(m, uname) logfsmapfindentry(m, uname)char *logfsgroupmapfinduname(GroupMap *m, char *uid);char *logfsunamemapfinduid(UnameMap *m, char *uid);#define logfsunamemapdeleteentry(m, uname) logfsmapdeleteentry(m, (void *)uname) typedef int LOGFSGROUPSETWALKFN(void *magic, Group *g);char *logfsgroupsetnew(GroupSet **sp);void logfsgroupsetfree(GroupSet **sp);int logfsgroupsetadd(GroupSet *s, Group *g);int logfsgroupsetremove(GroupSet *s, Group *g);int logfsgroupsetwalk(GroupSet *s, LOGFSGROUPSETWALKFN *func, void *magic);int logfsgroupsetismember(GroupSet *gs, Group *g);char *logfsisfindidfromname(LogfsIdentityStore *is, char *name);char *logfsisfindnamefromid(LogfsIdentityStore *is, char *id);#define logfsisfindgroupfromid(is, id) logfsgroupmapfindentry((is)->groupmap, id)Group *logfsisfindgroupfromname(LogfsIdentityStore *is, char *uname);#define logfsisustadd(is, s) logfsustadd((is)->ids, s)int logfsisgroupunameismember(LogfsIdentityStore *is, Group *g, char *uname);int logfsisgroupuidismember(LogfsIdentityStore *is, Group *g, char *uid);int logfsisgroupuidisleader(LogfsIdentityStore *is, Group *g, char *uid);extern char *logfsisgroupnonename; typedef struct LogMessage { uchar type; u32int path; union { struct { u32int nerase; } start; struct { u32int perm; u32int newpath; u32int mtime; u32int cvers; char *name; char *uid; char *gid; } create; struct { u32int mtime; char *muid; } remove; struct { u32int mtime; u32int cvers; char *muid; } trunc; struct { u32int offset; u32int count; u32int mtime; u32int cvers; char *muid; u32int flashaddr; uchar *data; } write; struct { char *name; u32int perm; char *uid; char *gid; u32int mtime; char *muid; } wstat; } u;} LogMessage; uint logfsconvM2S(uchar *ap, uint nap, LogMessage *f);uint logfssizeS2M(LogMessage *f);uint logfsconvS2M(LogMessage *f, uchar *ap, uint nap);void logfsdumpS(LogMessage *s); typedef struct LogSegment LogSegment; struct LogSegment { int gen; /* generation number of this log */ int dirty; /* written to since last sweep */ long curblockindex; /* index of block being filled, or -1 */ long unsweptblockindex; /* next block to sweep */ int curpage; /* page within block */ uchar *pagebuf; /* page buffer */ int nbytes; /* bytes used in page buffer */ long blockmap[1]; /* there are ll->blocks of these */}; char *logfslogsegmentnew(LogfsServer *server, int gen, LogSegment **segp);void logfslogsegmentfree(LogSegment **segp);char *logfslogbytes(LogfsServer *server, int active, uchar *msg, uint size);char *logfslog(LogfsServer *server, int active, LogMessage *s);char *logfslogwrite(LogfsServer *server, int active, u32int path, u32int offset, int count, u32int mtime, u32int cvers, char *muid, uchar *data, u32int *flashaddr);char *logfslogsegmentflush(LogfsServer *server, int active);int lognicesizeforwrite(LogfsServer *server, int active, u32int count, int muidlen);char *logfsscan(LogfsServer *server); typedef struct DataBlock DataBlock; struct DataBlock { u32int free; u32int dirty; long path; /* includes generation */ long block;}; u32int logfsdatapagemask(int pages, int base); typedef struct Path Path; struct Path { ulong path; Entry *entry;}; typedef struct Map PathMap; char *logfspathmapnew(PathMap **pathmapmapp);#define logfspathmapfree(mp) logfsmapfree(mp)char *logfspathmapnewentry(PathMap *m, ulong path, Entry *e, Path **pathmapp);#define logfspathmapfindentry(m, path) (Path *)logfsmapfindentry(m, (void *)path)#define logfspathmapdeleteentry(m, path) logfsmapdeleteentry(m, (void *)path)Entry *logfspathmapfinde(PathMap *m, ulong path); enum { LogfsTestDontFettleDataBlock = 1,}; struct LogfsServer { LogfsLowLevel *ll; LogfsBoot *lb; FidMap *fidmap; LogfsIdentityStore *is; PathMap *pathmap; LogSegment *activelog; LogSegment *sweptlog; long ndatablocks; DataBlock *datablock; ulong path; Entry root; int trace; ulong openflags; ulong testflags;}; int logfshashulong(void *v, int size); int logfsuserpermcheck(LogfsServer *s, Entry *e, Fid *f, ulong modemask);u32int logfsflattenentry(LogfsIdentityStore *is, uchar *buf, u32int buflen, Entry *e);char *logfsreplay(LogfsServer *server, LogSegment *seg, int disableerrorsforfirstblock);void logfsreplayfinddata(LogfsServer *server); #define dataseqof(path) ((path) >> L2BlockCopies)#define copygenof(path) ((path) & ((1 << L2BlockCopies) -1))#define mkdatapath(seq, gen) (((seq) << L2BlockCopies) | (gen))#define gensucc(g, l2) (((g) + 1) & ((1 << (l2)) - 1))#define copygensucc(g) gensucc(g, L2BlockCopies)#define loggenof(path) ((path >> L2BlockCopies) & ((1 << L2LogSweeps) - 1))#define logseqof(path) ((path) >> (L2BlockCopies + L2LogSweeps))#define mklogpath(seq, gen, copygen) (((((seq) << L2LogSweeps) | (gen)) << L2BlockCopies) | (copygen))#define loggensucc(g) gensucc(g, L2LogSweeps) int logfsunconditionallymarkfreeanddirty(void *magic, Extent *e, int hole);void logfsflashaddr2spo(LogfsServer *server, u32int flashaddr, long *seq, int *page, int *offset);int logfsgn(uchar **pp, uchar *mep, char **v);u32int logfsspo2flashaddr(LogfsServer *server, long seq, int page, int offset);int logfsgn(uchar **pp, uchar *mep, char **v);void logfsflashaddr2o(LogfsServer *server, u32int flashaddr, int *offset);void logfsfreedatapages(LogfsServer *server, long seq, u32int mask);void logfsfreeanddirtydatablockcheck(LogfsServer *server, long seq); typedef enum AllocReason { AllocReasonReplace, AllocReasonTransfer, AllocReasonLogExtend, AllocReasonDataExtend,} AllocReason; long logfsfindfreeblock(LogfsLowLevel *ll, AllocReason reason);char *logfsbootfettleblock(LogfsBoot *lb, long block, uchar tag, long path, int *markedbad);char *logfsserverreplacedatablock(LogfsServer *server, long index);char *logfsserverreplacelogblock(LogfsServer *server, LogSegment *seg, long index);char *logfsserverreplaceblock(LogfsServer *server, LogSegment *seg, long seq);char *logfsservercopyactivedata(LogfsServer *server, long newb, long oldblockindex, int forcepage0, LogfsLowLevelReadResult *llrrp, int *markedbadp); char *logfsstrdup(char *); extern char Enomem[];extern char Emsgsize[];extern char Enonexist[];extern char Etoobig[];extern char Eexist[];extern char Eunknown[];extern char Enotdir[];extern char Eisdir[];extern char logfsebadfid[];extern char logfsefidopen[];extern char logfsefidnotopen[];extern char logfsefidinuse[];extern char logfseopen[];extern char logfseaccess[];extern char logfselogmsgtoobig[];extern char logfselogfull[];extern char logfseinternal[];extern char logfsenotempty[];extern char logfseexcl[];extern char logfsefullreplacing[];extern char logfseunknownpath[];
enum {
L2LogSweeps = 2,
L2BlockCopies = 2,
LogDataLimit = 128,
LogAddr = (1 << 31),
Replacements = 2, /* how much free space must be available for replacements */
Transfers = 2, /* how much additional space must be available for transfers */
LogSlack = 1, /* how much additional space must be available for data allocation */
};
typedef struct Extent {
u32int min, max;
u32int flashaddr; /* encode block index, page number, and offset within page to min */
} Extent;
typedef struct ExtentList ExtentList;
char *logfsextentlistnew(ExtentList **l);
void logfsextentlistfree(ExtentList **l);
char *logfsextentlistinsert(ExtentList *l, Extent *add, Extent **new);
int logfsextentlistwalk(ExtentList *l, int (*func)(void *magic, Extent *e, int hole),void *magic);
Extent *logfsextentlistmatch(ExtentList *l, Extent *e);
int logfsextentlistwalkrange(ExtentList *l,
int (*func)(void *magic, u32int baseoffset, u32int limitoffset, Extent *, u32int extentoffset),
void *magic, u32int base, u32int limit);
int logfsextentlistmatchall(ExtentList *l, int (*func)(void *magic, Extent *), void *magic, Extent *e);
void logfsextentlistreset(ExtentList *l);
typedef struct Entry {
int inuse;
int deadandgone; /* removed */
Qid qid;
struct Entry *parent;
char *name;
char *uid;
char *gid;
ulong mtime;
char *muid;
u32int perm;
struct Entry *next;
struct {
struct {
ulong cvers;
ulong length;
ExtentList *extent;
} file;
struct {
struct Entry *list;
} dir;
} u;
} Entry;
char *logfsentrynew(LogfsServer *server, int inuse, u32int path, Entry *parent,
char *name, char *uid, char *gid,
u32int mtime, char *muid, u32int perm, ulong cvers, ulong length, Entry **ep);
void logfsentryclunk(Entry *e);
typedef struct DirReadState DirReadState;
void logfsdrsfree(DirReadState **drsp);
typedef struct Fid {
ulong fid;
int openmode;
Entry *entry;
char *uname;
DirReadState *drs;
} Fid;
typedef struct Map Map;
typedef int LOGFSMAPWALKFN(void *magic, void *entry);
char *logfsmapnew(int size, int (*hash)(void *key, int size), int (*compare)(void *entry, void *key), int (*allocsize)(void *key), void (*free)(void *), Map **mapp);
void logfsmapfree(Map **mp);
char *logfsmapnewentry(Map *m, void *key, void **entryp);
void *logfsmapfindentry(Map *m, void *key);
int logfsmapdeleteentry(Map *m, void *key);
int logfsmapwalk(Map *m, LOGFSMAPWALKFN *func, void *magic);
typedef struct Map FidMap;
char *logfsfidmapnew(FidMap **fidmapmapp);
#define logfsfidmapfree(mp) logfsmapfree(mp)
char *logfsfidmapnewentry(FidMap *m, ulong fid, Fid **fidmapp);
#define logfsfidmapfindentry(m, fid) logfsmapfindentry(m, (void *)fid)
int logfsfidmapclunk(FidMap *m, ulong fid);
struct Logfs {
int trace;
};
typedef struct Map Ust;
char *logfsustnew(Ust **ustp);
#define logfsustfree(m) logfsmapfree(m)
char *logfsustadd(Ust *m, char *s);
typedef struct GroupSet GroupSet;
typedef struct Group Group;
typedef struct Map GroupMap;
typedef struct Uname Uname;
typedef struct Map UnameMap;
struct Group {
char *uid;
char *uname;
Group *leader;
GroupSet *members;
};
struct Uname {
char *uname;
Group *g;
};
struct LogfsIdentityStore {
Ust *ids;
GroupMap *groupmap;
UnameMap *unamemap;
};
char *logfsgroupmapnew(GroupMap **groupmapp, UnameMap **unamemapp);
#define logfsgroupmapfree(mp) logfsmapfree(mp)
#define logfsunamemapfree(mp) logfsmapfree(mp)
char *logfsgroupmapnewentry(GroupMap *gm, UnameMap *um, char *uid, char *uname, Group **groupp, Uname **unamep);
#define logfsgroupmapdeleteentry(m, uid) logfsmapdeleteentry(m, (void *)uid)
#define logfsgroupmapfindentry(m, uid) logfsmapfindentry(m, uid)
#define logfsunamemapfindentry(m, uname) logfsmapfindentry(m, uname)
char *logfsgroupmapfinduname(GroupMap *m, char *uid);
char *logfsunamemapfinduid(UnameMap *m, char *uid);
#define logfsunamemapdeleteentry(m, uname) logfsmapdeleteentry(m, (void *)uname)
typedef int LOGFSGROUPSETWALKFN(void *magic, Group *g);
char *logfsgroupsetnew(GroupSet **sp);
void logfsgroupsetfree(GroupSet **sp);
int logfsgroupsetadd(GroupSet *s, Group *g);
int logfsgroupsetremove(GroupSet *s, Group *g);
int logfsgroupsetwalk(GroupSet *s, LOGFSGROUPSETWALKFN *func, void *magic);
int logfsgroupsetismember(GroupSet *gs, Group *g);
char *logfsisfindidfromname(LogfsIdentityStore *is, char *name);
char *logfsisfindnamefromid(LogfsIdentityStore *is, char *id);
#define logfsisfindgroupfromid(is, id) logfsgroupmapfindentry((is)->groupmap, id)
Group *logfsisfindgroupfromname(LogfsIdentityStore *is, char *uname);
#define logfsisustadd(is, s) logfsustadd((is)->ids, s)
int logfsisgroupunameismember(LogfsIdentityStore *is, Group *g, char *uname);
int logfsisgroupuidismember(LogfsIdentityStore *is, Group *g, char *uid);
int logfsisgroupuidisleader(LogfsIdentityStore *is, Group *g, char *uid);
extern char *logfsisgroupnonename;
typedef struct LogMessage {
uchar type;
u32int path;
union {
struct {
u32int nerase;
} start;
struct {
u32int perm;
u32int newpath;
u32int mtime;
u32int cvers;
char *name;
char *uid;
char *gid;
} create;
struct {
u32int mtime;
char *muid;
} remove;
struct {
u32int mtime;
u32int cvers;
char *muid;
} trunc;
struct {
u32int offset;
u32int count;
u32int mtime;
u32int cvers;
char *muid;
u32int flashaddr;
uchar *data;
} write;
struct {
char *name;
u32int perm;
char *uid;
char *gid;
u32int mtime;
char *muid;
} wstat;
} u;
} LogMessage;
uint logfsconvM2S(uchar *ap, uint nap, LogMessage *f);
uint logfssizeS2M(LogMessage *f);
uint logfsconvS2M(LogMessage *f, uchar *ap, uint nap);
void logfsdumpS(LogMessage *s);
typedef struct LogSegment LogSegment;
struct LogSegment {
int gen; /* generation number of this log */
int dirty; /* written to since last sweep */
long curblockindex; /* index of block being filled, or -1 */
long unsweptblockindex; /* next block to sweep */
int curpage; /* page within block */
uchar *pagebuf; /* page buffer */
int nbytes; /* bytes used in page buffer */
long blockmap[1]; /* there are ll->blocks of these */
};
char *logfslogsegmentnew(LogfsServer *server, int gen, LogSegment **segp);
void logfslogsegmentfree(LogSegment **segp);
char *logfslogbytes(LogfsServer *server, int active, uchar *msg, uint size);
char *logfslog(LogfsServer *server, int active, LogMessage *s);
char *logfslogwrite(LogfsServer *server, int active, u32int path, u32int offset, int count, u32int mtime,
u32int cvers, char *muid, uchar *data, u32int *flashaddr);
char *logfslogsegmentflush(LogfsServer *server, int active);
int lognicesizeforwrite(LogfsServer *server, int active, u32int count, int muidlen);
char *logfsscan(LogfsServer *server);
typedef struct DataBlock DataBlock;
struct DataBlock {
u32int free;
u32int dirty;
long path; /* includes generation */
long block;
};
u32int logfsdatapagemask(int pages, int base);
typedef struct Path Path;
struct Path {
ulong path;
Entry *entry;
};
typedef struct Map PathMap;
char *logfspathmapnew(PathMap **pathmapmapp);
#define logfspathmapfree(mp) logfsmapfree(mp)
char *logfspathmapnewentry(PathMap *m, ulong path, Entry *e, Path **pathmapp);
#define logfspathmapfindentry(m, path) (Path *)logfsmapfindentry(m, (void *)path)
#define logfspathmapdeleteentry(m, path) logfsmapdeleteentry(m, (void *)path)
Entry *logfspathmapfinde(PathMap *m, ulong path);
enum {
LogfsTestDontFettleDataBlock = 1,
};
struct LogfsServer {
LogfsLowLevel *ll;
LogfsBoot *lb;
FidMap *fidmap;
LogfsIdentityStore *is;
PathMap *pathmap;
LogSegment *activelog;
LogSegment *sweptlog;
long ndatablocks;
DataBlock *datablock;
ulong path;
Entry root;
int trace;
ulong openflags;
ulong testflags;
};
int logfshashulong(void *v, int size);
int logfsuserpermcheck(LogfsServer *s, Entry *e, Fid *f, ulong modemask);
u32int logfsflattenentry(LogfsIdentityStore *is, uchar *buf, u32int buflen, Entry *e);
char *logfsreplay(LogfsServer *server, LogSegment *seg, int disableerrorsforfirstblock);
void logfsreplayfinddata(LogfsServer *server);
#define dataseqof(path) ((path) >> L2BlockCopies)
#define copygenof(path) ((path) & ((1 << L2BlockCopies) -1))
#define mkdatapath(seq, gen) (((seq) << L2BlockCopies) | (gen))
#define gensucc(g, l2) (((g) + 1) & ((1 << (l2)) - 1))
#define copygensucc(g) gensucc(g, L2BlockCopies)
#define loggenof(path) ((path >> L2BlockCopies) & ((1 << L2LogSweeps) - 1))
#define logseqof(path) ((path) >> (L2BlockCopies + L2LogSweeps))
#define mklogpath(seq, gen, copygen) (((((seq) << L2LogSweeps) | (gen)) << L2BlockCopies) | (copygen))
#define loggensucc(g) gensucc(g, L2LogSweeps)
int logfsunconditionallymarkfreeanddirty(void *magic, Extent *e, int hole);
void logfsflashaddr2spo(LogfsServer *server, u32int flashaddr, long *seq, int *page, int *offset);
int logfsgn(uchar **pp, uchar *mep, char **v);
u32int logfsspo2flashaddr(LogfsServer *server, long seq, int page, int offset);
int logfsgn(uchar **pp, uchar *mep, char **v);
void logfsflashaddr2o(LogfsServer *server, u32int flashaddr, int *offset);
void logfsfreedatapages(LogfsServer *server, long seq, u32int mask);
void logfsfreeanddirtydatablockcheck(LogfsServer *server, long seq);
typedef enum AllocReason {
AllocReasonReplace,
AllocReasonTransfer,
AllocReasonLogExtend,
AllocReasonDataExtend,
} AllocReason;
long logfsfindfreeblock(LogfsLowLevel *ll, AllocReason reason);
char *logfsbootfettleblock(LogfsBoot *lb, long block, uchar tag, long path, int *markedbad);
char *logfsserverreplacedatablock(LogfsServer *server, long index);
char *logfsserverreplacelogblock(LogfsServer *server, LogSegment *seg, long index);
char *logfsserverreplaceblock(LogfsServer *server, LogSegment *seg, long seq);
char *logfsservercopyactivedata(LogfsServer *server, long newb, long oldblockindex, int forcepage0,
LogfsLowLevelReadResult *llrrp, int *markedbadp);
char *logfsstrdup(char *);
extern char Enomem[];
extern char Emsgsize[];
extern char Enonexist[];
extern char Etoobig[];
extern char Eexist[];
extern char Eunknown[];
extern char Enotdir[];
extern char Eisdir[];
extern char logfsebadfid[];
extern char logfsefidopen[];
extern char logfsefidnotopen[];
extern char logfsefidinuse[];
extern char logfseopen[];
extern char logfseaccess[];
extern char logfselogmsgtoobig[];
extern char logfselogfull[];
extern char logfseinternal[];
extern char logfsenotempty[];
extern char logfseexcl[];
extern char logfsefullreplacing[];
extern char logfseunknownpath[];