15e96a66cSDavid du Colombier typedef struct Arch Arch; 25e96a66cSDavid du Colombier typedef struct BList BList; 35e96a66cSDavid du Colombier typedef struct Block Block; 45e96a66cSDavid du Colombier typedef struct Cache Cache; 55e96a66cSDavid du Colombier typedef struct Disk Disk; 65e96a66cSDavid du Colombier typedef struct Entry Entry; 7e569ccb5SDavid du Colombier typedef struct Fsck Fsck; 85e96a66cSDavid du Colombier typedef struct Header Header; 95e96a66cSDavid du Colombier typedef struct Label Label; 105e96a66cSDavid du Colombier typedef struct Periodic Periodic; 115e96a66cSDavid du Colombier typedef struct Snap Snap; 125e96a66cSDavid du Colombier typedef struct Source Source; 135e96a66cSDavid du Colombier typedef struct Super Super; 145e96a66cSDavid du Colombier typedef struct WalkPtr WalkPtr; 155e96a66cSDavid du Colombier 1612fd1c83SDavid du Colombier #pragma incomplete Arch 1712fd1c83SDavid du Colombier #pragma incomplete BList 1812fd1c83SDavid du Colombier #pragma incomplete Cache 1912fd1c83SDavid du Colombier #pragma incomplete Disk 2012fd1c83SDavid du Colombier #pragma incomplete Periodic 2112fd1c83SDavid du Colombier #pragma incomplete Snap 2212fd1c83SDavid du Colombier 2300580da5SDavid du Colombier /* tunable parameters - probably should not be constants */ 245e96a66cSDavid du Colombier enum { 2500580da5SDavid du Colombier /* 2600580da5SDavid du Colombier * estimate of bytes per dir entries - determines number 2700580da5SDavid du Colombier * of index entries in the block 2800580da5SDavid du Colombier */ 2900580da5SDavid du Colombier BytesPerEntry = 100, 3000580da5SDavid du Colombier /* don't allocate in block if more than this percentage full */ 3100580da5SDavid du Colombier FullPercentage = 80, 325e96a66cSDavid du Colombier FlushSize = 200, /* number of blocks to flush */ 335e96a66cSDavid du Colombier DirtyPercentage = 50, /* maximum percentage of dirty blocks */ 345e96a66cSDavid du Colombier }; 355e96a66cSDavid du Colombier 365e96a66cSDavid du Colombier enum { 37*e12a9870SDavid du Colombier Nowaitlock, 38*e12a9870SDavid du Colombier Waitlock, 39*e12a9870SDavid du Colombier 405e96a66cSDavid du Colombier NilBlock = (~0UL), 415e96a66cSDavid du Colombier MaxBlock = (1UL<<31), 425e96a66cSDavid du Colombier }; 435e96a66cSDavid du Colombier 445e96a66cSDavid du Colombier enum { 455e96a66cSDavid du Colombier HeaderMagic = 0x3776ae89, 465e96a66cSDavid du Colombier HeaderVersion = 1, 475e96a66cSDavid du Colombier HeaderOffset = 128*1024, 485e96a66cSDavid du Colombier HeaderSize = 512, 495e96a66cSDavid du Colombier SuperMagic = 0x2340a3b1, 505e96a66cSDavid du Colombier SuperSize = 512, 515e96a66cSDavid du Colombier SuperVersion = 1, 525e96a66cSDavid du Colombier LabelSize = 14, 535e96a66cSDavid du Colombier }; 545e96a66cSDavid du Colombier 555e96a66cSDavid du Colombier /* well known tags */ 565e96a66cSDavid du Colombier enum { 575e96a66cSDavid du Colombier BadTag = 0, /* this tag should not be used */ 585e96a66cSDavid du Colombier RootTag = 1, /* root of fs */ 595e96a66cSDavid du Colombier EnumTag, /* root of a dir listing */ 605e96a66cSDavid du Colombier UserTag = 32, /* all other tags should be >= UserTag */ 615e96a66cSDavid du Colombier }; 625e96a66cSDavid du Colombier 635e96a66cSDavid du Colombier struct Super { 645e96a66cSDavid du Colombier u16int version; 655e96a66cSDavid du Colombier u32int epochLow; 665e96a66cSDavid du Colombier u32int epochHigh; 675e96a66cSDavid du Colombier u64int qid; /* next qid */ 685e96a66cSDavid du Colombier u32int active; /* root of active file system */ 695e96a66cSDavid du Colombier u32int next; /* root of next snapshot to archive */ 705e96a66cSDavid du Colombier u32int current; /* root of snapshot currently archiving */ 715e96a66cSDavid du Colombier uchar last[VtScoreSize]; /* last snapshot successfully archived */ 725e96a66cSDavid du Colombier char name[128]; /* label */ 735e96a66cSDavid du Colombier }; 745e96a66cSDavid du Colombier 755e96a66cSDavid du Colombier 765e96a66cSDavid du Colombier struct Fs { 775e96a66cSDavid du Colombier Arch *arch; /* immutable */ 785e96a66cSDavid du Colombier Cache *cache; /* immutable */ 795e96a66cSDavid du Colombier int mode; /* immutable */ 80f4051287SDavid du Colombier int noatimeupd; /* immutable */ 815e96a66cSDavid du Colombier int blockSize; /* immutable */ 825e96a66cSDavid du Colombier VtSession *z; /* immutable */ 835e96a66cSDavid du Colombier Snap *snap; /* immutable */ 840c6300e7SDavid du Colombier /* immutable; copy here & Fsys to ease error reporting */ 850c6300e7SDavid du Colombier char *name; 865e96a66cSDavid du Colombier 875e96a66cSDavid du Colombier Periodic *metaFlush; /* periodically flushes metadata cached in files */ 885e96a66cSDavid du Colombier 895e96a66cSDavid du Colombier /* 905e96a66cSDavid du Colombier * epoch lock. 915e96a66cSDavid du Colombier * Most operations on the fs require a read lock of elk, ensuring that 925e96a66cSDavid du Colombier * the current high and low epochs do not change under foot. 935e96a66cSDavid du Colombier * This lock is mostly acquired via a call to fileLock or fileRlock. 945e96a66cSDavid du Colombier * Deletion and creation of snapshots occurs under a write lock of elk, 955e96a66cSDavid du Colombier * ensuring no file operations are occurring concurrently. 965e96a66cSDavid du Colombier */ 975e96a66cSDavid du Colombier VtLock *elk; /* epoch lock */ 985e96a66cSDavid du Colombier u32int ehi; /* epoch high */ 995e96a66cSDavid du Colombier u32int elo; /* epoch low */ 1005e96a66cSDavid du Colombier 10181cf8742SDavid du Colombier int halted; /* epoch lock is held to halt (console initiated) */ 10281cf8742SDavid du Colombier 1035e96a66cSDavid du Colombier Source *source; /* immutable: root of sources */ 1045e96a66cSDavid du Colombier File *file; /* immutable: root of files */ 1055e96a66cSDavid du Colombier }; 1065e96a66cSDavid du Colombier 1075e96a66cSDavid du Colombier /* 1085e96a66cSDavid du Colombier * variant on VtEntry 1095e96a66cSDavid du Colombier * there are extra fields when stored locally 1105e96a66cSDavid du Colombier */ 1115e96a66cSDavid du Colombier struct Entry { 1125e96a66cSDavid du Colombier u32int gen; /* generation number */ 1135e96a66cSDavid du Colombier ushort psize; /* pointer block size */ 1145e96a66cSDavid du Colombier ushort dsize; /* data block size */ 1155e96a66cSDavid du Colombier uchar depth; /* unpacked from flags */ 1165e96a66cSDavid du Colombier uchar flags; 1175e96a66cSDavid du Colombier uvlong size; 1185e96a66cSDavid du Colombier uchar score[VtScoreSize]; 1195e96a66cSDavid du Colombier u32int tag; /* tag for local blocks: zero if stored on Venti */ 12000580da5SDavid du Colombier u32int snap; /* non-zero -> entering snapshot of given epoch */ 1215e96a66cSDavid du Colombier uchar archive; /* archive this snapshot: only valid for snap != 0 */ 1225e96a66cSDavid du Colombier }; 1235e96a66cSDavid du Colombier 12400580da5SDavid du Colombier /* 12500580da5SDavid du Colombier * This is called a `stream' in the fossil paper. There used to be Sinks too. 12600580da5SDavid du Colombier * We believe that Sources and Files are one-to-one. 12700580da5SDavid du Colombier */ 1285e96a66cSDavid du Colombier struct Source { 1295e96a66cSDavid du Colombier Fs *fs; /* immutable */ 1305e96a66cSDavid du Colombier int mode; /* immutable */ 13157195852SDavid du Colombier int issnapshot; /* immutable */ 1325e96a66cSDavid du Colombier u32int gen; /* immutable */ 1335e96a66cSDavid du Colombier int dsize; /* immutable */ 1345e96a66cSDavid du Colombier int dir; /* immutable */ 1355e96a66cSDavid du Colombier 1365e96a66cSDavid du Colombier Source *parent; /* immutable */ 1370c6300e7SDavid du Colombier File *file; /* immutable; point back */ 1385e96a66cSDavid du Colombier 1395e96a66cSDavid du Colombier VtLock *lk; 1405e96a66cSDavid du Colombier int ref; 1415e96a66cSDavid du Colombier /* 1425e96a66cSDavid du Colombier * epoch for the source 1435e96a66cSDavid du Colombier * for ReadWrite sources, epoch is used to lazily notice 1445e96a66cSDavid du Colombier * sources that must be split from the snapshots. 1455e96a66cSDavid du Colombier * for ReadOnly sources, the epoch represents the minimum epoch 1465e96a66cSDavid du Colombier * along the chain from the root, and is used to lazily notice 1475e96a66cSDavid du Colombier * sources that have become invalid because they belong to an old 1485e96a66cSDavid du Colombier * snapshot. 1495e96a66cSDavid du Colombier */ 1505e96a66cSDavid du Colombier u32int epoch; 1515e96a66cSDavid du Colombier Block *b; /* block containing this source */ 1525e96a66cSDavid du Colombier uchar score[VtScoreSize]; /* score of block containing this source */ 1535e96a66cSDavid du Colombier u32int scoreEpoch; /* epoch of block containing this source */ 1545e96a66cSDavid du Colombier int epb; /* immutable: entries per block in parent */ 1555e96a66cSDavid du Colombier u32int tag; /* immutable: tag of parent */ 1565e96a66cSDavid du Colombier u32int offset; /* immutable: entry offset in parent */ 1575e96a66cSDavid du Colombier }; 1585e96a66cSDavid du Colombier 1595e96a66cSDavid du Colombier 1605e96a66cSDavid du Colombier struct Header { 1615e96a66cSDavid du Colombier ushort version; 1625e96a66cSDavid du Colombier ushort blockSize; 1635e96a66cSDavid du Colombier ulong super; /* super blocks */ 1645e96a66cSDavid du Colombier ulong label; /* start of labels */ 1655e96a66cSDavid du Colombier ulong data; /* end of labels - start of data blocks */ 1665e96a66cSDavid du Colombier ulong end; /* end of data blocks */ 1675e96a66cSDavid du Colombier }; 1685e96a66cSDavid du Colombier 1695e96a66cSDavid du Colombier /* 1705e96a66cSDavid du Colombier * contains a one block buffer 1715e96a66cSDavid du Colombier * to avoid problems of the block changing underfoot 1725e96a66cSDavid du Colombier * and to enable an interface that supports unget. 1735e96a66cSDavid du Colombier */ 1745e96a66cSDavid du Colombier struct DirEntryEnum { 1755e96a66cSDavid du Colombier File *file; 1765e96a66cSDavid du Colombier 1775e96a66cSDavid du Colombier u32int boff; /* block offset */ 1785e96a66cSDavid du Colombier 1795e96a66cSDavid du Colombier int i, n; 1805e96a66cSDavid du Colombier DirEntry *buf; 1815e96a66cSDavid du Colombier }; 1825e96a66cSDavid du Colombier 183e569ccb5SDavid du Colombier /* Block states */ 1845e96a66cSDavid du Colombier enum { 1855e96a66cSDavid du Colombier BsFree = 0, /* available for allocation */ 1865e96a66cSDavid du Colombier BsBad = 0xFF, /* something is wrong with this block */ 1875e96a66cSDavid du Colombier 1885e96a66cSDavid du Colombier /* bit fields */ 1895e96a66cSDavid du Colombier BsAlloc = 1<<0, /* block is in use */ 190e569ccb5SDavid du Colombier BsCopied = 1<<1,/* block has been copied (usually in preparation for unlink) */ 1915e96a66cSDavid du Colombier BsVenti = 1<<2, /* block has been stored on Venti */ 192e569ccb5SDavid du Colombier BsClosed = 1<<3,/* block has been unlinked on disk from active file system */ 1935e96a66cSDavid du Colombier BsMask = BsAlloc|BsCopied|BsVenti|BsClosed, 1945e96a66cSDavid du Colombier }; 1955e96a66cSDavid du Colombier 1965e96a66cSDavid du Colombier /* 1975e96a66cSDavid du Colombier * block types 1985e96a66cSDavid du Colombier * more regular than Venti block types 1995e96a66cSDavid du Colombier * bit 3 -> block or data block 2005e96a66cSDavid du Colombier * bits 2-0 -> level of block 2015e96a66cSDavid du Colombier */ 2025e96a66cSDavid du Colombier enum { 2035e96a66cSDavid du Colombier BtData, 2045e96a66cSDavid du Colombier BtDir = 1<<3, 2055e96a66cSDavid du Colombier BtLevelMask = 7, 2065e96a66cSDavid du Colombier BtMax = 1<<4, 2075e96a66cSDavid du Colombier }; 2085e96a66cSDavid du Colombier 2095e96a66cSDavid du Colombier /* io states */ 2105e96a66cSDavid du Colombier enum { 2115e96a66cSDavid du Colombier BioEmpty, /* label & data are not valid */ 2125e96a66cSDavid du Colombier BioLabel, /* label is good */ 2135e96a66cSDavid du Colombier BioClean, /* data is on the disk */ 2145e96a66cSDavid du Colombier BioDirty, /* data is not yet on the disk */ 2155e96a66cSDavid du Colombier BioReading, /* in process of reading data */ 2165e96a66cSDavid du Colombier BioWriting, /* in process of writing data */ 2175e96a66cSDavid du Colombier BioReadError, /* error reading: assume disk always handles write errors */ 2185e96a66cSDavid du Colombier BioVentiError, /* error reading from venti (probably disconnected) */ 2195e96a66cSDavid du Colombier BioMax 2205e96a66cSDavid du Colombier }; 2215e96a66cSDavid du Colombier 2225e96a66cSDavid du Colombier struct Label { 2235e96a66cSDavid du Colombier uchar type; 2245e96a66cSDavid du Colombier uchar state; 2255e96a66cSDavid du Colombier u32int tag; 2265e96a66cSDavid du Colombier u32int epoch; 2275e96a66cSDavid du Colombier u32int epochClose; 2285e96a66cSDavid du Colombier }; 2295e96a66cSDavid du Colombier 2305e96a66cSDavid du Colombier struct Block { 2315e96a66cSDavid du Colombier Cache *c; 2325e96a66cSDavid du Colombier int ref; 2335e96a66cSDavid du Colombier int nlock; 23474f16c81SDavid du Colombier uintptr pc; /* pc that fetched this block from the cache */ 2355e96a66cSDavid du Colombier 2365e96a66cSDavid du Colombier VtLock *lk; 2375e96a66cSDavid du Colombier 2385e96a66cSDavid du Colombier int part; 2395e96a66cSDavid du Colombier u32int addr; 2405e96a66cSDavid du Colombier uchar score[VtScoreSize]; /* score */ 2415e96a66cSDavid du Colombier Label l; 2425e96a66cSDavid du Colombier 24361201b97SDavid du Colombier uchar *dmap; 24461201b97SDavid du Colombier 2455e96a66cSDavid du Colombier uchar *data; 2465e96a66cSDavid du Colombier 2475e96a66cSDavid du Colombier /* the following is private; used by cache */ 2485e96a66cSDavid du Colombier 2495e96a66cSDavid du Colombier Block *next; /* doubly linked hash chains */ 2505e96a66cSDavid du Colombier Block **prev; 2515e96a66cSDavid du Colombier u32int heap; /* index in heap table */ 2525e96a66cSDavid du Colombier u32int used; /* last reference times */ 2535e96a66cSDavid du Colombier 2545e96a66cSDavid du Colombier u32int vers; /* version of dirty flag */ 2555e96a66cSDavid du Colombier 2565e96a66cSDavid du Colombier BList *uhead; /* blocks to unlink when this block is written */ 2575e96a66cSDavid du Colombier BList *utail; 2585e96a66cSDavid du Colombier 2595e96a66cSDavid du Colombier /* block ordering for cache -> disk */ 2605e96a66cSDavid du Colombier BList *prior; /* list of blocks before this one */ 2615e96a66cSDavid du Colombier 2625e96a66cSDavid du Colombier Block *ionext; 2635e96a66cSDavid du Colombier int iostate; 2645e96a66cSDavid du Colombier VtRendez *ioready; 2655e96a66cSDavid du Colombier }; 2665e96a66cSDavid du Colombier 2675e96a66cSDavid du Colombier /* tree walker, for gc and archiver */ 2685e96a66cSDavid du Colombier struct WalkPtr 2695e96a66cSDavid du Colombier { 2705e96a66cSDavid du Colombier uchar *data; 2715e96a66cSDavid du Colombier int isEntry; 2725e96a66cSDavid du Colombier int n; 2735e96a66cSDavid du Colombier int m; 2745e96a66cSDavid du Colombier Entry e; 2755e96a66cSDavid du Colombier uchar type; 2765e96a66cSDavid du Colombier u32int tag; 2775e96a66cSDavid du Colombier }; 2785e96a66cSDavid du Colombier 279e569ccb5SDavid du Colombier enum 280e569ccb5SDavid du Colombier { 281e569ccb5SDavid du Colombier DoClose = 1<<0, 282e569ccb5SDavid du Colombier DoClre = 1<<1, 283e569ccb5SDavid du Colombier DoClri = 1<<2, 284e569ccb5SDavid du Colombier DoClrp = 1<<3, 285e569ccb5SDavid du Colombier }; 286e569ccb5SDavid du Colombier 287e569ccb5SDavid du Colombier struct Fsck 288e569ccb5SDavid du Colombier { 289e569ccb5SDavid du Colombier /* filled in by caller */ 290e569ccb5SDavid du Colombier int printblocks; 291e569ccb5SDavid du Colombier int useventi; 292e569ccb5SDavid du Colombier int flags; 293e569ccb5SDavid du Colombier int printdirs; 294e569ccb5SDavid du Colombier int printfiles; 295e569ccb5SDavid du Colombier int walksnapshots; 296e569ccb5SDavid du Colombier int walkfs; 297e569ccb5SDavid du Colombier Fs *fs; 298e569ccb5SDavid du Colombier int (*print)(char*, ...); 299e569ccb5SDavid du Colombier void (*clre)(Fsck*, Block*, int); 300e569ccb5SDavid du Colombier void (*clrp)(Fsck*, Block*, int); 301e569ccb5SDavid du Colombier void (*close)(Fsck*, Block*, u32int); 302e569ccb5SDavid du Colombier void (*clri)(Fsck*, char*, MetaBlock*, int, Block*); 303e569ccb5SDavid du Colombier 304e569ccb5SDavid du Colombier /* used internally */ 305e569ccb5SDavid du Colombier Cache *cache; 306e569ccb5SDavid du Colombier uchar *amap; /* all blocks seen so far */ 307e569ccb5SDavid du Colombier uchar *emap; /* all blocks seen in this epoch */ 308e569ccb5SDavid du Colombier uchar *xmap; /* all blocks in this epoch with parents in this epoch */ 309e569ccb5SDavid du Colombier uchar *errmap; /* blocks with errors */ 310e569ccb5SDavid du Colombier uchar *smap; /* walked sources */ 311e569ccb5SDavid du Colombier int nblocks; 312e569ccb5SDavid du Colombier int bsize; 313e569ccb5SDavid du Colombier int walkdepth; 314e569ccb5SDavid du Colombier u32int hint; /* where the next root probably is */ 315e569ccb5SDavid du Colombier int nseen; 316e569ccb5SDavid du Colombier int quantum; 317e569ccb5SDavid du Colombier int nclre; 318e569ccb5SDavid du Colombier int nclrp; 319e569ccb5SDavid du Colombier int nclose; 320e569ccb5SDavid du Colombier int nclri; 321e569ccb5SDavid du Colombier }; 322e569ccb5SDavid du Colombier 323f6333ca0SDavid du Colombier /* disk partitions; keep in sync with partname[] in disk.c */ 3245e96a66cSDavid du Colombier enum { 3255e96a66cSDavid du Colombier PartError, 3265e96a66cSDavid du Colombier PartSuper, 3275e96a66cSDavid du Colombier PartLabel, 3285e96a66cSDavid du Colombier PartData, 3295e96a66cSDavid du Colombier PartVenti, /* fake partition */ 3305e96a66cSDavid du Colombier }; 3315e96a66cSDavid du Colombier 3325e96a66cSDavid du Colombier extern vtType[BtMax]; 333