ref: 56bd332994102b4e194819abb5e087a8895452f9
dir: /all.h/
#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 */ }; /* 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 */ Data *io; Metadata *m; }; Metadataunit *cur; /* this has the current Indirect or Dentry values */ Metadataunit *new; /* use this unit for Indirect or Dentry changes */ u8 *append; /* appended data added not yet written to disk */ u64 appendsize; u8 freshalloc; /* uninitialized blocks on the disk */ }; 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); int checktag(Iobuf *p, u16 len, u8 tag, u64 qpath); Iobuf* getbuf(u64 blkno, u16 len, u8 readonly, u8 freshalloc); Iobuf* getbufchk(u64 blkno, u16 len, u8 readonly, int tag, u64 qpath); 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); /* 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); 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 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 freeaux(Aux *a); Iobuf* getdatablkat(Dentry *d, u64 reli); void loadfrees(u64 dblkno); Aux* newaux(u64 addr, u16 uid); s32 readfile(u64 dblkno, u64 qpath, char *rbuf, s32 rbufsize, u64 offset); s32 readfilesize(u64 dblkno, u64 qpath); void savefrees(u64 dblkno); void truncatefile(u64 qpath, u64 dblkno, s16 uid); s32 writeallappend(Iobuf *dbuf, Dentry *d, u64 dblkno); s32 writefile(u64 dblkno, u64 qpath, s16 uid, char *wbuf, s32 wbufsize, u64 offset); s8 flush(Iobuf *b); u64 sync(void); /* 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); void ctlread(Req *req); void ctlwrite(Req *req); int dprint(char *fmt, ...); int prime(long); u64 min(u64 a, u64 b); #pragma varargck argpos panic 1