15e96a66cSDavid du Colombier #include "stdinc.h"
25e96a66cSDavid du Colombier
35e96a66cSDavid du Colombier #include "9.h"
45e96a66cSDavid du Colombier
55e96a66cSDavid du Colombier static struct {
6*d7aba6c3SDavid du Colombier QLock 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){
17*d7aba6c3SDavid du Colombier wlock(&fid->lock);
185e96a66cSDavid du Colombier fid->flags = flags;
195e96a66cSDavid du Colombier }
205e96a66cSDavid du Colombier else
21*d7aba6c3SDavid du Colombier rlock(&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;
50*d7aba6c3SDavid du Colombier wunlock(&fid->lock);
515e96a66cSDavid du Colombier return;
525e96a66cSDavid du Colombier }
53*d7aba6c3SDavid du Colombier runlock(&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
61*d7aba6c3SDavid du Colombier qlock(&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{
68*d7aba6c3SDavid du Colombier fid = vtmallocz(sizeof(Fid));
695e96a66cSDavid du Colombier }
705e96a66cSDavid du Colombier fbox.inuse++;
71*d7aba6c3SDavid du Colombier qunlock(&fbox.lock);
725e96a66cSDavid du Colombier
735e96a66cSDavid du Colombier fid->con = nil;
745e96a66cSDavid du Colombier fid->fidno = NOFID;
755e96a66cSDavid du Colombier fid->ref = 0;
765e96a66cSDavid du Colombier fid->flags = 0;
775e96a66cSDavid du Colombier fid->open = FidOCreate;
7834e04225SDavid du Colombier assert(fid->fsys == nil);
795e96a66cSDavid du Colombier assert(fid->file == nil);
805e96a66cSDavid du Colombier fid->qid = (Qid){0, 0, 0};
815e96a66cSDavid du Colombier assert(fid->uid == nil);
825e96a66cSDavid du Colombier assert(fid->uname == nil);
835e96a66cSDavid du Colombier assert(fid->db == nil);
845e96a66cSDavid du Colombier assert(fid->excl == nil);
855e96a66cSDavid du Colombier assert(fid->rpc == nil);
865e96a66cSDavid du Colombier assert(fid->cuname == nil);
875e96a66cSDavid du Colombier fid->hash = fid->next = fid->prev = nil;
885e96a66cSDavid du Colombier
895e96a66cSDavid du Colombier return fid;
905e96a66cSDavid du Colombier }
915e96a66cSDavid du Colombier
925e96a66cSDavid du Colombier static void
fidFree(Fid * fid)935e96a66cSDavid du Colombier fidFree(Fid* fid)
945e96a66cSDavid du Colombier {
955e96a66cSDavid du Colombier if(fid->file != nil){
965e96a66cSDavid du Colombier fileDecRef(fid->file);
975e96a66cSDavid du Colombier fid->file = nil;
985e96a66cSDavid du Colombier }
995e96a66cSDavid du Colombier if(fid->db != nil){
1005e96a66cSDavid du Colombier dirBufFree(fid->db);
1015e96a66cSDavid du Colombier fid->db = nil;
1025e96a66cSDavid du Colombier }
1035e96a66cSDavid du Colombier fidUnlock(fid);
1045e96a66cSDavid du Colombier
1055e96a66cSDavid du Colombier if(fid->uid != nil){
106*d7aba6c3SDavid du Colombier vtfree(fid->uid);
1075e96a66cSDavid du Colombier fid->uid = nil;
1085e96a66cSDavid du Colombier }
1095e96a66cSDavid du Colombier if(fid->uname != nil){
110*d7aba6c3SDavid du Colombier vtfree(fid->uname);
1115e96a66cSDavid du Colombier fid->uname = nil;
1125e96a66cSDavid du Colombier }
1135e96a66cSDavid du Colombier if(fid->excl != nil)
1145e96a66cSDavid du Colombier exclFree(fid);
1155e96a66cSDavid du Colombier if(fid->rpc != nil){
1165e96a66cSDavid du Colombier close(fid->rpc->afd);
1175e96a66cSDavid du Colombier auth_freerpc(fid->rpc);
1185e96a66cSDavid du Colombier fid->rpc = nil;
1195e96a66cSDavid du Colombier }
1205e96a66cSDavid du Colombier if(fid->fsys != nil){
1215e96a66cSDavid du Colombier fsysPut(fid->fsys);
1225e96a66cSDavid du Colombier fid->fsys = nil;
1235e96a66cSDavid du Colombier }
1245e96a66cSDavid du Colombier if(fid->cuname != nil){
125*d7aba6c3SDavid du Colombier vtfree(fid->cuname);
1265e96a66cSDavid du Colombier fid->cuname = nil;
1275e96a66cSDavid du Colombier }
1285e96a66cSDavid du Colombier
129*d7aba6c3SDavid du Colombier qlock(&fbox.lock);
1305e96a66cSDavid du Colombier fbox.inuse--;
1315e96a66cSDavid du Colombier if(fbox.nfree < 10){
1325e96a66cSDavid du Colombier fid->hash = fbox.free;
1335e96a66cSDavid du Colombier fbox.free = fid;
1345e96a66cSDavid du Colombier fbox.nfree++;
1355e96a66cSDavid du Colombier }
1365e96a66cSDavid du Colombier else{
137*d7aba6c3SDavid du Colombier vtfree(fid);
1385e96a66cSDavid du Colombier }
139*d7aba6c3SDavid du Colombier qunlock(&fbox.lock);
1405e96a66cSDavid du Colombier }
1415e96a66cSDavid du Colombier
1425e96a66cSDavid du Colombier static void
fidUnHash(Fid * fid)1435e96a66cSDavid du Colombier fidUnHash(Fid* fid)
1445e96a66cSDavid du Colombier {
1455e96a66cSDavid du Colombier Fid *fp, **hash;
1465e96a66cSDavid du Colombier
1475e96a66cSDavid du Colombier assert(fid->ref == 0);
1485e96a66cSDavid du Colombier
1495e96a66cSDavid du Colombier hash = &fid->con->fidhash[fid->fidno % NFidHash];
1505e96a66cSDavid du Colombier for(fp = *hash; fp != nil; fp = fp->hash){
1515e96a66cSDavid du Colombier if(fp == fid){
1525e96a66cSDavid du Colombier *hash = fp->hash;
1535e96a66cSDavid du Colombier break;
1545e96a66cSDavid du Colombier }
1555e96a66cSDavid du Colombier hash = &fp->hash;
1565e96a66cSDavid du Colombier }
1575e96a66cSDavid du Colombier assert(fp == fid);
1585e96a66cSDavid du Colombier
1595e96a66cSDavid du Colombier if(fid->prev != nil)
1605e96a66cSDavid du Colombier fid->prev->next = fid->next;
1615e96a66cSDavid du Colombier else
1625e96a66cSDavid du Colombier fid->con->fhead = fid->next;
1635e96a66cSDavid du Colombier if(fid->next != nil)
1645e96a66cSDavid du Colombier fid->next->prev = fid->prev;
1655e96a66cSDavid du Colombier else
1665e96a66cSDavid du Colombier fid->con->ftail = fid->prev;
1675e96a66cSDavid du Colombier fid->prev = fid->next = nil;
1685e96a66cSDavid du Colombier
1695e96a66cSDavid du Colombier fid->con->nfid--;
1705e96a66cSDavid du Colombier }
1715e96a66cSDavid du Colombier
1725e96a66cSDavid du Colombier Fid*
fidGet(Con * con,u32int fidno,int flags)1735e96a66cSDavid du Colombier fidGet(Con* con, u32int fidno, int flags)
1745e96a66cSDavid du Colombier {
1755e96a66cSDavid du Colombier Fid *fid, **hash;
1765e96a66cSDavid du Colombier
1775e96a66cSDavid du Colombier if(fidno == NOFID)
1785e96a66cSDavid du Colombier return nil;
1795e96a66cSDavid du Colombier
1805e96a66cSDavid du Colombier hash = &con->fidhash[fidno % NFidHash];
181*d7aba6c3SDavid du Colombier qlock(&con->fidlock);
1825e96a66cSDavid du Colombier for(fid = *hash; fid != nil; fid = fid->hash){
1835e96a66cSDavid du Colombier if(fid->fidno != fidno)
1845e96a66cSDavid du Colombier continue;
1855e96a66cSDavid du Colombier
1865e96a66cSDavid du Colombier /*
1875e96a66cSDavid du Colombier * Already in use is an error
1885e96a66cSDavid du Colombier * when called from attach, clone or walk.
1895e96a66cSDavid du Colombier */
1905e96a66cSDavid du Colombier if(flags & FidFCreate){
191*d7aba6c3SDavid du Colombier qunlock(&con->fidlock);
192*d7aba6c3SDavid du Colombier werrstr("%s: fid 0x%ud in use", argv0, fidno);
1935e96a66cSDavid du Colombier return nil;
1945e96a66cSDavid du Colombier }
1955e96a66cSDavid du Colombier fid->ref++;
196*d7aba6c3SDavid du Colombier qunlock(&con->fidlock);
1975e96a66cSDavid du Colombier
1985e96a66cSDavid du Colombier fidLock(fid, flags);
1995e96a66cSDavid du Colombier if((fid->open & FidOCreate) || fid->fidno == NOFID){
2005e96a66cSDavid du Colombier fidPut(fid);
201*d7aba6c3SDavid du Colombier werrstr("%s: fid invalid", argv0);
2025e96a66cSDavid du Colombier return nil;
2035e96a66cSDavid du Colombier }
2045e96a66cSDavid du Colombier return fid;
2055e96a66cSDavid du Colombier }
2065e96a66cSDavid du Colombier
2075e96a66cSDavid du Colombier if((flags & FidFCreate) && (fid = fidAlloc()) != nil){
2085e96a66cSDavid du Colombier assert(flags & FidFWlock);
2095e96a66cSDavid du Colombier fid->con = con;
2105e96a66cSDavid du Colombier fid->fidno = fidno;
2115e96a66cSDavid du Colombier fid->ref = 1;
2125e96a66cSDavid du Colombier
2135e96a66cSDavid du Colombier fid->hash = *hash;
2145e96a66cSDavid du Colombier *hash = fid;
2155e96a66cSDavid du Colombier if(con->ftail != nil){
2165e96a66cSDavid du Colombier fid->prev = con->ftail;
2175e96a66cSDavid du Colombier con->ftail->next = fid;
2185e96a66cSDavid du Colombier }
2195e96a66cSDavid du Colombier else{
2205e96a66cSDavid du Colombier con->fhead = fid;
2215e96a66cSDavid du Colombier fid->prev = nil;
2225e96a66cSDavid du Colombier }
2235e96a66cSDavid du Colombier con->ftail = fid;
2245e96a66cSDavid du Colombier fid->next = nil;
2255e96a66cSDavid du Colombier
2265e96a66cSDavid du Colombier con->nfid++;
227*d7aba6c3SDavid du Colombier qunlock(&con->fidlock);
2285e96a66cSDavid du Colombier
2295e96a66cSDavid du Colombier /*
2305e96a66cSDavid du Colombier * The FidOCreate flag is used to prevent any
2315e96a66cSDavid du Colombier * accidental access to the Fid between unlocking the
2325e96a66cSDavid du Colombier * hash and acquiring the Fid lock for return.
2335e96a66cSDavid du Colombier */
2345e96a66cSDavid du Colombier fidLock(fid, flags);
2355e96a66cSDavid du Colombier fid->open &= ~FidOCreate;
2365e96a66cSDavid du Colombier return fid;
2375e96a66cSDavid du Colombier }
238*d7aba6c3SDavid du Colombier qunlock(&con->fidlock);
2395e96a66cSDavid du Colombier
240*d7aba6c3SDavid du Colombier werrstr("%s: fid not found", argv0);
2415e96a66cSDavid du Colombier return nil;
2425e96a66cSDavid du Colombier }
2435e96a66cSDavid du Colombier
2445e96a66cSDavid du Colombier void
fidPut(Fid * fid)2455e96a66cSDavid du Colombier fidPut(Fid* fid)
2465e96a66cSDavid du Colombier {
247*d7aba6c3SDavid du Colombier qlock(&fid->con->fidlock);
2485e96a66cSDavid du Colombier assert(fid->ref > 0);
2495e96a66cSDavid du Colombier fid->ref--;
250*d7aba6c3SDavid du Colombier qunlock(&fid->con->fidlock);
2515e96a66cSDavid du Colombier
2525e96a66cSDavid du Colombier if(fid->ref == 0 && fid->fidno == NOFID){
2535e96a66cSDavid du Colombier fidFree(fid);
2545e96a66cSDavid du Colombier return;
2555e96a66cSDavid du Colombier }
2565e96a66cSDavid du Colombier fidUnlock(fid);
2575e96a66cSDavid du Colombier }
2585e96a66cSDavid du Colombier
2595e96a66cSDavid du Colombier void
fidClunk(Fid * fid)2605e96a66cSDavid du Colombier fidClunk(Fid* fid)
2615e96a66cSDavid du Colombier {
2625e96a66cSDavid du Colombier assert(fid->flags & FidFWlock);
2635e96a66cSDavid du Colombier
264*d7aba6c3SDavid du Colombier qlock(&fid->con->fidlock);
2655e96a66cSDavid du Colombier assert(fid->ref > 0);
2665e96a66cSDavid du Colombier fid->ref--;
2675e96a66cSDavid du Colombier fidUnHash(fid);
2685e96a66cSDavid du Colombier fid->fidno = NOFID;
269*d7aba6c3SDavid du Colombier qunlock(&fid->con->fidlock);
2705e96a66cSDavid du Colombier
2715e96a66cSDavid du Colombier if(fid->ref > 0){
272decede3dSDavid du Colombier /* not reached - fidUnHash requires ref == 0 */
2735e96a66cSDavid du Colombier fidUnlock(fid);
2745e96a66cSDavid du Colombier return;
2755e96a66cSDavid du Colombier }
2765e96a66cSDavid du Colombier fidFree(fid);
2775e96a66cSDavid du Colombier }
2785e96a66cSDavid du Colombier
2795e96a66cSDavid du Colombier void
fidClunkAll(Con * con)28034e04225SDavid du Colombier fidClunkAll(Con* con)
28134e04225SDavid du Colombier {
28234e04225SDavid du Colombier Fid *fid;
28334e04225SDavid du Colombier u32int fidno;
28434e04225SDavid du Colombier
285*d7aba6c3SDavid du Colombier qlock(&con->fidlock);
28634e04225SDavid du Colombier while(con->fhead != nil){
28734e04225SDavid du Colombier fidno = con->fhead->fidno;
288*d7aba6c3SDavid du Colombier qunlock(&con->fidlock);
28934e04225SDavid du Colombier if((fid = fidGet(con, fidno, FidFWlock)) != nil)
29034e04225SDavid du Colombier fidClunk(fid);
291*d7aba6c3SDavid du Colombier qlock(&con->fidlock);
29234e04225SDavid du Colombier }
293*d7aba6c3SDavid du Colombier qunlock(&con->fidlock);
29434e04225SDavid du Colombier }
29534e04225SDavid du Colombier
29634e04225SDavid du Colombier void
fidInit(void)2975e96a66cSDavid du Colombier fidInit(void)
2985e96a66cSDavid du Colombier {
2995e96a66cSDavid du Colombier }
300