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 235e96a66cSDavid du Colombier /* tuneable parameters - probably should not be constants */ 245e96a66cSDavid du Colombier enum { 255e96a66cSDavid du Colombier BytesPerEntry = 100, /* estimate of bytes per dir entries - determines number of index entries in the block */ 265e96a66cSDavid du Colombier FullPercentage = 80, /* don't allocate in block if more than this percentage full */ 275e96a66cSDavid du Colombier FlushSize = 200, /* number of blocks to flush */ 285e96a66cSDavid du Colombier DirtyPercentage = 50, /* maximum percentage of dirty blocks */ 295e96a66cSDavid du Colombier }; 305e96a66cSDavid du Colombier 315e96a66cSDavid du Colombier enum { 325e96a66cSDavid du Colombier NilBlock = (~0UL), 335e96a66cSDavid du Colombier MaxBlock = (1UL<<31), 345e96a66cSDavid du Colombier }; 355e96a66cSDavid du Colombier 365e96a66cSDavid du Colombier enum { 375e96a66cSDavid du Colombier HeaderMagic = 0x3776ae89, 385e96a66cSDavid du Colombier HeaderVersion = 1, 395e96a66cSDavid du Colombier HeaderOffset = 128*1024, 405e96a66cSDavid du Colombier HeaderSize = 512, 415e96a66cSDavid du Colombier SuperMagic = 0x2340a3b1, 425e96a66cSDavid du Colombier SuperSize = 512, 435e96a66cSDavid du Colombier SuperVersion = 1, 445e96a66cSDavid du Colombier LabelSize = 14, 455e96a66cSDavid du Colombier }; 465e96a66cSDavid du Colombier 475e96a66cSDavid du Colombier /* well known tags */ 485e96a66cSDavid du Colombier enum { 495e96a66cSDavid du Colombier BadTag = 0, /* this tag should not be used */ 505e96a66cSDavid du Colombier RootTag = 1, /* root of fs */ 515e96a66cSDavid du Colombier EnumTag, /* root of a dir listing */ 525e96a66cSDavid du Colombier UserTag = 32, /* all other tags should be >= UserTag */ 535e96a66cSDavid du Colombier }; 545e96a66cSDavid du Colombier 555e96a66cSDavid du Colombier struct Super { 565e96a66cSDavid du Colombier u16int version; 575e96a66cSDavid du Colombier u32int epochLow; 585e96a66cSDavid du Colombier u32int epochHigh; 595e96a66cSDavid du Colombier u64int qid; /* next qid */ 605e96a66cSDavid du Colombier u32int active; /* root of active file system */ 615e96a66cSDavid du Colombier u32int next; /* root of next snapshot to archive */ 625e96a66cSDavid du Colombier u32int current; /* root of snapshot currently archiving */ 635e96a66cSDavid du Colombier uchar last[VtScoreSize]; /* last snapshot successfully archived */ 645e96a66cSDavid du Colombier char name[128]; /* label */ 655e96a66cSDavid du Colombier }; 665e96a66cSDavid du Colombier 675e96a66cSDavid du Colombier 685e96a66cSDavid du Colombier struct Fs { 695e96a66cSDavid du Colombier Arch *arch; /* immutable */ 705e96a66cSDavid du Colombier Cache *cache; /* immutable */ 715e96a66cSDavid du Colombier int mode; /* immutable */ 725e96a66cSDavid du Colombier int blockSize; /* immutable */ 735e96a66cSDavid du Colombier VtSession *z; /* immutable */ 745e96a66cSDavid du Colombier Snap *snap; /* immutable */ 755e96a66cSDavid du Colombier 765e96a66cSDavid du Colombier Periodic *metaFlush; /* periodically flushes meta data cached in files */ 775e96a66cSDavid du Colombier 785e96a66cSDavid du Colombier /* 795e96a66cSDavid du Colombier * epoch lock. 805e96a66cSDavid du Colombier * Most operations on the fs require a read lock of elk, ensuring that 815e96a66cSDavid du Colombier * the current high and low epochs do not change under foot. 825e96a66cSDavid du Colombier * This lock is mostly acquired via a call to fileLock or fileRlock. 835e96a66cSDavid du Colombier * Deletion and creation of snapshots occurs under a write lock of elk, 845e96a66cSDavid du Colombier * ensuring no file operations are occurring concurrently. 855e96a66cSDavid du Colombier */ 865e96a66cSDavid du Colombier VtLock *elk; /* epoch lock */ 875e96a66cSDavid du Colombier u32int ehi; /* epoch high */ 885e96a66cSDavid du Colombier u32int elo; /* epoch low */ 895e96a66cSDavid du Colombier 9081cf8742SDavid du Colombier int halted; /* epoch lock is held to halt (console initiated) */ 9181cf8742SDavid du Colombier 925e96a66cSDavid du Colombier Source *source; /* immutable: root of sources */ 935e96a66cSDavid du Colombier File *file; /* immutable: root of files */ 945e96a66cSDavid du Colombier }; 955e96a66cSDavid du Colombier 965e96a66cSDavid du Colombier /* 975e96a66cSDavid du Colombier * variant on VtEntry 985e96a66cSDavid du Colombier * there are extra fields when stored locally 995e96a66cSDavid du Colombier */ 1005e96a66cSDavid du Colombier struct Entry { 1015e96a66cSDavid du Colombier u32int gen; /* generation number */ 1025e96a66cSDavid du Colombier ushort psize; /* pointer block size */ 1035e96a66cSDavid du Colombier ushort dsize; /* data block size */ 1045e96a66cSDavid du Colombier uchar depth; /* unpacked from flags */ 1055e96a66cSDavid du Colombier uchar flags; 1065e96a66cSDavid du Colombier uvlong size; 1075e96a66cSDavid du Colombier uchar score[VtScoreSize]; 1085e96a66cSDavid du Colombier u32int tag; /* tag for local blocks: zero if stored on Venti */ 1095e96a66cSDavid du Colombier u32int snap; /* non zero -> entering snapshot of given epoch */ 1105e96a66cSDavid du Colombier uchar archive; /* archive this snapshot: only valid for snap != 0 */ 1115e96a66cSDavid du Colombier }; 1125e96a66cSDavid du Colombier 1135e96a66cSDavid du Colombier struct Source { 1145e96a66cSDavid du Colombier Fs *fs; /* immutable */ 1155e96a66cSDavid du Colombier int mode; /* immutable */ 1165e96a66cSDavid du Colombier u32int gen; /* immutable */ 1175e96a66cSDavid du Colombier int dsize; /* immutable */ 1185e96a66cSDavid du Colombier int dir; /* immutable */ 1195e96a66cSDavid du Colombier 1205e96a66cSDavid du Colombier Source *parent; /* immutable */ 1215e96a66cSDavid du Colombier 1225e96a66cSDavid du Colombier VtLock *lk; 1235e96a66cSDavid du Colombier int ref; 1245e96a66cSDavid du Colombier /* 1255e96a66cSDavid du Colombier * epoch for the source 1265e96a66cSDavid du Colombier * for ReadWrite sources, epoch is used to lazily notice 1275e96a66cSDavid du Colombier * sources that must be split from the snapshots. 1285e96a66cSDavid du Colombier * for ReadOnly sources, the epoch represents the minimum epoch 1295e96a66cSDavid du Colombier * along the chain from the root, and is used to lazily notice 1305e96a66cSDavid du Colombier * sources that have become invalid because they belong to an old 1315e96a66cSDavid du Colombier * snapshot. 1325e96a66cSDavid du Colombier */ 1335e96a66cSDavid du Colombier u32int epoch; 1345e96a66cSDavid du Colombier Block *b; /* block containing this source */ 1355e96a66cSDavid du Colombier uchar score[VtScoreSize]; /* score of block containing this source */ 1365e96a66cSDavid du Colombier u32int scoreEpoch; /* epoch of block containing this source */ 1375e96a66cSDavid du Colombier int epb; /* immutable: entries per block in parent */ 1385e96a66cSDavid du Colombier u32int tag; /* immutable: tag of parent */ 1395e96a66cSDavid du Colombier u32int offset; /* immutable: entry offset in parent */ 1405e96a66cSDavid du Colombier }; 1415e96a66cSDavid du Colombier 1425e96a66cSDavid du Colombier 1435e96a66cSDavid du Colombier struct Header { 1445e96a66cSDavid du Colombier ushort version; 1455e96a66cSDavid du Colombier ushort blockSize; 1465e96a66cSDavid du Colombier ulong super; /* super blocks */ 1475e96a66cSDavid du Colombier ulong label; /* start of labels */ 1485e96a66cSDavid du Colombier ulong data; /* end of labels - start of data blocks */ 1495e96a66cSDavid du Colombier ulong end; /* end of data blocks */ 1505e96a66cSDavid du Colombier }; 1515e96a66cSDavid du Colombier 1525e96a66cSDavid du Colombier /* 1535e96a66cSDavid du Colombier * contains a one block buffer 1545e96a66cSDavid du Colombier * to avoid problems of the block changing underfoot 1555e96a66cSDavid du Colombier * and to enable an interface that supports unget. 1565e96a66cSDavid du Colombier */ 1575e96a66cSDavid du Colombier struct DirEntryEnum { 1585e96a66cSDavid du Colombier File *file; 1595e96a66cSDavid du Colombier 1605e96a66cSDavid du Colombier u32int boff; /* block offset */ 1615e96a66cSDavid du Colombier 1625e96a66cSDavid du Colombier int i, n; 1635e96a66cSDavid du Colombier DirEntry *buf; 1645e96a66cSDavid du Colombier }; 1655e96a66cSDavid du Colombier 166e569ccb5SDavid du Colombier /* Block states */ 1675e96a66cSDavid du Colombier enum { 1685e96a66cSDavid du Colombier BsFree = 0, /* available for allocation */ 1695e96a66cSDavid du Colombier BsBad = 0xFF, /* something is wrong with this block */ 1705e96a66cSDavid du Colombier 1715e96a66cSDavid du Colombier /* bit fields */ 1725e96a66cSDavid du Colombier BsAlloc = 1<<0, /* block is in use */ 173e569ccb5SDavid du Colombier BsCopied = 1<<1, /* block has been copied (usually in preparation for unlink) */ 1745e96a66cSDavid du Colombier BsVenti = 1<<2, /* block has been stored on Venti */ 175e569ccb5SDavid du Colombier BsClosed = 1<<3, /* block has been unlinked on disk from active file system */ 1765e96a66cSDavid du Colombier BsMask = BsAlloc|BsCopied|BsVenti|BsClosed, 1775e96a66cSDavid du Colombier }; 1785e96a66cSDavid du Colombier 1795e96a66cSDavid du Colombier /* 1805e96a66cSDavid du Colombier * block types 1815e96a66cSDavid du Colombier * more regular than Venti block types 1825e96a66cSDavid du Colombier * bit 3 -> block or data block 1835e96a66cSDavid du Colombier * bits 2-0 -> level of block 1845e96a66cSDavid du Colombier */ 1855e96a66cSDavid du Colombier enum { 1865e96a66cSDavid du Colombier BtData, 1875e96a66cSDavid du Colombier BtDir = 1<<3, 1885e96a66cSDavid du Colombier BtLevelMask = 7, 1895e96a66cSDavid du Colombier BtMax = 1<<4, 1905e96a66cSDavid du Colombier }; 1915e96a66cSDavid du Colombier 1925e96a66cSDavid du Colombier /* io states */ 1935e96a66cSDavid du Colombier enum { 1945e96a66cSDavid du Colombier BioEmpty, /* label & data are not valid */ 1955e96a66cSDavid du Colombier BioLabel, /* label is good */ 1965e96a66cSDavid du Colombier BioClean, /* data is on the disk */ 1975e96a66cSDavid du Colombier BioDirty, /* data is not yet on the disk */ 1985e96a66cSDavid du Colombier BioReading, /* in process of reading data */ 1995e96a66cSDavid du Colombier BioWriting, /* in process of writing data */ 2005e96a66cSDavid du Colombier BioReadError, /* error reading: assume disk always handles write errors */ 2015e96a66cSDavid du Colombier BioVentiError, /* error reading from venti (probably disconnected) */ 2025e96a66cSDavid du Colombier BioMax 2035e96a66cSDavid du Colombier }; 2045e96a66cSDavid du Colombier 2055e96a66cSDavid du Colombier struct Label { 2065e96a66cSDavid du Colombier uchar type; 2075e96a66cSDavid du Colombier uchar state; 2085e96a66cSDavid du Colombier u32int tag; 2095e96a66cSDavid du Colombier u32int epoch; 2105e96a66cSDavid du Colombier u32int epochClose; 2115e96a66cSDavid du Colombier }; 2125e96a66cSDavid du Colombier 2135e96a66cSDavid du Colombier struct Block { 2145e96a66cSDavid du Colombier Cache *c; 2155e96a66cSDavid du Colombier int ref; 2165e96a66cSDavid du Colombier int nlock; 21774f16c81SDavid du Colombier uintptr pc; /* pc that fetched this block from the cache */ 2185e96a66cSDavid du Colombier 2195e96a66cSDavid du Colombier VtLock *lk; 2205e96a66cSDavid du Colombier 2215e96a66cSDavid du Colombier int part; 2225e96a66cSDavid du Colombier u32int addr; 2235e96a66cSDavid du Colombier uchar score[VtScoreSize]; /* score */ 2245e96a66cSDavid du Colombier Label l; 2255e96a66cSDavid du Colombier 22661201b97SDavid du Colombier uchar *dmap; 22761201b97SDavid du Colombier 2285e96a66cSDavid du Colombier uchar *data; 2295e96a66cSDavid du Colombier 2305e96a66cSDavid du Colombier /* the following is private; used by cache */ 2315e96a66cSDavid du Colombier 2325e96a66cSDavid du Colombier Block *next; /* doubly linked hash chains */ 2335e96a66cSDavid du Colombier Block **prev; 2345e96a66cSDavid du Colombier u32int heap; /* index in heap table */ 2355e96a66cSDavid du Colombier u32int used; /* last reference times */ 2365e96a66cSDavid du Colombier 2375e96a66cSDavid du Colombier u32int vers; /* version of dirty flag */ 2385e96a66cSDavid du Colombier 2395e96a66cSDavid du Colombier BList *uhead; /* blocks to unlink when this block is written */ 2405e96a66cSDavid du Colombier BList *utail; 2415e96a66cSDavid du Colombier 2425e96a66cSDavid du Colombier /* block ordering for cache -> disk */ 2435e96a66cSDavid du Colombier BList *prior; /* list of blocks before this one */ 2445e96a66cSDavid du Colombier 2455e96a66cSDavid du Colombier Block *ionext; 2465e96a66cSDavid du Colombier int iostate; 2475e96a66cSDavid du Colombier VtRendez *ioready; 2485e96a66cSDavid du Colombier }; 2495e96a66cSDavid du Colombier 2505e96a66cSDavid du Colombier /* tree walker, for gc and archiver */ 2515e96a66cSDavid du Colombier struct WalkPtr 2525e96a66cSDavid du Colombier { 2535e96a66cSDavid du Colombier uchar *data; 2545e96a66cSDavid du Colombier int isEntry; 2555e96a66cSDavid du Colombier int n; 2565e96a66cSDavid du Colombier int m; 2575e96a66cSDavid du Colombier Entry e; 2585e96a66cSDavid du Colombier uchar type; 2595e96a66cSDavid du Colombier u32int tag; 2605e96a66cSDavid du Colombier }; 2615e96a66cSDavid du Colombier 262e569ccb5SDavid du Colombier enum 263e569ccb5SDavid du Colombier { 264e569ccb5SDavid du Colombier DoClose = 1<<0, 265e569ccb5SDavid du Colombier DoClre = 1<<1, 266e569ccb5SDavid du Colombier DoClri = 1<<2, 267e569ccb5SDavid du Colombier DoClrp = 1<<3, 268e569ccb5SDavid du Colombier }; 269e569ccb5SDavid du Colombier 270e569ccb5SDavid du Colombier struct Fsck 271e569ccb5SDavid du Colombier { 272e569ccb5SDavid du Colombier /* filled in by caller */ 273e569ccb5SDavid du Colombier int printblocks; 274e569ccb5SDavid du Colombier int useventi; 275e569ccb5SDavid du Colombier int flags; 276e569ccb5SDavid du Colombier int printdirs; 277e569ccb5SDavid du Colombier int printfiles; 278e569ccb5SDavid du Colombier int walksnapshots; 279e569ccb5SDavid du Colombier int walkfs; 280e569ccb5SDavid du Colombier Fs *fs; 281e569ccb5SDavid du Colombier int (*print)(char*, ...); 282e569ccb5SDavid du Colombier void (*clre)(Fsck*, Block*, int); 283e569ccb5SDavid du Colombier void (*clrp)(Fsck*, Block*, int); 284e569ccb5SDavid du Colombier void (*close)(Fsck*, Block*, u32int); 285e569ccb5SDavid du Colombier void (*clri)(Fsck*, char*, MetaBlock*, int, Block*); 286e569ccb5SDavid du Colombier 287e569ccb5SDavid du Colombier /* used internally */ 288e569ccb5SDavid du Colombier Cache *cache; 289e569ccb5SDavid du Colombier uchar *amap; /* all blocks seen so far */ 290e569ccb5SDavid du Colombier uchar *emap; /* all blocks seen in this epoch */ 291e569ccb5SDavid du Colombier uchar *xmap; /* all blocks in this epoch with parents in this epoch */ 292e569ccb5SDavid du Colombier uchar *errmap; /* blocks with errors */ 293e569ccb5SDavid du Colombier uchar *smap; /* walked sources */ 294e569ccb5SDavid du Colombier int nblocks; 295e569ccb5SDavid du Colombier int bsize; 296e569ccb5SDavid du Colombier int walkdepth; 297e569ccb5SDavid du Colombier u32int hint; /* where the next root probably is */ 298e569ccb5SDavid du Colombier int nseen; 299e569ccb5SDavid du Colombier int quantum; 300e569ccb5SDavid du Colombier int nclre; 301e569ccb5SDavid du Colombier int nclrp; 302e569ccb5SDavid du Colombier int nclose; 303e569ccb5SDavid du Colombier int nclri; 304e569ccb5SDavid du Colombier }; 305e569ccb5SDavid du Colombier 306*f6333ca0SDavid du Colombier /* disk partitions; keep in sync with partname[] in disk.c */ 3075e96a66cSDavid du Colombier enum { 3085e96a66cSDavid du Colombier PartError, 3095e96a66cSDavid du Colombier PartSuper, 3105e96a66cSDavid du Colombier PartLabel, 3115e96a66cSDavid du Colombier PartData, 3125e96a66cSDavid du Colombier PartVenti, /* fake partition */ 3135e96a66cSDavid du Colombier }; 3145e96a66cSDavid du Colombier 3155e96a66cSDavid du Colombier extern vtType[BtMax]; 316