code: mafs

ref: 16f09290e03ec4fba68b6587dc01c13299c2a6f6
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;

typedef	struct	Config	Config;
typedef	struct	Content	Content;
typedef	struct	Dentryhdr	Dentryhdr;
typedef	struct	Dentry	Dentry;
typedef struct	Qid9p1	Qid9p1;
typedef	struct	Super	Super;
typedef	struct	Tlock	Tlock;
typedef	struct	User	User;
typedef struct	Aux Aux;

enum
{
	KiB	= 1024ULL,	/* Kibibytes */
	MiB	= KiB*KiB,	/* Mibibytes */
	GiB	= KiB*MiB,	/* Gibibytes */
	TiB	= KiB*GiB,	/* Tibibytes */

	Ngroups	= 32,	/* maximum number of groups an user can belong to */
	None	= 0,	/* user ID for "none" */
	Noworld	= 9999,	/* conventional id for "noworld" group */
	Userlen = 32,

	Nsec	= 1000ULL*1000*1000,
	Usec	= 1000ULL*1000,
	Msec	= 1000ULL,
	Nbkp	= 2,
};

/*
 * 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.
 *
 * Trying to keep the Qpath the same as the directory entry block number
 * for the system files to help me identify numbers easily.
 *
 * derived constants
 * Nindperblock number of block pointers in a block
 */
enum {
	Unit	= 512ULL,		/* minimum data unit size */
	Dentryunits	= 1,		/* number of units per Tdentry */
	Rawblockunits= 16,		/* number of units for others */

	Dentrysize	= Dentryunits*Unit,		/* real block size of a Tdentry */
	/* real block size of others. a multiple of Unit to keep the extents code uniform */
	Rawblocksize= Rawblockunits*Unit,
	Blocksize	= Rawblocksize - sizeof(u8 /* tag */) -sizeof(u64 /* path */),
	Nindperblock= (Blocksize-7)/sizeof(u64),/* number of pointers per block. -7 for pad */

	Namelen = 129,	/* maximum length of a file name, calculated manually */
	Ndblock	= 32,	/* number of direct blocks in a Dentry */
	Niblock	= 3,	/* maximum depth of indirect blocks, can increase it to 6 without issues */
	MAXRPC	= Blocksize,/* Tdata block size in bytes */
	Iounit	= MAXRPC,	/* in bytes, TODO adjust for the 9p header size? */

	/* global block numbers. The bkp contents locations are calculated by ream() */
	Bdmagic	= 0,	/* block number of first block. Bmagic conflicts with bio.h */
	Bdconfig= 1,	/* block number of /adm/config dentry and contents */
	Bdsuper	= 2,	/* block number of /adm/super dentry and contents */
	Bdadm	= 3,	/* block number of /adm directory */
	Bdusers	= 4,	/* block number of /adm/users/ dentry */

					/* contents of blocks below change on use */ 
	Bdbkp	= 5,	/* block number of /adm/bkp directory */
	Bdusersinuse = 6,	/* block number of /adm/users/inuse dentry and contents */
	Bdfrees = 7,	/* block number of /adm/frees dentry, text file of free extents */

					/* no user writes allowed on blocks below Bdctl */
	Bdctl	= 8,	/* block number of /adm/ctl dentry, empty contents, virtual file */
	Bdusersstaging = 9,/* block number of /adm/users/staging dentry */
	Bdroot	= 10,	/* block number of root directory */
	Nbused,			/* blocks used up by default */
	Nminblocks = Nbused+(Nbkp*3), /* number of blocks used by the above and the backup blocks */

	/* Qpnone is the Tag.path of free blocks/extents(Tfree),
		and zero'ed out dentry blocks */
	Qpnone		= 0,
	Qpconfig	= Bdconfig,	/* /adm/config block Tag.qpath */
	Qpsuper		= Bdsuper,	/* /adm/super block Tag.qpath */
	Qpadm		= Bdadm,	/* /adm */
	Qpusers		= Bdusers,	/* /adm/users block Tag.qpath */

	Qpbkp		= Bdbkp,	/* /adm/bkp block Tag.qpath */
	Qpusersinuse	= Bdusersinuse,	/* /adm/users/inuse block Tag.qpath */
	Qpfrees		= Bdfrees,	/* /adm/frees block Tag.qpath */

	Qpctl		= Bdctl,	/* /adm/ctl */
	Qpusersstaging	= Bdusersstaging,/* /adm/users/staging block Tag.qpath */
	Qproot		= Bdroot,	/* /, so fscreate() can disallow any create's below */

				/* system qpaths */
	Qpmagic,	/* magic block Tag.qpath */
	Qpconfig0,	/* /adm/bkp/config.0 block Tag.qpath */
	Qpsuper0,	/* /adm/bkp/super.0 block Tag.qpath */
	Qproot0	,	/* /adm/bkp/root.0 block Tag.qpath */
	Qpconfig1,	/* /adm/bkp/config.1 block Tag.qpath */
	Qpsuper1,	/* /adm/bkp/super.1 block Tag.qpath */
	Qproot1	,	/* /adm/bkp/root.1 block Tag.qpath */

