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