code: mafs

ref: 390e726c64ee2aca967617ac7f7fd2a44f27646b
dir: /all.h/

View raw version
#include <u.h>
#include <libc.h>

#include <fcall.h>
#include <auth.h>
#include <authsrv.h>
#include <thread.h>
#include <9p.h>

#include "dat.h"
#include "extents.h"

enum
{
	/*
	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

	Size of buffer cache is approximately (Nbuckets * Ncollisions * Rawblocksize).

	If you have RAM to spare, increase the Nbuckets instead of
	Ncollisions as the hash index lookup is faster than searching
	through a linked list.
	 */
	Ncollisions = 3,	/* soft limit after which we start reusing older Iobuf's */

	Iounit	= Maxdatablocksize-IOHDRSZ,

	/* for dirty */
	Add = 1,
	Remove
};

typedef	struct	Hiob	Hiob;
typedef	struct	Iobuf	Iobuf;

struct Hiob		/* Hash bucket */
{
	Iobuf*	link;	/* least recently used of the circular list */
	QLock;		/* controls access to this hash bucket */
	u64	n;		/* count of Iobuf's in the circular list */
};

/*
	using Ref to avoid locking up the hash bucket when a process
	is waiting for a lock on an Iobuf in that hash bucket.

	The Ref ensures that an Iobuf is not stolen before another process
	can get to wlock()'ing it after letting go of the lock on the hash bucket.
	We cannot hold the lock on the hash bucket until we wlock() the iobuf
	as that blocks other processes from using the hash bucket. This could
	also result in a deadlock. For example, the directory entry is block 18,
	which hashes to a hash index of 7. A writer() locked the directory entry
	iobuf and wants to add a data block 84 to the directory entry. Block 84
	hashes to the same hash index of 7. Another process wanting to access the
	directory entry is waiting for a lock on that io buffer. While doing so,
	it has locked the hash bucket. Now, this has caused a deadlock between
	both these processes. The first process cannot proceed until it can
	lock the hash bucket holding block 84 and is still holding the lock
	on the directory entry in block 18. The second process cannot lock
	block 18 and is holding the lock on the hash bucket.

	for locking a buffer:
		qlock(hash bucket); incref(buffer); qunlock(hash bucket);
			wlock(buffer); decref(buffer);

	for stealing an unused buffer:
		qlock(hash bucket);
		find a buffer with ref == 0 and wlock()'able.
		qunlock(hash bucket);

	for unlocking a buffer:
		wunlock(buffer);
 */
struct Iobuf
{
	Ref;
	RWLock;			/* controls access to this Iobuf */
	u64	blkno;		/* block number on the disk, primary key */
	u16	len;		/* number of Units */
	Iobuf *fore;	/* for lru */
	Iobuf *back;	/* for lru */
	union{
		u8	*xiobuf;	/* "real" buffer pointer */
		u64	*xiobuf64;
		Data *io;
		Dentry *d;
		Indirect *i;
	};

	u8 *append;		/* appended data added not yet written to disk */
	u64 appendsize;
	u8 freshalloc;	/* uninitialized blocks on the disk */
	u64 atime;		/* to find old buffers to flush to the disk */
	u8 tag;
	u64 callerpc;	/* when locked, the locker pc for debugging */
};

extern	u64	nbuckets;		/* n hash buckets for i/o */
extern	Extents frees;		/* extents of free blocks on the disk */

#include "fns.h"

/* Iobuf routines - contents of the blocks in memory */
void	initmemunitpool(u64 nunits);
u8*		allocmemunits(u16 len);
void	freememunits(u8 *m, u16 len);
void	fsflush(void);
int		checktag(Iobuf *p, u16 len, u8 tag, u64 qpath);
Iobuf *egetbufchk(u64 blkno, u16 len, u8 readonly, int tag, u64 qpath, u64 userpc);
Iobuf *egetmetachk(u64 blkno, u8 readonly, int tag, u64 qpath);
Iobuf *egetmeta(u64 blkno, u8 readonly, u8 freshalloc);
Iobuf*	getbuf(u64 blkno, u16 len, u8 readonly, u8 freshalloc, u64 userpc);
Iobuf*	getbufchk(u64 blkno, u16 len, u8 readonly, int tag, u64 qpath, u64 userpc);
Iobuf*	getmeta(u64 blkno, u8 readonly, u8 freshalloc);
Iobuf*	getmetachk(u64 blkno, u8 readonly, int tag, u64 qpath);
void	iobufinit(void);
void	putbuf(Iobuf *p, u8 dowrite);
void	putbuffree(Iobuf *p);
void	settag(Iobuf *p, u8 tag, u64 qpath);
void	showbuf(Iobuf *p);
u32		showhashbuckets(s8 *buf, u32 nbuf);

