123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- #include "stdinc.h"
- #include "9.h"
- static struct {
- VtLock* lock;
- Fid* free;
- int nfree;
- int inuse;
- } fbox;
- static void
- fidLock(Fid* fid, int flags)
- {
- if(flags & FidFWlock){
- vtLock(fid->lock);
- fid->flags = flags;
- }
- else
- vtRLock(fid->lock);
- /*
- * Callers of file* routines are expected to lock fsys->fs->elk
- * before making any calls in order to make sure the epoch doesn't
- * change underfoot. With the exception of Tversion and Tattach,
- * that implies all 9P functions need to lock on entry and unlock
- * on exit. Fortunately, the general case is the 9P functions do
- * fidGet on entry and fidPut on exit, so this is a convenient place
- * to do the locking.
- * No fsys->fs->elk lock is required if the fid is being created
- * (Tauth, Tattach and Twalk). FidFCreate is always accompanied by
- * FidFWlock so the setting and testing of FidFCreate here and in
- * fidUnlock below is always done under fid->lock.
- * A side effect is that fidFree is called with the fid locked, and
- * must call fidUnlock only after it has disposed of any File
- * resources still held.
- */
- if(!(flags & FidFCreate))
- fsysFsRlock(fid->fsys);
- }
- static void
- fidUnlock(Fid* fid)
- {
- if(!(fid->flags & FidFCreate))
- fsysFsRUnlock(fid->fsys);
- if(fid->flags & FidFWlock){
- fid->flags = 0;
- vtUnlock(fid->lock);
- return;
- }
- vtRUnlock(fid->lock);
- }
- static Fid*
- fidAlloc(void)
- {
- Fid *fid;
- vtLock(fbox.lock);
- if(fbox.nfree > 0){
- fid = fbox.free;
- fbox.free = fid->hash;
- fbox.nfree--;
- }
- else{
- fid = vtMemAllocZ(sizeof(Fid));
- fid->lock = vtLockAlloc();
- fid->alock = vtLockAlloc();
- }
- fbox.inuse++;
- vtUnlock(fbox.lock);
- fid->con = nil;
- fid->fidno = NOFID;
- fid->ref = 0;
- fid->flags = 0;
- fid->open = FidOCreate;
- assert(fid->fsys == nil);
- assert(fid->file == nil);
- fid->qid = (Qid){0, 0, 0};
- assert(fid->uid == nil);
- assert(fid->uname == nil);
- assert(fid->db == nil);
- assert(fid->excl == nil);
- assert(fid->rpc == nil);
- assert(fid->cuname == nil);
- fid->hash = fid->next = fid->prev = nil;
- return fid;
- }
- static void
- fidFree(Fid* fid)
- {
- if(fid->file != nil){
- fileDecRef(fid->file);
- fid->file = nil;
- }
- if(fid->db != nil){
- dirBufFree(fid->db);
- fid->db = nil;
- }
- fidUnlock(fid);
- if(fid->uid != nil){
- vtMemFree(fid->uid);
- fid->uid = nil;
- }
- if(fid->uname != nil){
- vtMemFree(fid->uname);
- fid->uname = nil;
- }
- if(fid->excl != nil)
- exclFree(fid);
- if(fid->rpc != nil){
- close(fid->rpc->afd);
- auth_freerpc(fid->rpc);
- fid->rpc = nil;
- }
- if(fid->fsys != nil){
- fsysPut(fid->fsys);
- fid->fsys = nil;
- }
- if(fid->cuname != nil){
- vtMemFree(fid->cuname);
- fid->cuname = nil;
- }
- vtLock(fbox.lock);
- fbox.inuse--;
- if(fbox.nfree < 10){
- fid->hash = fbox.free;
- fbox.free = fid;
- fbox.nfree++;
- }
- else{
- vtLockFree(fid->alock);
- vtLockFree(fid->lock);
- vtMemFree(fid);
- }
- vtUnlock(fbox.lock);
- }
- static void
- fidUnHash(Fid* fid)
- {
- Fid *fp, **hash;
- assert(fid->ref == 0);
- hash = &fid->con->fidhash[fid->fidno % NFidHash];
- for(fp = *hash; fp != nil; fp = fp->hash){
- if(fp == fid){
- *hash = fp->hash;
- break;
- }
- hash = &fp->hash;
- }
- assert(fp == fid);
- if(fid->prev != nil)
- fid->prev->next = fid->next;
- else
- fid->con->fhead = fid->next;
- if(fid->next != nil)
- fid->next->prev = fid->prev;
- else
- fid->con->ftail = fid->prev;
- fid->prev = fid->next = nil;
- fid->con->nfid--;
- }
- Fid*
- fidGet(Con* con, u32int fidno, int flags)
- {
- Fid *fid, **hash;
- if(fidno == NOFID)
- return nil;
- hash = &con->fidhash[fidno % NFidHash];
- vtLock(con->fidlock);
- for(fid = *hash; fid != nil; fid = fid->hash){
- if(fid->fidno != fidno)
- continue;
- /*
- * Already in use is an error
- * when called from attach, clone or walk.
- */
- if(flags & FidFCreate){
- vtUnlock(con->fidlock);
- vtSetError("fid 0x%ud in use", fidno);
- return nil;
- }
- fid->ref++;
- vtUnlock(con->fidlock);
- fidLock(fid, flags);
- if((fid->open & FidOCreate) || fid->fidno == NOFID){
- fidPut(fid);
- vtSetError("fid invalid");
- return nil;
- }
- return fid;
- }
- if((flags & FidFCreate) && (fid = fidAlloc()) != nil){
- assert(flags & FidFWlock);
- fid->con = con;
- fid->fidno = fidno;
- fid->ref = 1;
- fid->hash = *hash;
- *hash = fid;
- if(con->ftail != nil){
- fid->prev = con->ftail;
- con->ftail->next = fid;
- }
- else{
- con->fhead = fid;
- fid->prev = nil;
- }
- con->ftail = fid;
- fid->next = nil;
- con->nfid++;
- vtUnlock(con->fidlock);
- /*
- * The FidOCreate flag is used to prevent any
- * accidental access to the Fid between unlocking the
- * hash and acquiring the Fid lock for return.
- */
- fidLock(fid, flags);
- fid->open &= ~FidOCreate;
- return fid;
- }
- vtUnlock(con->fidlock);
- vtSetError("fid not found");
- return nil;
- }
- void
- fidPut(Fid* fid)
- {
- vtLock(fid->con->fidlock);
- assert(fid->ref > 0);
- fid->ref--;
- vtUnlock(fid->con->fidlock);
- if(fid->ref == 0 && fid->fidno == NOFID){
- fidFree(fid);
- return;
- }
- fidUnlock(fid);
- }
- void
- fidClunk(Fid* fid)
- {
- assert(fid->flags & FidFWlock);
- vtLock(fid->con->fidlock);
- assert(fid->ref > 0);
- fid->ref--;
- fidUnHash(fid);
- fid->fidno = NOFID;
- vtUnlock(fid->con->fidlock);
- if(fid->ref > 0){
- /* not reached - fidUnHash requires ref == 0 */
- fidUnlock(fid);
- return;
- }
- fidFree(fid);
- }
- void
- fidClunkAll(Con* con)
- {
- Fid *fid;
- u32int fidno;
- vtLock(con->fidlock);
- while(con->fhead != nil){
- fidno = con->fhead->fidno;
- vtUnlock(con->fidlock);
- if((fid = fidGet(con, fidno, FidFWlock)) != nil)
- fidClunk(fid);
- vtLock(con->fidlock);
- }
- vtUnlock(con->fidlock);
- }
- void
- fidInit(void)
- {
- fbox.lock = vtLockAlloc();
- }
|