	Nqidgen	= 64,

	/* check qpath for overflows - TODO, should be 2^64 */
	Maxqpath = 72057594037927936ULL, /* 2^56 */

	Nthdirty = 9,	/* dirty byte is the 9th byte in the Tag */
};

#pragma pack on
/* DONT TOUCH, this is the disk structure */
struct Qid9p1
{
	u64 path;	/* unique identifier */
	u32 version;
};

/* DONT TOUCH, this is the disk structure */
/*
 * no access time
 */
struct Dentryhdr
{
	u8 tag;
	s8  name[Namelen]; /* 130, Namelen = 129 to align to a u64 after the ids*/
	s16 uid;		/* 132 */
	s16 gid;		/* 134 */
	s16 muid;		/* 136 */
	u64 size;		/* 0 for directories. For files, size in bytes of the content - 8 */
	u64 pdblkno; 	/* block number of the parent directory entry. Will be 0 for root. - 16 */
	u64 pqpath; 	/* parent qid.path - 24 */
	u64 mtime;		/* modified time in nano seconds from epoch - 32 */
	Qid9p1	qid;	/* 44 bytes */
	u32 mode;		/* same bits as defined in /sys/include/libc.h:/Dir\.mode/ - 48 */
};
#pragma pack off

enum {
	/* max possible size of data that can be stuffed into a Dentry */
	Ddatasize = Dentrysize -sizeof(u64 /* path */) -sizeof(Dentryhdr),
};

#pragma pack on
struct Dentry
{
	Dentryhdr;
	union
	{
		struct
		{
			u64 dblocks[Ndblock];	/* direct blocks. */
									/* List of Tdata block numbers for files and
										Tdentry block numbers for directories */
			u64 iblocks[Niblock];	/* indirect blocks */
		};
		/* when size <= Dentrysize-184-sizeof(Tag), store the data here itself */
		s8 buf[Ddatasize];
	};
	u64 path;
};
/* DONT TOUCH, this is the disk structure */
struct Super
{
	Dentryhdr;
	u64 qidgen;	/* generator for unique ids. starts from 1024. */
			/* 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 */
	u64 path;
};
/* DONT TOUCH, this is the disk structure */
struct Content	/* used to unmarshall the disk contents */
{
	u8 tag;
	union
	{
		u8 buf[Blocksize];
		struct
		{
			u8 pad[7];	/* unused, to align to a multiple of 8 */
			u64 bufa[Nindperblock];
		};
	};
	u64 path;	/* same as qid.path */
};
#pragma pack off

/*
 * array of qids that are locked
 */
struct Tlock
{
	u64 time;
	u64 qpath;
	u64 dblkno;
	Tlock *prev, *next;
};

struct Aux
{
	u64 dblkno; /* dentry absolute block number */
	u16 uid;
	u8 tlocked;	/* for exclusive use files, flag to indicate lock */
	u64 dri;	/* directory index while reading a directory */
	/* u64 lastreadahead; TODO */
};

/*
	every user is also a group with one user.
 */
struct User
{
	s16 id;		/* user id */
	s16 lid;	/* id of the leader of group */
	char name[Userlen];	/* user name */
	s16 *members;/* list of member id's belonging to this group */
	int nmembers;/* number of members in this group */
	int nalloc;	/* allocated space members */
	User *prev, *next;	/* linked list sorted by id */
};

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? */
	Nworkers = 2 /* 32 */,	/* make this a parameter? */
	Nlru  = 32,
	Nuserserrmsg = 64,
};

/*
 * 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,
	Einvusers,
	Enousers,
	Ewalk,

	MAXERR
};

/*
 * tags on block
 */
/* DONT TOUCH, this is in disk structures */
/* the first 512 bytes holds the magic.
	Not bothering with a tag for 1 Unit. Use Tdentry for that.
 */
/* also, the order from Tdata to Tmaxind is exploited in indirck() & isdirty() */
enum
{
	Tblank = 0,
	Tfree  = 0,	/* free block */
	Tnone  = 0,
	Tdentry,	/* directory entry, size = Dentrysize */
				/* Tdata & indirect blocks are last, to allow for greater depth */
	Tdata,		/* actual file contents */
	Tind0,		/* contains a list of Tdata block numbers for files
					and Tdentry block numbers for directories.*/
	Tind1,		/* contains a list of Tind0 block numbers */
	Tind2,		/* contains a list of Tind1 block numbers */
				/* gap for more indirect block depth in future.
					It can be put upto Tind5 without needing any code changes */
	Maxtind,	/* should be Tind0+Niblock */
	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 */
};

#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)

extern	char*	errstring[MAXERR];
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	*procname;

extern Config config;
extern char userserrmsg[Nuserserrmsg];