code: mafs

ref: fb53d7e68bcb2108fb304c81dccb1d7ff50ffa1f
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	Data	Data;
typedef struct	Metadata Metadata;
typedef struct	Metadataunit Metadataunit;
typedef	struct	Dentryhdr	Dentryhdr;
typedef	struct	Dentry	Dentry;
typedef	struct	Datahdr	Datahdr;
typedef	struct	Indirect	Indirect;
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	= 1,
	Nrefresh = 3*Nsec,
};

/*
 * 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 {
	Blocksize	= 512ULL,	/* minimum data unit size */

	Metadataunits	= 2,
	Metadatablocksize = Metadataunits*Blocksize, /* Keep the original and a copy together */

	Maxdatablockunits = 2048,
	Nindperblock= (Blocksize-3*sizeof(u64))/sizeof(u64),/* number of pointers per block */
	Nu64perblock= (Blocksize/sizeof(u64)),		/* number of u64's in a block */
	Dpathidx	= (Blocksize/sizeof(u64) -1),	/* index of path in the last data block, last u64 */

	Namelen = 127,	/* maximum length of a file name, calculated manually */
	Ndblock	= 32,	/* number of direct blocks in a Dentry */
	Niblock	= 5,	/* maximum depth of indirect blocks, can increase it to 8 without issues */

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

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

					/* no user writes allowed on blocks below Bdctl */
	Bdctl	= 16,	/* block number of /adm/ctl dentry, empty contents, virtual file */
	Bdusersstaging = 18,/* block number of /adm/users/staging dentry */
	Bdroot	= 20,	/* block number of root directory */

	Nbused	= Bdroot+2,	/* blocks used up by default */

	/* number of blocks used by the above and the backup blocks */
	Nminblocks = Nbused+(Metadataunits*Nbkp*3),

	/* 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 = 1,	/* magic block Tag.qpath */
	Qpconfig0 = 3,	/* /adm/bkp/config.0 block Tag.qpath */
	Qpsuper0  = 5,	/* /adm/bkp/super.0 block Tag.qpath */
	Qproot0	  = 21,	/* /adm/bkp/root.0 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 */
/* no access time */
struct Dentryhdr
{
	u8 tag;
	u8 verd;
	s16 uid;
	s16 gid;
	s16 muid;		/* 8 */
	u64 size;		/* 0 for directories. For files, size in bytes of the content - 16 */
	u64 pdblkno; 	/* block number of the parent directory entry. Will be 0 for root. - 24 */
	u64 pqpath; 	/* parent qid.path - 32 */
	u64 mtime;		/* modified time in nano seconds from epoch - 40 */
	u64 qpath;		/* unique identifier Qid.path 48 */
	u32 version;	/* Qid.version 52 */
	u32 mode;		/* same bits as defined in /sys/include/libc.h:/Dir\.mode/ - 56 */
	u8 namelen;		/* store name as a counted string 57 */
	s8 name[Namelen]; /* Namelen = 127 - 184*/
};
struct Datahdr
{
	u8 tag;
	u8 unused;	/* for alignment and future use */
	u16 len;
	u64 dblkno;	/* block number of the directory entry */
};
#pragma pack off

enum {
	/* size of identifiers used in a Tdata block */
	Ddataidssize = sizeof(Datahdr) +sizeof(u64 /* trailing path */),
	/* max possible size of data that can be stuffed into a Dentry */
	Ddatasize = Blocksize -sizeof(Dentryhdr) -sizeof(u64 /* trailing path */),
	Maxdatablocksize = Maxdatablockunits*Blocksize -Ddataidssize,
};

#pragma pack on
/* DONT TOUCH, these are all disk structures */
struct Super
{
	u64 qidgen;	/* generator for unique ids. starts from 1024. */
				/* TODO make fsok a time stamp in nano seconds */
	u64 fsok;	/* fsck status, using 64 bits to keep it all aligned */
};
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 */
		};
		Super;

		/* when size <= Dentrysize-184-sizeof(Tag), store the data here itself */
		s8 buf[Ddatasize];
	};
	u64 path;	/* same as qid.path */
};
struct Indirect
{
	u8 tagi;	/* the suffix i to avoid union complaining about ambiguous fields */
	u8 veri;
	u8 pad[6];	/* unused, to align to a multiple of 8 */
	u64 dblkno;	/* block number of the directory entry */
	u64 bufa[Nindperblock];
	u64 path;	/* same as qid.path */
};
struct Metadataunit
{
	union
	{
		Indirect;
		Dentry;
	};
};
struct Metadata
{
	union
	{
		Indirect i[2];
		Dentry d[2];
	};
};
struct Data		/* used to unmarshall the disk contents */
{
	Datahdr;
	u8 buf[1];	/* upto Maxdatablocksize, followed by u64 qid.path */
	/* u64 path; same as qid.path at the end of the data content - check consistency */
};
#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 */
};

/* storing this in ascii to the Bdconfig block */
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 = 8 /* 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,
	Tdata,		/* actual file contents */
	Tdentry,	/* directory entry, size = Dentrysize */
				/* Tdata & indirect blocks are last, to allow for greater depth */
	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 */
	Tind3,		/* contains a list of Tind1 block numbers */
	Tind4,		/* contains a list of Tind1 block numbers */
				/* gap for more indirect block depth in future.
					It can be put upto Tind7 without needing any code changes */
	Maxtind,	/* should be Tind0+Niblock */
	MAXTAG = Maxtind,

	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];
Config *parseconfig(s8 *cfg, Config *c);