| 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]; |