332 lines
7.8 KiB
C
332 lines
7.8 KiB
C
typedef struct Arch Arch;
|
|
typedef struct BList BList;
|
|
typedef struct Block Block;
|
|
typedef struct Cache Cache;
|
|
typedef struct Disk Disk;
|
|
typedef struct Entry Entry;
|
|
typedef struct Fsck Fsck;
|
|
typedef struct Header Header;
|
|
typedef struct Label Label;
|
|
typedef struct Periodic Periodic;
|
|
typedef struct Snap Snap;
|
|
typedef struct Source Source;
|
|
typedef struct Super Super;
|
|
typedef struct WalkPtr WalkPtr;
|
|
|
|
#pragma incomplete Arch
|
|
#pragma incomplete BList
|
|
#pragma incomplete Cache
|
|
#pragma incomplete Disk
|
|
#pragma incomplete Periodic
|
|
#pragma incomplete Snap
|
|
|
|
/* tunable parameters - probably should not be constants */
|
|
enum {
|
|
/*
|
|
* estimate of bytes per dir entries - determines number
|
|
* of index entries in the block
|
|
*/
|
|
BytesPerEntry = 100,
|
|
/* don't allocate in block if more than this percentage full */
|
|
FullPercentage = 80,
|
|
FlushSize = 200, /* number of blocks to flush */
|
|
DirtyPercentage = 50, /* maximum percentage of dirty blocks */
|
|
};
|
|
|
|
enum {
|
|
Nowaitlock,
|
|
Waitlock,
|
|
|
|
MaxBlock = (1UL<<31),
|
|
};
|
|
|
|
enum {
|
|
HeaderMagic = 0x3776ae89,
|
|
HeaderVersion = 1,
|
|
HeaderOffset = 128*1024,
|
|
HeaderSize = 512,
|
|
SuperMagic = 0x2340a3b1,
|
|
SuperSize = 512,
|
|
SuperVersion = 1,
|
|
LabelSize = 14,
|
|
};
|
|
|
|
/* well known tags */
|
|
enum {
|
|
BadTag = 0, /* this tag should not be used */
|
|
RootTag = 1, /* root of fs */
|
|
EnumTag, /* root of a dir listing */
|
|
UserTag = 32, /* all other tags should be >= UserTag */
|
|
};
|
|
|
|
struct Super {
|
|
u16int version;
|
|
u32int epochLow;
|
|
u32int epochHigh;
|
|
u64int qid; /* next qid */
|
|
u32int active; /* root of active file system */
|
|
u32int next; /* root of next snapshot to archive */
|
|
u32int current; /* root of snapshot currently archiving */
|
|
uchar last[VtScoreSize]; /* last snapshot successfully archived */
|
|
char name[128]; /* label */
|
|
};
|
|
|
|
|
|
struct Fs {
|
|
Arch *arch; /* immutable */
|
|
Cache *cache; /* immutable */
|
|
int mode; /* immutable */
|
|
int noatimeupd; /* immutable */
|
|
int blockSize; /* immutable */
|
|
VtConn *z; /* immutable */
|
|
Snap *snap; /* immutable */
|
|
/* immutable; copy here & Fsys to ease error reporting */
|
|
char *name;
|
|
|
|
Periodic *metaFlush; /* periodically flushes metadata cached in files */
|
|
|
|
/*
|
|
* epoch lock.
|
|
* Most operations on the fs require a read lock of elk, ensuring that
|
|
* the current high and low epochs do not change under foot.
|
|
* This lock is mostly acquired via a call to fileLock or fileRlock.
|
|
* Deletion and creation of snapshots occurs under a write lock of elk,
|
|
* ensuring no file operations are occurring concurrently.
|
|
*/
|
|
RWLock elk; /* epoch lock */
|
|
u32int ehi; /* epoch high */
|
|
u32int elo; /* epoch low */
|
|
|
|
int halted; /* epoch lock is held to halt (console initiated) */
|
|
|
|
Source *source; /* immutable: root of sources */
|
|
File *file; /* immutable: root of files */
|
|
};
|
|
|
|
/*
|
|
* variant on VtEntry
|
|
* there are extra fields when stored locally
|
|
*/
|
|
struct Entry {
|
|
u32int gen; /* generation number */
|
|
ushort psize; /* pointer block size */
|
|
ushort dsize; /* data block size */
|
|
uchar depth; /* unpacked from flags */
|
|
uchar flags;
|
|
uvlong size;
|
|
uchar score[VtScoreSize];
|
|
u32int tag; /* tag for local blocks: zero if stored on Venti */
|
|
u32int snap; /* non-zero -> entering snapshot of given epoch */
|
|
uchar archive; /* archive this snapshot: only valid for snap != 0 */
|
|
};
|
|
|
|
/*
|
|
* This is called a `stream' in the fossil paper. There used to be Sinks too.
|
|
* We believe that Sources and Files are one-to-one.
|
|
*/
|
|
struct Source {
|
|
Fs *fs; /* immutable */
|
|
int mode; /* immutable */
|
|
int issnapshot; /* immutable */
|
|
u32int gen; /* immutable */
|
|
int dsize; /* immutable */
|
|
int dir; /* immutable */
|
|
|
|
Source *parent; /* immutable */
|
|
File *file; /* immutable; point back */
|
|
|
|
QLock lk;
|
|
int ref;
|
|
/*
|
|
* epoch for the source
|
|
* for ReadWrite sources, epoch is used to lazily notice
|
|
* sources that must be split from the snapshots.
|
|
* for ReadOnly sources, the epoch represents the minimum epoch
|
|
* along the chain from the root, and is used to lazily notice
|
|
* sources that have become invalid because they belong to an old
|
|
* snapshot.
|
|
*/
|
|
u32int epoch;
|
|
Block *b; /* block containing this source */
|
|
uchar score[VtScoreSize]; /* score of block containing this source */
|
|
u32int scoreEpoch; /* epoch of block containing this source */
|
|
int epb; /* immutable: entries per block in parent */
|
|
u32int tag; /* immutable: tag of parent */
|
|
u32int offset; /* immutable: entry offset in parent */
|
|
};
|
|
|
|
|
|
struct Header {
|
|
ushort version;
|
|
ushort blockSize;
|
|
ulong super; /* super blocks */
|
|
ulong label; /* start of labels */
|
|
ulong data; /* end of labels - start of data blocks */
|
|
ulong end; /* end of data blocks */
|
|
};
|
|
|
|
/*
|
|
* contains a one block buffer
|
|
* to avoid problems of the block changing underfoot
|
|
* and to enable an interface that supports unget.
|
|
*/
|
|
struct DirEntryEnum {
|
|
File *file;
|
|
|
|
u32int boff; /* block offset */
|
|
|
|
int i, n;
|
|
DirEntry *buf;
|
|
};
|
|
|
|
/* Block states */
|
|
enum {
|
|
BsFree = 0, /* available for allocation */
|
|
BsBad = 0xFF, /* something is wrong with this block */
|
|
|
|
/* bit fields */
|
|
BsAlloc = 1<<0, /* block is in use */
|
|
BsCopied = 1<<1,/* block has been copied (usually in preparation for unlink) */
|
|
BsVenti = 1<<2, /* block has been stored on Venti */
|
|
BsClosed = 1<<3,/* block has been unlinked on disk from active file system */
|
|
BsMask = BsAlloc|BsCopied|BsVenti|BsClosed,
|
|
};
|
|
|
|
/*
|
|
* block types
|
|
* more regular than Venti block types
|
|
* bit 3 -> block or data block
|
|
* bits 2-0 -> level of block
|
|
*/
|
|
enum {
|
|
BtData,
|
|
BtDir = 1<<3,
|
|
BtLevelMask = 7,
|
|
BtMax = 1<<4,
|
|
};
|
|
|
|
/* io states */
|
|
enum {
|
|
BioEmpty, /* label & data are not valid */
|
|
BioLabel, /* label is good */
|
|
BioClean, /* data is on the disk */
|
|
BioDirty, /* data is not yet on the disk */
|
|
BioReading, /* in process of reading data */
|
|
BioWriting, /* in process of writing data */
|
|
BioReadError, /* error reading: assume disk always handles write errors */
|
|
BioVentiError, /* error reading from venti (probably disconnected) */
|
|
BioMax
|
|
};
|
|
|
|
struct Label {
|
|
uchar type;
|
|
uchar state;
|
|
u32int tag;
|
|
u32int epoch;
|
|
u32int epochClose;
|
|
};
|
|
|
|
struct Block {
|
|
Cache *c;
|
|
int ref;
|
|
int nlock;
|
|
uintptr pc; /* pc that fetched this block from the cache */
|
|
|
|
QLock lk;
|
|
|
|
int part;
|
|
u32int addr;
|
|
uchar score[VtScoreSize]; /* score */
|
|
Label l;
|
|
|
|
uchar *dmap;
|
|
|
|
uchar *data;
|
|
|
|
/* the following is private; used by cache */
|
|
|
|
Block *next; /* doubly linked hash chains */
|
|
Block **prev;
|
|
u32int heap; /* index in heap table */
|
|
u32int used; /* last reference times */
|
|
|
|
u32int vers; /* version of dirty flag */
|
|
|
|
BList *uhead; /* blocks to unlink when this block is written */
|
|
BList *utail;
|
|
|
|
/* block ordering for cache -> disk */
|
|
BList *prior; /* list of blocks before this one */
|
|
|
|
Block *ionext;
|
|
int iostate;
|
|
Rendez ioready;
|
|
};
|
|
|
|
/* tree walker, for gc and archiver */
|
|
struct WalkPtr
|
|
{
|
|
uchar *data;
|
|
int isEntry;
|
|
int n;
|
|
int m;
|
|
Entry e;
|
|
uchar type;
|
|
u32int tag;
|
|
};
|
|
|
|
enum
|
|
{
|
|
DoClose = 1<<0,
|
|
DoClre = 1<<1,
|
|
DoClri = 1<<2,
|
|
DoClrp = 1<<3,
|
|
};
|
|
|
|
struct Fsck
|
|
{
|
|
/* filled in by caller */
|
|
int printblocks;
|
|
int useventi;
|
|
int flags;
|
|
int printdirs;
|
|
int printfiles;
|
|
int walksnapshots;
|
|
int walkfs;
|
|
Fs *fs;
|
|
int (*print)(char*, ...);
|
|
void (*clre)(Fsck*, Block*, int);
|
|
void (*clrp)(Fsck*, Block*, int);
|
|
void (*close)(Fsck*, Block*, u32int);
|
|
void (*clri)(Fsck*, char*, MetaBlock*, int, Block*);
|
|
|
|
/* used internally */
|
|
Cache *cache;
|
|
uchar *amap; /* all blocks seen so far */
|
|
uchar *emap; /* all blocks seen in this epoch */
|
|
uchar *xmap; /* all blocks in this epoch with parents in this epoch */
|
|
uchar *errmap; /* blocks with errors */
|
|
uchar *smap; /* walked sources */
|
|
int nblocks;
|
|
int bsize;
|
|
int walkdepth;
|
|
u32int hint; /* where the next root probably is */
|
|
int nseen;
|
|
int quantum;
|
|
int nclre;
|
|
int nclrp;
|
|
int nclose;
|
|
int nclri;
|
|
};
|
|
|
|
/* disk partitions; keep in sync with partname[] in disk.c */
|
|
enum {
|
|
PartError,
|
|
PartSuper,
|
|
PartLabel,
|
|
PartData,
|
|
PartVenti, /* fake partition */
|
|
};
|
|
|
|
extern int vtType[BtMax];
|