code: mafs

ref: c947228f7cf50bbbeb3f1e1b1808280e9ae9247f
dir: /dat.h/

View raw version
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,
	KiB	= 1024ULL,	/* Kibibytes */
	MiB	= KiB*KiB,	/* Mibibytes */
	GiB	= KiB*MiB,	/* Gibibytes */
	TiB	= KiB*GiB,	/* Tibibytes */
	Nwriters = 10,	/* max. number of writer processes */

	/*
	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 * 1MiB = 2.5GiB
	 */
	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	= MiB/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 TiB file */
	Maxtind,	/* should be Tind0+Niblock */
				/* gap for more indirect block depth in future */
	MAXTAG,

	Tmaxind = Maxtind - 1,
};

/*
 * flags to getbuf
 */
enum
{
	Breadonly	= 1,/* read the block, cannot write to it */
	Bwritable	= 0,
	Bfreshalloc = 1,/* newly allocated block, no contents on the disk */
	Bused 		= 0,/* has contents on the disk */
};

/*
 * 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;