xref: /plan9/sys/src/cmd/fossil/9fid.c (revision 36066be07288900642605e3e4f42ceece4e473a9)
15e96a66cSDavid du Colombier #include "stdinc.h"
25e96a66cSDavid du Colombier 
35e96a66cSDavid du Colombier #include "9.h"
45e96a66cSDavid du Colombier 
55e96a66cSDavid du Colombier static struct {
65e96a66cSDavid du Colombier 	VtLock*	lock;
75e96a66cSDavid du Colombier 
85e96a66cSDavid du Colombier 	Fid*	free;
95e96a66cSDavid du Colombier 	int	nfree;
105e96a66cSDavid du Colombier 	int	inuse;
115e96a66cSDavid du Colombier } fbox;
125e96a66cSDavid du Colombier 
135e96a66cSDavid du Colombier static void
fidLock(Fid * fid,int flags)145e96a66cSDavid du Colombier fidLock(Fid* fid, int flags)
155e96a66cSDavid du Colombier {
165e96a66cSDavid du Colombier 	if(flags & FidFWlock){
175e96a66cSDavid du Colombier 		vtLock(fid->lock);
185e96a66cSDavid du Colombier 		fid->flags = flags;
195e96a66cSDavid du Colombier 	}
205e96a66cSDavid du Colombier 	else
215e96a66cSDavid du Colombier 		vtRLock(fid->lock);
225e96a66cSDavid du Colombier 
235e96a66cSDavid du Colombier 	/*
245e96a66cSDavid du Colombier 	 * Callers of file* routines are expected to lock fsys->fs->elk
255e96a66cSDavid du Colombier 	 * before making any calls in order to make sure the epoch doesn't
265e96a66cSDavid du Colombier 	 * change underfoot. With the exception of Tversion and Tattach,
275e96a66cSDavid du Colombier 	 * that implies all 9P functions need to lock on entry and unlock
285e96a66cSDavid du Colombier 	 * on exit. Fortunately, the general case is the 9P functions do
295e96a66cSDavid du Colombier 	 * fidGet on entry and fidPut on exit, so this is a convenient place
305e96a66cSDavid du Colombier 	 * to do the locking.
315e96a66cSDavid du Colombier 	 * No fsys->fs->elk lock is required if the fid is being created
325e96a66cSDavid du Colombier 	 * (Tauth, Tattach and Twalk). FidFCreate is always accompanied by
335e96a66cSDavid du Colombier 	 * FidFWlock so the setting and testing of FidFCreate here and in
345e96a66cSDavid du Colombier 	 * fidUnlock below is always done under fid->lock.
355e96a66cSDavid du Colombier 	 * A side effect is that fidFree is called with the fid locked, and
365e96a66cSDavid du Colombier 	 * must call fidUnlock only after it has disposed of any File
375e96a66cSDavid du Colombier 	 * resources still held.
385e96a66cSDavid du Colombier 	 */
395e96a66cSDavid du Colombier 	if(!(flags & FidFCreate))
405e96a66cSDavid du Colombier 		fsysFsRlock(fid->fsys);
415e96a66cSDavid du Colombier }
425e96a66cSDavid du Colombier 
435e96a66cSDavid du Colombier static void
fidUnlock(Fid * fid)445e96a66cSDavid du Colombier fidUnlock(Fid* fid)
455e96a66cSDavid du Colombier {
465e96a66cSDavid du Colombier 	if(!(fid->flags & FidFCreate))
475e96a66cSDavid du Colombier 		fsysFsRUnlock(fid->fsys);
485e96a66cSDavid du Colombier 	if(fid->flags & FidFWlock){
495e96a66cSDavid du Colombier 		fid->flags = 0;
505e96a66cSDavid du Colombier 		vtUnlock(fid->lock);
515e96a66cSDavid du Colombier 		return;
525e96a66cSDavid du Colombier 	}
535e96a66cSDavid du Colombier 	vtRUnlock(fid->lock);
545e96a66cSDavid du Colombier }
555e96a66cSDavid du Colombier 
565e96a66cSDavid du Colombier static Fid*
fidAlloc(void)575e96a66cSDavid du Colombier fidAlloc(void)
585e96a66cSDavid du Colombier {
595e96a66cSDavid du Colombier 	Fid *fid;
605e96a66cSDavid du Colombier 
615e96a66cSDavid du Colombier 	vtLock(fbox.lock);
625e96a66cSDavid du Colombier 	if(fbox.nfree > 0){
635e96a66cSDavid du Colombier 		fid = fbox.free;
645e96a66cSDavid du Colombier 		fbox.free = fid->hash;
655e96a66cSDavid du Colombier 		fbox.nfree--;
665e96a66cSDavid du Colombier 	}
675e96a66cSDavid du Colombier 	else{
685e96a66cSDavid du Colombier 		fid = vtMemAllocZ(sizeof(Fid));
695e96a66cSDavid du Colombier 		fid->lock = vtLockAlloc();
705e96a66cSDavid du Colombier 		fid->alock = vtLockAlloc();
715e96a66cSDavid du Colombier 	}
725e96a66cSDavid du Colombier 	fbox.inuse++;
735e96a66cSDavid du Colombier 	vtUnlock(fbox.lock);
745e96a66cSDavid du Colombier 
755e96a66cSDavid du Colombier 	fid->con = nil;
765e96a66cSDavid du Colombier 	fid->fidno = NOFID;
775e96a66cSDavid du Colombier 	fid->ref = 0;
785e96a66cSDavid du Colombier 	fid->flags = 0;
795e96a66cSDavid du Colombier 	fid->open = FidOCreate;
8034e04225SDavid du Colombier 	assert(fid->fsys == nil);
815e96a66cSDavid du Colombier 	assert(fid->file == nil);
825e96a66cSDavid du Colombier 	fid->qid = (Qid){0, 0, 0};
835e96a66cSDavid du Colombier 	assert(fid->uid == nil);
845e96a66cSDavid du Colombier 	assert(fid->uname == nil);
855e96a66cSDavid du Colombier 	assert(fid->db == nil);
865e96a66cSDavid du Colombier 	assert(fid->excl == nil);
875e96a66cSDavid du Colombier 	assert(fid->rpc == nil);
885e96a66cSDavid du Colombier 	assert(fid->cuname == nil);
895e96a66cSDavid du Colombier 	fid->hash = fid->next = fid->prev = nil;
905e96a66cSDavid du Colombier 
915e96a66cSDavid du Colombier 	return fid;
925e96a66cSDavid du Colombier }
935e96a66cSDavid du Colombier 
945e96a66cSDavid du Colombier static void
fidFree(Fid * fid)955e96a66cSDavid du Colombier fidFree(Fid* fid)
965e96a66cSDavid du Colombier {
975e96a66cSDavid du Colombier 	if(fid->file != nil){
985e96a66cSDavid du Colombier 		fileDecRef(fid->file);
995e96a66cSDavid du Colombier 		fid->file = nil;
1005e96a66cSDavid du Colombier 	}
1015e96a66cSDavid du Colombier 	if(fid->db != nil){
1025e96a66cSDavid du Colombier 		dirBufFree(fid->db);
1035e96a66cSDavid du Colombier 		fid->db = nil;
1045e96a66cSDavid du Colombier 	}
1055e96a66cSDavid du Colombier 	fidUnlock(fid);
1065e96a66cSDavid du Colombier 
1075e96a66cSDavid du Colombier 	if(fid->uid != nil){
1085e96a66cSDavid du Colombier 		vtMemFree(fid->uid);
1095e96a66cSDavid du Colombier 		fid->uid = nil;
1105e96a66cSDavid du Colombier 	}
1115e96a66cSDavid du Colombier 	if(fid->uname != nil){
1125e96a66cSDavid du Colombier 		vtMemFree(fid->uname);
1135e96a66cSDavid du Colombier 		fid->uname = nil;
1145e96a66cSDavid du Colombier 	}
1155e96a66cSDavid du Colombier 	if(fid->excl != nil)
1165e96a66cSDavid du Colombier 		exclFree(fid);
1175e96a66cSDavid du Colombier 	if(fid->rpc != nil){
1185e96a66cSDavid du Colombier 		close(fid->rpc->afd);
1195e96a66cSDavid du Colombier 		auth_freerpc(fid->rpc);
1205e96a66cSDavid du Colombier 		fid->rpc = nil;
1215e96a66cSDavid du Colombier 	}
1225e96a66cSDavid du Colombier 	if(fid->fsys != nil){
1235e96a66cSDavid du Colombier 		fsysPut(fid->fsys);
1245e96a66cSDavid du Colombier 		fid->fsys = nil;
1255e96a66cSDavid du Colombier 	}
1265e96a66cSDavid du Colombier 	if(fid->cuname != nil){
1275e96a66cSDavid du Colombier 		vtMemFree(fid->cuname);
1285e96a66cSDavid du Colombier 		fid->cuname = nil;
1295e96a66cSDavid du Colombier 	}
1305e96a66cSDavid du Colombier 
1315e96a66cSDavid du Colombier 	vtLock(fbox.lock);
1325e96a66cSDavid du Colombier 	fbox.inuse--;
1335e96a66cSDavid du Colombier 	if(fbox.nfree < 10){
1345e96a66cSDavid du Colombier 		fid->hash = fbox.free;
1355e96a66cSDavid du Colombier 		fbox.free = fid;
1365e96a66cSDavid du Colombier 		fbox.nfree++;
1375e96a66cSDavid du Colombier 	}
1385e96a66cSDavid du Colombier 	else{
1395e96a66cSDavid du Colombier 		vtLockFree(fid->alock);
1405e96a66cSDavid du Colombier 		vtLockFree(fid->lock);
1415e96a66cSDavid du Colombier 		vtMemFree(fid);
1425e96a66cSDavid du Colombier 	}
1435e96a66cSDavid du Colombier 	vtUnlock(fbox.lock);
1445e96a66cSDavid du Colombier }
1455e96a66cSDavid du Colombier 
1465e96a66cSDavid du Colombier static void
fidUnHash(Fid * fid)1475e96a66cSDavid du Colombier fidUnHash(Fid* fid)
1485e96a66cSDavid du Colombier {
1495e96a66cSDavid du Colombier 	Fid *fp, **hash;
1505e96a66cSDavid du Colombier 
1515e96a66cSDavid du Colombier 	assert(fid->ref == 0);
1525e96a66cSDavid du Colombier 
1535e96a66cSDavid du Colombier 	hash = &fid->con->fidhash[fid->fidno % NFidHash];
1545e96a66cSDavid du Colombier 	for(fp = *hash; fp != nil; fp = fp->hash){
1555e96a66cSDavid du Colombier 		if(fp == fid){
1565e96a66cSDavid du Colombier 			*hash = fp->hash;
1575e96a66cSDavid du Colombier 			break;
1585e96a66cSDavid du Colombier 		}
1595e96a66cSDavid du Colombier 		hash = &fp->hash;
1605e96a66cSDavid du Colombier 	}
1615e96a66cSDavid du Colombier 	assert(fp == fid);
1625e96a66cSDavid du Colombier 
1635e96a66cSDavid du Colombier 	if(fid->prev != nil)
1645e96a66cSDavid du Colombier 		fid->prev->next = fid->next;
1655e96a66cSDavid du Colombier 	else
1665e96a66cSDavid du Colombier 		fid->con->fhead = fid->next;
1675e96a66cSDavid du Colombier 	if(fid->next != nil)
1685e96a66cSDavid du Colombier 		fid->next->prev = fid->prev;
1695e96a66cSDavid du Colombier 	else
1705e96a66cSDavid du Colombier 		fid->con->ftail = fid->prev;
1715e96a66cSDavid du Colombier 	fid->prev = fid->next = nil;
1725e96a66cSDavid du Colombier 
1735e96a66cSDavid du Colombier 	fid->con->nfid--;
1745e96a66cSDavid du Colombier }
1755e96a66cSDavid du Colombier 
1765e96a66cSDavid du Colombier Fid*
fidGet(Con * con,u32int fidno,int flags)1775e96a66cSDavid du Colombier fidGet(Con* con, u32int fidno, int flags)
1785e96a66cSDavid du Colombier {
1795e96a66cSDavid du Colombier 	Fid *fid, **hash;
1805e96a66cSDavid du Colombier 
1815e96a66cSDavid du Colombier 	if(fidno == NOFID)
1825e96a66cSDavid du Colombier 		return nil;
1835e96a66cSDavid du Colombier 
1845e96a66cSDavid du Colombier 	hash = &con->fidhash[fidno % NFidHash];
1855e96a66cSDavid du Colombier 	vtLock(con->fidlock);
1865e96a66cSDavid du Colombier 	for(fid = *hash; fid != nil; fid = fid->hash){
1875e96a66cSDavid du Colombier 		if(fid->fidno != fidno)
1885e96a66cSDavid du Colombier 			continue;
1895e96a66cSDavid du Colombier 
1905e96a66cSDavid du Colombier 		/*
1915e96a66cSDavid du Colombier 		 * Already in use is an error
1925e96a66cSDavid du Colombier 		 * when called from attach, clone or walk.
1935e96a66cSDavid du Colombier 		 */
1945e96a66cSDavid du Colombier 		if(flags & FidFCreate){
1955e96a66cSDavid du Colombier 			vtUnlock(con->fidlock);
196*36066be0SDavid du Colombier 			vtSetError("%s: fid 0x%ud in use", argv0, fidno);
1975e96a66cSDavid du Colombier 			return nil;
1985e96a66cSDavid du Colombier 		}
1995e96a66cSDavid du Colombier 		fid->ref++;
2005e96a66cSDavid du Colombier 		vtUnlock(con->fidlock);
2015e96a66cSDavid du Colombier 
2025e96a66cSDavid du Colombier 		fidLock(fid, flags);
2035e96a66cSDavid du Colombier 		if((fid->open & FidOCreate) || fid->fidno == NOFID){
2045e96a66cSDavid du Colombier 			fidPut(fid);
205*36066be0SDavid du Colombier 			vtSetError("%s: fid invalid", argv0);
2065e96a66cSDavid du Colombier 			return nil;
2075e96a66cSDavid du Colombier 		}
2085e96a66cSDavid du Colombier 		return fid;
2095e96a66cSDavid du Colombier 	}
2105e96a66cSDavid du Colombier 
2115e96a66cSDavid du Colombier 	if((flags & FidFCreate) && (fid = fidAlloc()) != nil){
2125e96a66cSDavid du Colombier 		assert(flags & FidFWlock);
2135e96a66cSDavid du Colombier 		fid->con = con;
2145e96a66cSDavid du Colombier 		fid->fidno = fidno;
2155e96a66cSDavid du Colombier 		fid->ref = 1;
2165e96a66cSDavid du Colombier 
2175e96a66cSDavid du Colombier 		fid->hash = *hash;
2185e96a66cSDavid du Colombier 		*hash = fid;
2195e96a66cSDavid du Colombier 		if(con->ftail != nil){
2205e96a66cSDavid du Colombier 			fid->prev = con->ftail;
2215e96a66cSDavid du Colombier 			con->ftail->next = fid;
2225e96a66cSDavid du Colombier 		}
2235e96a66cSDavid du Colombier 		else{
2245e96a66cSDavid du Colombier 			con->fhead = fid;
2255e96a66cSDavid du Colombier 			fid->prev = nil;
2265e96a66cSDavid du Colombier 		}
2275e96a66cSDavid du Colombier 		con->ftail = fid;
2285e96a66cSDavid du Colombier 		fid->next = nil;
2295e96a66cSDavid du Colombier 
2305e96a66cSDavid du Colombier 		con->nfid++;
2315e96a66cSDavid du Colombier 		vtUnlock(con->fidlock);
2325e96a66cSDavid du Colombier 
2335e96a66cSDavid du Colombier 		/*
2345e96a66cSDavid du Colombier 		 * The FidOCreate flag is used to prevent any
2355e96a66cSDavid du Colombier 		 * accidental access to the Fid between unlocking the
2365e96a66cSDavid du Colombier 		 * hash and acquiring the Fid lock for return.
2375e96a66cSDavid du Colombier 		 */
2385e96a66cSDavid du Colombier 		fidLock(fid, flags);
2395e96a66cSDavid du Colombier 		fid->open &= ~FidOCreate;
2405e96a66cSDavid du Colombier 		return fid;
2415e96a66cSDavid du Colombier 	}
2425e96a66cSDavid du Colombier 	vtUnlock(con->fidlock);
2435e96a66cSDavid du Colombier 
244*36066be0SDavid du Colombier 	vtSetError("%s: fid not found", argv0);
2455e96a66cSDavid du Colombier 	return nil;
2465e96a66cSDavid du Colombier }
2475e96a66cSDavid du Colombier 
2485e96a66cSDavid du Colombier void
fidPut(Fid * fid)2495e96a66cSDavid du Colombier fidPut(Fid* fid)
2505e96a66cSDavid du Colombier {
2515e96a66cSDavid du Colombier 	vtLock(fid->con->fidlock);
2525e96a66cSDavid du Colombier 	assert(fid->ref > 0);
2535e96a66cSDavid du Colombier 	fid->ref--;
2545e96a66cSDavid du Colombier 	vtUnlock(fid->con->fidlock);
2555e96a66cSDavid du Colombier 
2565e96a66cSDavid du Colombier 	if(fid->ref == 0 && fid->fidno == NOFID){
2575e96a66cSDavid du Colombier 		fidFree(fid);
2585e96a66cSDavid du Colombier 		return;
2595e96a66cSDavid du Colombier 	}
2605e96a66cSDavid du Colombier 	fidUnlock(fid);
2615e96a66cSDavid du Colombier }
2625e96a66cSDavid du Colombier 
2635e96a66cSDavid du Colombier void
fidClunk(Fid * fid)2645e96a66cSDavid du Colombier fidClunk(Fid* fid)
2655e96a66cSDavid du Colombier {
2665e96a66cSDavid du Colombier 	assert(fid->flags & FidFWlock);
2675e96a66cSDavid du Colombier 
2685e96a66cSDavid du Colombier 	vtLock(fid->con->fidlock);
2695e96a66cSDavid du Colombier 	assert(fid->ref > 0);
2705e96a66cSDavid du Colombier 	fid->ref--;
2715e96a66cSDavid du Colombier 	fidUnHash(fid);
2725e96a66cSDavid du Colombier 	fid->fidno = NOFID;
2735e96a66cSDavid du Colombier 	vtUnlock(fid->con->fidlock);
2745e96a66cSDavid du Colombier 
2755e96a66cSDavid du Colombier 	if(fid->ref > 0){
276decede3dSDavid du Colombier 		/* not reached - fidUnHash requires ref == 0 */
2775e96a66cSDavid du Colombier 		fidUnlock(fid);
2785e96a66cSDavid du Colombier 		return;
2795e96a66cSDavid du Colombier 	}
2805e96a66cSDavid du Colombier 	fidFree(fid);
2815e96a66cSDavid du Colombier }
2825e96a66cSDavid du Colombier 
2835e96a66cSDavid du Colombier void
fidClunkAll(Con * con)28434e04225SDavid du Colombier fidClunkAll(Con* con)
28534e04225SDavid du Colombier {
28634e04225SDavid du Colombier 	Fid *fid;
28734e04225SDavid du Colombier 	u32int fidno;
28834e04225SDavid du Colombier 
28934e04225SDavid du Colombier 	vtLock(con->fidlock);
29034e04225SDavid du Colombier 	while(con->fhead != nil){
29134e04225SDavid du Colombier 		fidno = con->fhead->fidno;
29234e04225SDavid du Colombier 		vtUnlock(con->fidlock);
29334e04225SDavid du Colombier 		if((fid = fidGet(con, fidno, FidFWlock)) != nil)
29434e04225SDavid du Colombier 			fidClunk(fid);
29534e04225SDavid du Colombier 		vtLock(con->fidlock);
29634e04225SDavid du Colombier 	}
29734e04225SDavid du Colombier 	vtUnlock(con->fidlock);
29834e04225SDavid du Colombier }
29934e04225SDavid du Colombier 
30034e04225SDavid du Colombier void
fidInit(void)3015e96a66cSDavid du Colombier fidInit(void)
3025e96a66cSDavid du Colombier {
3035e96a66cSDavid du Colombier 	fbox.lock = vtLockAlloc();
3045e96a66cSDavid du Colombier }
305