/* writer functions */
void	initwriter(void);
void	putwrite(Iobuf *b);
void	stopwriter(void);
u64		pendingwrites(void);

/* routines to manipulate the contents */
Iobuf*	allocblocks(u64 len, int tag, u64 qpath);
Iobuf*	allocmeta(int tag, u64 qpath);
u8		allocdentries(u16 n, Iobuf **iobufs, u64 qpath);
void	freeblockbuf(Iobuf *buf);
void	freeblocks(u64 blkno, u64 len, u16 tag, u64 qpath);
void	fsok(int ok);
void	init(int doream, u64 size);
u64		newqpath(void);
u64		newqpaths(u8 n);
u64		nperiblock(u16 tag);
u64		nperindunit(u16 tag);
u64		power( u64 base, int n);
void	ream(u64 size);
u64	rel2abs(Dentry *d, u64 reli);
void	rmfile(u64 qpath, u64 dblkno);
void	rmdirectory(u64 qpath,  u64 dblkno);
void	rootream(void);
Dentry	*searchdir(u64 dblkno, u64 qpath, u16 uid, char *searchname, u64 searchidx, Iobuf **dbuf, Iobuf **buf);
void	shutdown(void);
void	start9p(int stdio);
void	superream(u64 size, u64 nblocks);
Tlock*	tlocked(Iobuf*, Dentry*);

/* dentry routines */
u64 	addrelative(Dentry *d, u64 dblkno, u64 reli, u64 blkno);
void	clearfrees(void);
void	freeaux(Aux *a);
Iobuf*	getdatablkat(Dentry *d, u64 reli);
u64		loadextentsfile(u64 blkno, u64 qpath, Extents *es);
void	loadfrees(void);
s32		readfile(u64 dblkno, u64 qpath, char *rbuf, s32 rbufsize, u64 offset);
s32		readfilesize(u64 dblkno, u64 qpath);
void	saveextentstofile(u64 blkno, u64 qpath, u16 uid, Extents *es);
void	savefrees(void);
void	truncatefile(u64 qpath, u64 dblkno, s16 uid);
s32		writeallappend(Iobuf *dbuf, u64 dblkno, Iobuf **oldbufp);
s32		writefile(u64 dblkno, u64 qpath, s16 uid, char *wbuf, s32 wbufsize, u64 offset);
void	flush(Iobuf *b);
u64		sync(void);
void	flushold(void);

/* names routines */
s8	searchnames(Dentry *d, char *searchname, u64 *relip);
u16	readname(Dentry *d, u64 noffset, s8 **namep, u16 *namelen);
void	rmname(Dentry *pd, s16 uid, u64 noffset);
u16	addname(Dentry *pd, u16 uid, u64 preli, s8 *name);
u16	updatename(Dentry *pd, u16 uid, u64 preli, s8 *name);
void	newnames(Dentry *pd, u16 uid, u64 pdblkno, Iobuf **iobufs);

/* user access routines */
int	byname(void*, void*);
int	byuid(void*, void*);
int canaccess(s16 uid, Dentry *d, u32 mode);
int	checkname(char*);
int	checkname9p2(char*);
void	chkqunlock(QLock *q);
void	chkrunlock(RWLock *q);
u8	chkwunlock(RWLock *q);
void 	cmd_user(void);
char*	cname(char*);
void	sublockinit(void);
int	fname(char*);
void	formatinit(void);
void   freesearchstate(Iobuf **dbuf, Iobuf **buf);
int	iaccess(short uid, Dentry *d, int m);
int	ingroup(s16 uid, s16 gid, int locked);
void	initconfig(u64 bno);
int	leadgroup(s16 uid, s16 gid);
s16	lookupid(char *name);
void	newstart(void);
int	oconvD2M(Dentry*, void*);
int	oconvM2D(void*, Dentry*);
int	ofcallfmt(Fmt*);
int	strtouid(char*);
int	strtouid1(char*);
void	syncusers(void);
char	*username(s16 uid, char *username);
void	usersinit(void);
void	writeconfig(u64 bno);
u16	configstr(s8 *buf, u16 nbuf);

void	ctlread(Req *req);
void	ctlwrite(Req *req);

int	dprint(char *fmt, ...);
int	dprintfd(int fd, char *fmt, ...);
int	prime(long);
u64	min(u64 a, u64 b);
void	*malloc9p(u32 sz);
void	*emalloc(u32 sz);

#pragma varargck	argpos	panic	1