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 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 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* 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; 80*34e04225SDavid 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 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 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* 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); 1965e96a66cSDavid du Colombier vtSetError("fid in use"); 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); 2055e96a66cSDavid du Colombier vtSetError("fid invalid"); 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 2445e96a66cSDavid du Colombier vtSetError("fid not found"); 2455e96a66cSDavid du Colombier return nil; 2465e96a66cSDavid du Colombier } 2475e96a66cSDavid du Colombier 2485e96a66cSDavid du Colombier void 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 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){ 2765e96a66cSDavid du Colombier fidUnlock(fid); 2775e96a66cSDavid du Colombier return; 2785e96a66cSDavid du Colombier } 2795e96a66cSDavid du Colombier fidFree(fid); 2805e96a66cSDavid du Colombier } 2815e96a66cSDavid du Colombier 2825e96a66cSDavid du Colombier void 283*34e04225SDavid du Colombier fidClunkAll(Con* con) 284*34e04225SDavid du Colombier { 285*34e04225SDavid du Colombier Fid *fid; 286*34e04225SDavid du Colombier u32int fidno; 287*34e04225SDavid du Colombier 288*34e04225SDavid du Colombier vtLock(con->fidlock); 289*34e04225SDavid du Colombier while(con->fhead != nil){ 290*34e04225SDavid du Colombier fidno = con->fhead->fidno; 291*34e04225SDavid du Colombier vtUnlock(con->fidlock); 292*34e04225SDavid du Colombier if((fid = fidGet(con, fidno, FidFWlock)) != nil) 293*34e04225SDavid du Colombier fidClunk(fid); 294*34e04225SDavid du Colombier vtLock(con->fidlock); 295*34e04225SDavid du Colombier } 296*34e04225SDavid du Colombier vtUnlock(con->fidlock); 297*34e04225SDavid du Colombier } 298*34e04225SDavid du Colombier 299*34e04225SDavid du Colombier void 3005e96a66cSDavid du Colombier fidInit(void) 3015e96a66cSDavid du Colombier { 3025e96a66cSDavid du Colombier fbox.lock = vtLockAlloc(); 3035e96a66cSDavid du Colombier } 304