313 lines · 5.9 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "stdinc.h" #include "9.h" static struct {	VtLock*	lock; 	Fid*	free;	int	nfree;	int	inuse;} fbox; static voidfidLock(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 voidfidUnlock(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 voidfidFree(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 voidfidUnHash(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("%s: fid 0x%ud in use", argv0, fidno);			return nil;		}		fid->ref++;		vtUnlock(con->fidlock); 		fidLock(fid, flags);		if((fid->open & FidOCreate) || fid->fidno == NOFID){			fidPut(fid);			vtSetError("%s: fid invalid", argv0);			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("%s: fid not found", argv0);	return nil;} voidfidPut(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);} voidfidClunk(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);} voidfidClunkAll(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);} voidfidInit(void){	fbox.lock = vtLockAlloc();}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t