ref: 5c21eca829380c28769f79beabb7cc51f1787f97
dir: /dat.h/
typedef signed char s8; typedef signed short s16; typedef signed int s32; typedef signed long long s64; typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long u64; enum { Nusers = 32, /* max. number of users */ None = 0, /* user ID for "none" */ Noworld = 9999, /* conventional id for "noworld" group */ Userlen = 32, Nsec = 1000ULL*1000*1000, Usec = 1000ULL*1000, Msec = 1000ULL, Iounit = 65536, Nbkp = 2, KB = 1024ULL, /* in bytes */ MB = KB*KB, /* in bytes */ GB = KB*MB, /* in bytes */ TB = KB*GB, /* in bytes */ /* https://cs.stackexchange.com/questions/11029/why-is-it-best-to-use-a-prime-number-as-a-mod-in-a-hashing-function using small numbers for testing using Nbuckets=2 for testing. Size of buffer cache = Nbuckets * Ncollisions * Maxspansize = 256 * 10 * 1MB = 2.5GB */ Nbuckets = 256, /* number of Hiob */ Ncollisions = 10, /* soft limit after which we start reusing older Iobuf's */ /* Qpnone is the Tag.path of free blocks/extents(Tfree), and zero'ed out dentry blocks */ Qpnone = 0, Qpmagic = 1, /* magic block Tag.qpath */ Qpconfig = 2, /* /adm/config block Tag.qpath */ Qpsuper = 3, /* /adm/super block Tag.qpath */ Qpadm = 5, /* /adm */ Qpusers = 6, /* /adm/users */ Qpbkp = 7, /* /adm/bkp block Tag.qpath */ Qpconfig0 = 8, /* /adm/bkp/config.0 block Tag.qpath */ Qpsuper0 = 9, /* /adm/bkp/super.0 block Tag.qpath */ Qproot0 = 10, /* /adm/bkp/root.0 block Tag.qpath */ Qpconfig1 = 11, /* /adm/bkp/config.1 block Tag.qpath */ Qpsuper1 = 12, /* /adm/bkp/super.1 block Tag.qpath */ Qproot1 = 13, /* /adm/bkp/root.1 block Tag.qpath */ Qpctl = 14, /* /adm/ctl */ Qpfrees = 15, /* /adm/frees block Tag.qpath */ Nqidgen = 64, Qproot = Nqidgen-1, /* /, so fscreate() can disallow any create's below */ /* check qpath for overflows - TODO, should be 2^64 */ Maxqpath = 72057594037927936ULL, /* 2^56 */ }; /* * fundamental constants and types of the implementation * changing any of these changes the layout on disk * The very first block (index = 0) has the magic written at offset 256. */ enum { Rawblocksize= 512, /* real block size */ Ndspanid = 24, /* number of direct Spanid identifiers in a Dentry */ Niblock = 4, /* max depth of indirect blocks */ /* from tests/sizes.c, this provides 12M data spans */ /* global block numbers. The bkp contents locations are calculated by ream() */ Bmagicb = 0, /* block number of first block. Bmagic conflicts with bio.h */ Bconfig = 1, /* block number of config contents */ Bsuper = 2, /* block number of super contents */ Broot = 3, /* block number of root directory */ Badm = 4, /* block number of /adm directory */ Bdconfig = 5, /* block number of /adm/config dentry */ Bdsuper = 6, /* block number of /adm/super dentry */ Bdusers = 7, /* block number of /adm/users file */ Busers = 8, /* block number of /adm/users file contents */ Bbkp = 9, /* block number of /adm/bkp directory */ Bdconfig0 = 10, /* block number of /adm/bkp/config.0 dentry */ Bdsuper0 = 11, /* block number of /adm/bkp/super.0 dentry */ Bdroot0 = 12, /* block number of /adm/bkp/root.0 dentry */ Bdconfig1 = 13, /* block number of /adm/bkp/config.1 dentry */ Bdsuper1 = 14, /* block number of /adm/bkp/super.1 dentry */ Bdroot1 = 15, /* block number of /adm/bkp/root.1 dentry */ Bdctl = 16, /* block number of /adm/ctl dentry, empty contents, virtual file */ Bdfrees = 17, /* block number of /adm/frees dentry, text file of free extents */ Nbused, /* blocks used up by default */ Nminblocks = Nbused+(Nbkp*3), /* number of blocks used by the above and the backup blocks */ NTLOCK = 200, /* number of active file Tlocks */ Nthdirty = 9, /* dirty byte is the 9th byte in the Tag */ }; typedef struct Config Config; typedef struct Content Content; typedef struct Dentry1 Dentry1; typedef struct Dentry Dentry; typedef struct Spanid Spanid; typedef struct Fblock Fblock; typedef struct Qid9p1 Qid9p1; typedef union Rabuf Rabuf; typedef struct Super1 Super1; typedef struct Superb Superb; typedef struct Tag Tag; typedef struct User User; typedef struct Aux Aux; typedef struct Log Log; /* from kfs, might have to be removed */ typedef struct Filta Filta; typedef struct Filter Filter; typedef struct P9call P9call; typedef struct Tlock Tlock; typedef struct Uid Uid; typedef struct Wpath Wpath; typedef struct AuthRpc AuthRpc; /* * DONT TOUCH -- data structures stored on disk */ #pragma pack on /* DONT TOUCH, this is the disk structure */ struct Tag { u64 path; /* Qid.path, unique identifier */ u8 type; /* Tmagic, Tdentry, Tdata, Tindn */ u8 dirty; /* is 1, when being written to. Identifies dirty data on a crash. This byte position is denoted by the enum Nthdirty. */ u16 len; /* number of blocks in this Spanid */ }; /* DONT TOUCH, this is the disk structure */ struct Super1 { u64 start; /* starting block */ u64 tfree; /* total number of free blocks - obsolete? */ u64 qidgen; /* generator for unique ids. starts from 1024. */ u64 frees; /* list of free extents was written here at halt */ /* make fsok a time stamp with the highest bit being the fsok flag */ u64 fsok; /* fsck status, using 64 bits to keep it all aligned */ }; /* DONT TOUCH, this is the disk structure */ struct Qid9p1 { u32 version; u64 path; /* unique identifier */ }; /* DONT TOUCH, this is the disk structure */ /* code gets less confusing when we store the length of the extent in the dentry. If not, we have to keep checking if the data extent is the last extent for each extent. This makes the code more convoluted as we need to track the file size any time we work on any data extent. Another option is to use the 64th bit as a flag to indicate if this is the last extent. That appears hacky. The name Extent is used by extents.h, hence, using Spanid. */ struct Spanid /* Spanid identifier */ { u64 blkno; /* starting block number */ u16 len; /* number of blocks */ }; /* DONT TOUCH, this is the disk structure */ /* * 1 dentry per block * no access time */ struct Dentry1 { Qid9p1 qid; u64 size; /* 0 for directories. For files, size in bytes of the content */ u64 pdblkno; /* parent dentry absolute block number. Will be 0 for root. */ u64 pqpath; /* parent qid.path */ u64 mtime; /* modified time nano seconds from epoch */ u32 mode; /* same bits as defined in lib.h Dir.mode */ s16 uid; s16 gid; s16 muid; Spanid dspans[Ndspanid]; /* direct Spanids */ /* Tag.type = Tdentry for directories and Tdata for files */ u64 iblocks[Niblock]; /* indirect blocks */ }; #pragma pack off /* * derived constants * Ndentriesperblock number of Dentry's in a block * Nindperblock number of block pointers in a block * Nspanidperblock number of Spanid identifiers in a Tind0 block */ enum { Blocksize = Rawblocksize - sizeof(Tag), Namelen = (Blocksize-sizeof(Dentry1)),/* max size of file name components */ Maxspanlen = MB/Rawblocksize, /* in blocks */ Maxspansize = (Maxspanlen*Rawblocksize)-sizeof(Tag), /* in bytes */ Ndentryperblock = 1, /* Blocksize / sizeof(Dentry), */ Nindperblock = Blocksize / sizeof(u64), Nspanidperblock = Blocksize / sizeof(Spanid), }; #pragma pack on /* DONT TOUCH, this is the disk structure */ struct Dentry { struct Dentry1; char name[Namelen]; }; struct Content /* used to unmarshall the disk contents */ { Tag; union{ u8 buf[Blocksize]; u64 bufa[Nindperblock]; Spanid s[Nspanidperblock]; Dentry d; }; }; #pragma pack off #pragma pack on /* DONT TOUCH, this is the disk structure */ struct Superb { Super1; }; #pragma pack off /* * for load stats */ struct Filter { u64 count; /* count and old count kept separate */ u64 oldcount; /* so interrput can read them */ /* Float filter[3];*/ /* filters for 1m 10m 100m */ }; struct Filta { Filter* f; int scale; }; /* * array of qids that are locked */ struct Tlock { u64 time; u64 qpath; u64 dblockno; }; struct Aux { u64 dblkno; /* dentry absolute block number */ u16 uid; Tlock *tlock; /* for exclusive use files */ u64 dri; /* directory index while reading a directory */ /* u64 lastreadahead; TODO */ }; struct User { s16 id; /* user id */ s16 lid; /* id of the leader of group */ s16 members[Nusers]; /* group table, member id's */ int nmembers; /* number of group entries */ char name[Userlen]; /* user name */ User *next; }; struct Bkp { u64 srcbno; /* source of the backup */ u64 dest[Nbkp]; /* destinations written to */ }; struct Config { u64 size; /* size from dirfstat */ u64 nblocks; /* size in blocks */ struct Bkp config; struct Bkp super; struct Bkp root; char service[Namelen]; }; enum { Nworks = 1024, /* make this a parameter? */ Nprocs = 32, /* make this a parameter? */ }; /* * error codes generated from the file server */ enum { Eaccess = 1, Ealloc, Eauth, Eauthmsg, Ebadname, Ebadspc, Ebadu, Ebroken, Echar, Econvert, Ecount, Edir1, Edir2, Edirty, Edot, Eempty, Eentry, Eexist, Efid, Efidinuse, Efull, Einval, Elocked, Emode, Ename, Enomem, Enotd, Enotdir, Enotg, Enotl, Enotm, Enotu, Enotw, Eoffset, Eopen, Eperm, Ephase, Eqid, Eqidmode, Eronly, Ersc, Eshutdown, Esystem, Etoolong, Etoou64, Ewalk, MAXERR }; /* * tags on block */ /* DONT TOUCH, this is in disk structures */ /* also, the order from Tdata to Tmaxind is exploited in indirck() & isdirty() */ enum { Tblank = 0, Tnone = 0, Tmagic, /* the first (zero'th) block holds the magic */ Tdentry, /* directory entry */ /* Tdata & indirect blocks are last, to allow for greater depth */ Tdata, /* has the file contents */ Tind0, /* points to Tdata blocks for files or Tdentry blocks for directories. */ Tind1, /* points to Tind0 blocks */ Tind2, /* points to Tind1 blocks */ Tind3, /* list of Tind2 blocks. we can have a 12 TB file */ Maxtind, /* should be Tind0+Niblock */ /* gap for more indirect block depth in future */ MAXTAG, Tmaxind = Maxtind - 1, }; /* * flags to getbuf * As all writes except for the Super block are synchronous, Bimm is mostly obsolete. */ enum { Breadonly = (1<<0), /* read the block if miss */ Bprobe = (1<<1), /* return null if miss */ Bmod = (1<<2), /* set modified bit in buffer, needs writing */ Bimm = (1<<3), /* set immediate bit in buffer */ Bres = (1<<4), /* reserved, never renammed */ }; /* * open modes passed into P9 open/create */ enum { MREAD = 0, MWRITE, MBOTH, MEXEC, MTRUNC = (1<<4), /* truncate on open */ MCEXEC = (1<<5), /* close on exec (host) */ MRCLOSE = (1<<6), /* remove on close */ }; /* * check flags */ enum { Crdall = (1<<0), /* read all files */ Ctag = (1<<1), /* rebuild tags */ Cpfile = (1<<2), /* print files */ Cpdir = (1<<3), /* print directories */ Cfree = (1<<4), /* rebuild free list */ Cream = (1<<6), /* clear all bad tags */ Cbad = (1<<7), /* clear all bad blocks */ Ctouch = (1<<8), /* touch old dir and indir */ Cquiet = (1<<9), /* report just nasty things */ }; /* * console cons.flag flags */ enum { Fchat = (1<<0), /* print out filesys rpc traffic */ Fuid = (1<<2), /* print out uids */ /* debugging flags for drivers */ }; struct Cons { int flags; /* overall flags for all channels */ int uid; /* botch -- used to get uid on cons_create */ int gid; /* botch -- used to get gid on cons_create */ int allow; /* no-protection flag */ u64 offset; /* used to read files, c.f. fchar */ char* arg; /* pointer to remaining line */ Filter work; /* thruput in messages */ Filter rate; /* thruput in bytes */ Filter bhit; /* getbufs that hit */ Filter bread; /* getbufs that miss and read */ Filter binit; /* getbufs that miss and dont read */ Filter tags[MAXTAG]; /* reads of each type of block */ }; #define SECOND(n) (n) #define MINUTE(n) (n*SECOND(60)) #define HOUR(n) (n*MINUTE(60)) #define DAY(n) (n*HOUR(24)) #define TLOCK MINUTE(5) #define CHAT(cp) (chat) #define QID9P1(a,b) (Qid9p1){a,b} extern char* errstring[MAXERR]; extern Tlock *tlocks; extern char service[Namelen]; extern char *tagnames[]; extern char *devfile; /* device file path */ extern int devfd ; /* device fd */ extern int writeallow; extern int wstatallow; extern int allownone; extern u8 readonly; extern u8 shuttingdown; extern u8 noauth; /* used by panic() */ extern char *progname; extern char *procname; extern Config config;