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; 75e96a66cSDavid du Colombier typedef struct Header Header; 85e96a66cSDavid du Colombier typedef struct Label Label; 95e96a66cSDavid du Colombier typedef struct Periodic Periodic; 105e96a66cSDavid du Colombier typedef struct Snap Snap; 115e96a66cSDavid du Colombier typedef struct Source Source; 125e96a66cSDavid du Colombier typedef struct Super Super; 135e96a66cSDavid du Colombier typedef struct WalkPtr WalkPtr; 145e96a66cSDavid du Colombier 155e96a66cSDavid du Colombier /* tuneable parameters - probably should not be constants */ 165e96a66cSDavid du Colombier enum { 175e96a66cSDavid du Colombier BytesPerEntry = 100, /* estimate of bytes per dir entries - determines number of index entries in the block */ 185e96a66cSDavid du Colombier FullPercentage = 80, /* don't allocate in block if more than this percentage full */ 195e96a66cSDavid du Colombier FlushSize = 200, /* number of blocks to flush */ 205e96a66cSDavid du Colombier DirtyPercentage = 50, /* maximum percentage of dirty blocks */ 215e96a66cSDavid du Colombier }; 225e96a66cSDavid du Colombier 235e96a66cSDavid du Colombier enum { 245e96a66cSDavid du Colombier NilBlock = (~0UL), 255e96a66cSDavid du Colombier MaxBlock = (1UL<<31), 265e96a66cSDavid du Colombier }; 275e96a66cSDavid du Colombier 285e96a66cSDavid du Colombier enum { 295e96a66cSDavid du Colombier HeaderMagic = 0x3776ae89, 305e96a66cSDavid du Colombier HeaderVersion = 1, 315e96a66cSDavid du Colombier HeaderOffset = 128*1024, 325e96a66cSDavid du Colombier HeaderSize = 512, 335e96a66cSDavid du Colombier SuperMagic = 0x2340a3b1, 345e96a66cSDavid du Colombier SuperSize = 512, 355e96a66cSDavid du Colombier SuperVersion = 1, 365e96a66cSDavid du Colombier LabelSize = 14, 375e96a66cSDavid du Colombier }; 385e96a66cSDavid du Colombier 395e96a66cSDavid du Colombier /* well known tags */ 405e96a66cSDavid du Colombier enum { 415e96a66cSDavid du Colombier BadTag = 0, /* this tag should not be used */ 425e96a66cSDavid du Colombier RootTag = 1, /* root of fs */ 435e96a66cSDavid du Colombier EnumTag, /* root of a dir listing */ 445e96a66cSDavid du Colombier UserTag = 32, /* all other tags should be >= UserTag */ 455e96a66cSDavid du Colombier }; 465e96a66cSDavid du Colombier 475e96a66cSDavid du Colombier struct Super { 485e96a66cSDavid du Colombier u16int version; 495e96a66cSDavid du Colombier u32int epochLow; 505e96a66cSDavid du Colombier u32int epochHigh; 515e96a66cSDavid du Colombier u64int qid; /* next qid */ 525e96a66cSDavid du Colombier u32int active; /* root of active file system */ 535e96a66cSDavid du Colombier u32int next; /* root of next snapshot to archive */ 545e96a66cSDavid du Colombier u32int current; /* root of snapshot currently archiving */ 555e96a66cSDavid du Colombier uchar last[VtScoreSize]; /* last snapshot successfully archived */ 565e96a66cSDavid du Colombier char name[128]; /* label */ 575e96a66cSDavid du Colombier }; 585e96a66cSDavid du Colombier 595e96a66cSDavid du Colombier 605e96a66cSDavid du Colombier struct Fs { 615e96a66cSDavid du Colombier Arch *arch; /* immutable */ 625e96a66cSDavid du Colombier Cache *cache; /* immutable */ 635e96a66cSDavid du Colombier int mode; /* immutable */ 645e96a66cSDavid du Colombier int blockSize; /* immutable */ 655e96a66cSDavid du Colombier VtSession *z; /* immutable */ 665e96a66cSDavid du Colombier Snap *snap; /* immutable */ 675e96a66cSDavid du Colombier 685e96a66cSDavid du Colombier Periodic *metaFlush; /* periodically flushes meta data cached in files */ 695e96a66cSDavid du Colombier 705e96a66cSDavid du Colombier /* 715e96a66cSDavid du Colombier * epoch lock. 725e96a66cSDavid du Colombier * Most operations on the fs require a read lock of elk, ensuring that 735e96a66cSDavid du Colombier * the current high and low epochs do not change under foot. 745e96a66cSDavid du Colombier * This lock is mostly acquired via a call to fileLock or fileRlock. 755e96a66cSDavid du Colombier * Deletion and creation of snapshots occurs under a write lock of elk, 765e96a66cSDavid du Colombier * ensuring no file operations are occurring concurrently. 775e96a66cSDavid du Colombier */ 785e96a66cSDavid du Colombier VtLock *elk; /* epoch lock */ 795e96a66cSDavid du Colombier u32int ehi; /* epoch high */ 805e96a66cSDavid du Colombier u32int elo; /* epoch low */ 815e96a66cSDavid du Colombier 82*81cf8742SDavid du Colombier int halted; /* epoch lock is held to halt (console initiated) */ 83*81cf8742SDavid du Colombier 845e96a66cSDavid du Colombier Source *source; /* immutable: root of sources */ 855e96a66cSDavid du Colombier File *file; /* immutable: root of files */ 865e96a66cSDavid du Colombier }; 875e96a66cSDavid du Colombier 885e96a66cSDavid du Colombier /* 895e96a66cSDavid du Colombier * variant on VtEntry 905e96a66cSDavid du Colombier * there are extra fields when stored locally 915e96a66cSDavid du Colombier */ 925e96a66cSDavid du Colombier struct Entry { 935e96a66cSDavid du Colombier u32int gen; /* generation number */ 945e96a66cSDavid du Colombier ushort psize; /* pointer block size */ 955e96a66cSDavid du Colombier ushort dsize; /* data block size */ 965e96a66cSDavid du Colombier uchar depth; /* unpacked from flags */ 975e96a66cSDavid du Colombier uchar flags; 985e96a66cSDavid du Colombier uvlong size; 995e96a66cSDavid du Colombier uchar score[VtScoreSize]; 1005e96a66cSDavid du Colombier u32int tag; /* tag for local blocks: zero if stored on Venti */ 1015e96a66cSDavid du Colombier u32int snap; /* non zero -> entering snapshot of given epoch */ 1025e96a66cSDavid du Colombier uchar archive; /* archive this snapshot: only valid for snap != 0 */ 1035e96a66cSDavid du Colombier }; 1045e96a66cSDavid du Colombier 1055e96a66cSDavid du Colombier struct Source { 1065e96a66cSDavid du Colombier Fs *fs; /* immutable */ 1075e96a66cSDavid du Colombier int mode; /* immutable */ 1085e96a66cSDavid du Colombier u32int gen; /* immutable */ 1095e96a66cSDavid du Colombier int dsize; /* immutable */ 1105e96a66cSDavid du Colombier int dir; /* immutable */ 1115e96a66cSDavid du Colombier 1125e96a66cSDavid du Colombier Source *parent; /* immutable */ 1135e96a66cSDavid du Colombier 1145e96a66cSDavid du Colombier VtLock *lk; 1155e96a66cSDavid du Colombier int ref; 1165e96a66cSDavid du Colombier /* 1175e96a66cSDavid du Colombier * epoch for the source 1185e96a66cSDavid du Colombier * for ReadWrite sources, epoch is used to lazily notice 1195e96a66cSDavid du Colombier * sources that must be split from the snapshots. 1205e96a66cSDavid du Colombier * for ReadOnly sources, the epoch represents the minimum epoch 1215e96a66cSDavid du Colombier * along the chain from the root, and is used to lazily notice 1225e96a66cSDavid du Colombier * sources that have become invalid because they belong to an old 1235e96a66cSDavid du Colombier * snapshot. 1245e96a66cSDavid du Colombier */ 1255e96a66cSDavid du Colombier u32int epoch; 1265e96a66cSDavid du Colombier Block *b; /* block containing this source */ 1275e96a66cSDavid du Colombier uchar score[VtScoreSize]; /* score of block containing this source */ 1285e96a66cSDavid du Colombier u32int scoreEpoch; /* epoch of block containing this source */ 1295e96a66cSDavid du Colombier int epb; /* immutable: entries per block in parent */ 1305e96a66cSDavid du Colombier u32int tag; /* immutable: tag of parent */ 1315e96a66cSDavid du Colombier u32int offset; /* immutable: entry offset in parent */ 1325e96a66cSDavid du Colombier }; 1335e96a66cSDavid du Colombier 1345e96a66cSDavid du Colombier 1355e96a66cSDavid du Colombier struct Header { 1365e96a66cSDavid du Colombier ushort version; 1375e96a66cSDavid du Colombier ushort blockSize; 1385e96a66cSDavid du Colombier ulong super; /* super blocks */ 1395e96a66cSDavid du Colombier ulong label; /* start of labels */ 1405e96a66cSDavid du Colombier ulong data; /* end of labels - start of data blocks */ 1415e96a66cSDavid du Colombier ulong end; /* end of data blocks */ 1425e96a66cSDavid du Colombier }; 1435e96a66cSDavid du Colombier 1445e96a66cSDavid du Colombier /* 1455e96a66cSDavid du Colombier * contains a one block buffer 1465e96a66cSDavid du Colombier * to avoid problems of the block changing underfoot 1475e96a66cSDavid du Colombier * and to enable an interface that supports unget. 1485e96a66cSDavid du Colombier */ 1495e96a66cSDavid du Colombier struct DirEntryEnum { 1505e96a66cSDavid du Colombier File *file; 1515e96a66cSDavid du Colombier 1525e96a66cSDavid du Colombier u32int boff; /* block offset */ 1535e96a66cSDavid du Colombier 1545e96a66cSDavid du Colombier int i, n; 1555e96a66cSDavid du Colombier DirEntry *buf; 1565e96a66cSDavid du Colombier }; 1575e96a66cSDavid du Colombier 1585e96a66cSDavid du Colombier /* Block states; two orthogonal fields, Bv* and Ba* */ 1595e96a66cSDavid du Colombier enum { 1605e96a66cSDavid du Colombier BsFree = 0, /* available for allocation */ 1615e96a66cSDavid du Colombier BsBad = 0xFF, /* something is wrong with this block */ 1625e96a66cSDavid du Colombier 1635e96a66cSDavid du Colombier /* bit fields */ 1645e96a66cSDavid du Colombier BsAlloc = 1<<0, /* block is in use */ 1655e96a66cSDavid du Colombier BsCopied = 1<<1, /* block has been copied */ 1665e96a66cSDavid du Colombier BsVenti = 1<<2, /* block has been stored on Venti */ 1675e96a66cSDavid du Colombier BsClosed = 1<<3, /* block has been unlinked from active file system */ 1685e96a66cSDavid du Colombier BsMask = BsAlloc|BsCopied|BsVenti|BsClosed, 1695e96a66cSDavid du Colombier }; 1705e96a66cSDavid du Colombier 1715e96a66cSDavid du Colombier /* 1725e96a66cSDavid du Colombier * Each block has a state and generation 1735e96a66cSDavid du Colombier * The following invariants are maintained 1745e96a66cSDavid du Colombier * Each block has no more than than one parent per generation 1755e96a66cSDavid du Colombier * For Active*, no child has a parent of a greater generation 1765e96a66cSDavid du Colombier * For Snap*, there is a snap parent of given generation and there are 1775e96a66cSDavid du Colombier * no parents of greater gen - implies no children snaps 1785e96a66cSDavid du Colombier * of a lesser gen 1795e96a66cSDavid du Colombier * For *RO, the block is fixed - no change can be made - all pointers 1805e96a66cSDavid du Colombier * are valid venti addresses 1815e96a66cSDavid du Colombier * For *A, the block is on the venti server 1825e96a66cSDavid du Colombier * There are no pointers to Zombie blocks 1835e96a66cSDavid du Colombier * 1845e96a66cSDavid du Colombier * Transitions 1855e96a66cSDavid du Colombier * Archiver at generation g 1865e96a66cSDavid du Colombier * Mutator at generation h 1875e96a66cSDavid du Colombier * 1885e96a66cSDavid du Colombier * Want to modify a block 1895e96a66cSDavid du Colombier * Venti: create new Active(h) 1905e96a66cSDavid du Colombier * Active(x): x == h: do nothing 1915e96a66cSDavid du Colombier * Active(x): x < h: change to Snap(h-1) + add Active(h) 1925e96a66cSDavid du Colombier * ActiveRO(x): change to SnapRO(h-1) + add Active(h) 1935e96a66cSDavid du Colombier * ActiveA(x): add Active(h) 1945e96a66cSDavid du Colombier * Snap*(x): should not occur 1955e96a66cSDavid du Colombier * Zombie(x): should not occur 1965e96a66cSDavid du Colombier * Want to archive 1975e96a66cSDavid du Colombier * Active(x): x != g: should never happen 1985e96a66cSDavid du Colombier * Active(x): x == g fix children and free them: move to ActiveRO(g); 1995e96a66cSDavid du Colombier * ActiveRO(x): x != g: should never happen 2005e96a66cSDavid du Colombier * ActiveRO(x): x == g: wait until it hits ActiveA or SnapA 2015e96a66cSDavid du Colombier * ActiveA(x): done 2025e96a66cSDavid du Colombier * Snap(x): x < g: should never happen 2035e96a66cSDavid du Colombier * Snap(x): x >= g: fix children, freeing all SnapA(y) x == y; 2045e96a66cSDavid du Colombier * SnapRO(x): wait until it hits SnapA 2055e96a66cSDavid du Colombier * 2065e96a66cSDavid du Colombier */ 2075e96a66cSDavid du Colombier 2085e96a66cSDavid du Colombier /* 2095e96a66cSDavid du Colombier * block types 2105e96a66cSDavid du Colombier * more regular than Venti block types 2115e96a66cSDavid du Colombier * bit 3 -> block or data block 2125e96a66cSDavid du Colombier * bits 2-0 -> level of block 2135e96a66cSDavid du Colombier */ 2145e96a66cSDavid du Colombier enum { 2155e96a66cSDavid du Colombier BtData, 2165e96a66cSDavid du Colombier BtDir = 1<<3, 2175e96a66cSDavid du Colombier BtLevelMask = 7, 2185e96a66cSDavid du Colombier BtMax = 1<<4, 2195e96a66cSDavid du Colombier }; 2205e96a66cSDavid du Colombier 2215e96a66cSDavid du Colombier /* io states */ 2225e96a66cSDavid du Colombier enum { 2235e96a66cSDavid du Colombier BioEmpty, /* label & data are not valid */ 2245e96a66cSDavid du Colombier BioLabel, /* label is good */ 2255e96a66cSDavid du Colombier BioClean, /* data is on the disk */ 2265e96a66cSDavid du Colombier BioDirty, /* data is not yet on the disk */ 2275e96a66cSDavid du Colombier BioReading, /* in process of reading data */ 2285e96a66cSDavid du Colombier BioWriting, /* in process of writing data */ 2295e96a66cSDavid du Colombier BioReadError, /* error reading: assume disk always handles write errors */ 2305e96a66cSDavid du Colombier BioVentiError, /* error reading from venti (probably disconnected) */ 2315e96a66cSDavid du Colombier BioMax 2325e96a66cSDavid du Colombier }; 2335e96a66cSDavid du Colombier 2345e96a66cSDavid du Colombier struct Label { 2355e96a66cSDavid du Colombier uchar type; 2365e96a66cSDavid du Colombier uchar state; 2375e96a66cSDavid du Colombier u32int tag; 2385e96a66cSDavid du Colombier u32int epoch; 2395e96a66cSDavid du Colombier u32int epochClose; 2405e96a66cSDavid du Colombier }; 2415e96a66cSDavid du Colombier 2425e96a66cSDavid du Colombier struct Block { 2435e96a66cSDavid du Colombier Cache *c; 2445e96a66cSDavid du Colombier int ref; 2455e96a66cSDavid du Colombier int nlock; 2465e96a66cSDavid du Colombier ulong pc; /* pc that fetched this block from the cache */ 2475e96a66cSDavid du Colombier 2485e96a66cSDavid du Colombier VtLock *lk; 2495e96a66cSDavid du Colombier 2505e96a66cSDavid du Colombier int part; 2515e96a66cSDavid du Colombier u32int addr; 2525e96a66cSDavid du Colombier uchar score[VtScoreSize]; /* score */ 2535e96a66cSDavid du Colombier Label l; 2545e96a66cSDavid du Colombier 25561201b97SDavid du Colombier uchar *dmap; 25661201b97SDavid du Colombier 2575e96a66cSDavid du Colombier uchar *data; 2585e96a66cSDavid du Colombier 2595e96a66cSDavid du Colombier /* the following is private; used by cache */ 2605e96a66cSDavid du Colombier 2615e96a66cSDavid du Colombier Block *next; /* doubly linked hash chains */ 2625e96a66cSDavid du Colombier Block **prev; 2635e96a66cSDavid du Colombier u32int heap; /* index in heap table */ 2645e96a66cSDavid du Colombier u32int used; /* last reference times */ 2655e96a66cSDavid du Colombier 2665e96a66cSDavid du Colombier u32int vers; /* version of dirty flag */ 2675e96a66cSDavid du Colombier 2685e96a66cSDavid du Colombier BList *uhead; /* blocks to unlink when this block is written */ 2695e96a66cSDavid du Colombier BList *utail; 2705e96a66cSDavid du Colombier 2715e96a66cSDavid du Colombier /* block ordering for cache -> disk */ 2725e96a66cSDavid du Colombier BList *prior; /* list of blocks before this one */ 2735e96a66cSDavid du Colombier 2745e96a66cSDavid du Colombier Block *ionext; 2755e96a66cSDavid du Colombier int iostate; 2765e96a66cSDavid du Colombier VtRendez *ioready; 2775e96a66cSDavid du Colombier }; 2785e96a66cSDavid du Colombier 2795e96a66cSDavid du Colombier /* tree walker, for gc and archiver */ 2805e96a66cSDavid du Colombier struct WalkPtr 2815e96a66cSDavid du Colombier { 2825e96a66cSDavid du Colombier uchar *data; 2835e96a66cSDavid du Colombier int isEntry; 2845e96a66cSDavid du Colombier int n; 2855e96a66cSDavid du Colombier int m; 2865e96a66cSDavid du Colombier Entry e; 2875e96a66cSDavid du Colombier uchar type; 2885e96a66cSDavid du Colombier u32int tag; 2895e96a66cSDavid du Colombier }; 2905e96a66cSDavid du Colombier 2915e96a66cSDavid du Colombier /* disk partitions */ 2925e96a66cSDavid du Colombier enum { 2935e96a66cSDavid du Colombier PartError, 2945e96a66cSDavid du Colombier PartSuper, 2955e96a66cSDavid du Colombier PartLabel, 2965e96a66cSDavid du Colombier PartData, 2975e96a66cSDavid du Colombier PartVenti, /* fake partition */ 2985e96a66cSDavid du Colombier }; 2995e96a66cSDavid du Colombier 3005e96a66cSDavid du Colombier extern vtType[BtMax]; 301