1*5e96a66cSDavid du Colombier #include "stdinc.h" 2*5e96a66cSDavid du Colombier 3*5e96a66cSDavid du Colombier #include "9.h" 4*5e96a66cSDavid du Colombier 5*5e96a66cSDavid du Colombier static struct { 6*5e96a66cSDavid du Colombier VtLock* lock; 7*5e96a66cSDavid du Colombier 8*5e96a66cSDavid du Colombier Fid* free; 9*5e96a66cSDavid du Colombier int nfree; 10*5e96a66cSDavid du Colombier int inuse; 11*5e96a66cSDavid du Colombier } fbox; 12*5e96a66cSDavid du Colombier 13*5e96a66cSDavid du Colombier static void 14*5e96a66cSDavid du Colombier fidLock(Fid* fid, int flags) 15*5e96a66cSDavid du Colombier { 16*5e96a66cSDavid du Colombier if(flags & FidFWlock){ 17*5e96a66cSDavid du Colombier vtLock(fid->lock); 18*5e96a66cSDavid du Colombier fid->flags = flags; 19*5e96a66cSDavid du Colombier } 20*5e96a66cSDavid du Colombier else 21*5e96a66cSDavid du Colombier vtRLock(fid->lock); 22*5e96a66cSDavid du Colombier 23*5e96a66cSDavid du Colombier /* 24*5e96a66cSDavid du Colombier * Callers of file* routines are expected to lock fsys->fs->elk 25*5e96a66cSDavid du Colombier * before making any calls in order to make sure the epoch doesn't 26*5e96a66cSDavid du Colombier * change underfoot. With the exception of Tversion and Tattach, 27*5e96a66cSDavid du Colombier * that implies all 9P functions need to lock on entry and unlock 28*5e96a66cSDavid du Colombier * on exit. Fortunately, the general case is the 9P functions do 29*5e96a66cSDavid du Colombier * fidGet on entry and fidPut on exit, so this is a convenient place 30*5e96a66cSDavid du Colombier * to do the locking. 31*5e96a66cSDavid du Colombier * No fsys->fs->elk lock is required if the fid is being created 32*5e96a66cSDavid du Colombier * (Tauth, Tattach and Twalk). FidFCreate is always accompanied by 33*5e96a66cSDavid du Colombier * FidFWlock so the setting and testing of FidFCreate here and in 34*5e96a66cSDavid du Colombier * fidUnlock below is always done under fid->lock. 35*5e96a66cSDavid du Colombier * A side effect is that fidFree is called with the fid locked, and 36*5e96a66cSDavid du Colombier * must call fidUnlock only after it has disposed of any File 37*5e96a66cSDavid du Colombier * resources still held. 38*5e96a66cSDavid du Colombier */ 39*5e96a66cSDavid du Colombier if(!(flags & FidFCreate)) 40*5e96a66cSDavid du Colombier fsysFsRlock(fid->fsys); 41*5e96a66cSDavid du Colombier } 42*5e96a66cSDavid du Colombier 43*5e96a66cSDavid du Colombier static void 44*5e96a66cSDavid du Colombier fidUnlock(Fid* fid) 45*5e96a66cSDavid du Colombier { 46*5e96a66cSDavid du Colombier if(!(fid->flags & FidFCreate)) 47*5e96a66cSDavid du Colombier fsysFsRUnlock(fid->fsys); 48*5e96a66cSDavid du Colombier if(fid->flags & FidFWlock){ 49*5e96a66cSDavid du Colombier fid->flags = 0; 50*5e96a66cSDavid du Colombier vtUnlock(fid->lock); 51*5e96a66cSDavid du Colombier return; 52*5e96a66cSDavid du Colombier } 53*5e96a66cSDavid du Colombier vtRUnlock(fid->lock); 54*5e96a66cSDavid du Colombier } 55*5e96a66cSDavid du Colombier 56*5e96a66cSDavid du Colombier static Fid* 57*5e96a66cSDavid du Colombier fidAlloc(void) 58*5e96a66cSDavid du Colombier { 59*5e96a66cSDavid du Colombier Fid *fid; 60*5e96a66cSDavid du Colombier 61*5e96a66cSDavid du Colombier vtLock(fbox.lock); 62*5e96a66cSDavid du Colombier if(fbox.nfree > 0){ 63*5e96a66cSDavid du Colombier fid = fbox.free; 64*5e96a66cSDavid du Colombier fbox.free = fid->hash; 65*5e96a66cSDavid du Colombier fbox.nfree--; 66*5e96a66cSDavid du Colombier } 67*5e96a66cSDavid du Colombier else{ 68*5e96a66cSDavid du Colombier fid = vtMemAllocZ(sizeof(Fid)); 69*5e96a66cSDavid du Colombier fid->lock = vtLockAlloc(); 70*5e96a66cSDavid du Colombier fid->alock = vtLockAlloc(); 71*5e96a66cSDavid du Colombier } 72*5e96a66cSDavid du Colombier fbox.inuse++; 73*5e96a66cSDavid du Colombier vtUnlock(fbox.lock); 74*5e96a66cSDavid du Colombier 75*5e96a66cSDavid du Colombier fid->con = nil; 76*5e96a66cSDavid du Colombier fid->fidno = NOFID; 77*5e96a66cSDavid du Colombier fid->ref = 0; 78*5e96a66cSDavid du Colombier fid->flags = 0; 79*5e96a66cSDavid du Colombier fid->open = FidOCreate; 80*5e96a66cSDavid du Colombier assert(fid->file == nil); 81*5e96a66cSDavid du Colombier fid->qid = (Qid){0, 0, 0}; 82*5e96a66cSDavid du Colombier assert(fid->uid == nil); 83*5e96a66cSDavid du Colombier assert(fid->uname == nil); 84*5e96a66cSDavid du Colombier assert(fid->db == nil); 85*5e96a66cSDavid du Colombier assert(fid->excl == nil); 86*5e96a66cSDavid du Colombier assert(fid->rpc == nil); 87*5e96a66cSDavid du Colombier assert(fid->fsys == nil); 88*5e96a66cSDavid du Colombier assert(fid->cuname == nil); 89*5e96a66cSDavid du Colombier fid->hash = fid->next = fid->prev = nil; 90*5e96a66cSDavid du Colombier 91*5e96a66cSDavid du Colombier return fid; 92*5e96a66cSDavid du Colombier } 93*5e96a66cSDavid du Colombier 94*5e96a66cSDavid du Colombier static void 95*5e96a66cSDavid du Colombier fidFree(Fid* fid) 96*5e96a66cSDavid du Colombier { 97*5e96a66cSDavid du Colombier if(fid->file != nil){ 98*5e96a66cSDavid du Colombier fileDecRef(fid->file); 99*5e96a66cSDavid du Colombier fid->file = nil; 100*5e96a66cSDavid du Colombier } 101*5e96a66cSDavid du Colombier if(fid->db != nil){ 102*5e96a66cSDavid du Colombier dirBufFree(fid->db); 103*5e96a66cSDavid du Colombier fid->db = nil; 104*5e96a66cSDavid du Colombier } 105*5e96a66cSDavid du Colombier fidUnlock(fid); 106*5e96a66cSDavid du Colombier 107*5e96a66cSDavid du Colombier if(fid->uid != nil){ 108*5e96a66cSDavid du Colombier vtMemFree(fid->uid); 109*5e96a66cSDavid du Colombier fid->uid = nil; 110*5e96a66cSDavid du Colombier } 111*5e96a66cSDavid du Colombier if(fid->uname != nil){ 112*5e96a66cSDavid du Colombier vtMemFree(fid->uname); 113*5e96a66cSDavid du Colombier fid->uname = nil; 114*5e96a66cSDavid du Colombier } 115*5e96a66cSDavid du Colombier if(fid->excl != nil) 116*5e96a66cSDavid du Colombier exclFree(fid); 117*5e96a66cSDavid du Colombier if(fid->rpc != nil){ 118*5e96a66cSDavid du Colombier close(fid->rpc->afd); 119*5e96a66cSDavid du Colombier auth_freerpc(fid->rpc); 120*5e96a66cSDavid du Colombier fid->rpc = nil; 121*5e96a66cSDavid du Colombier } 122*5e96a66cSDavid du Colombier if(fid->fsys != nil){ 123*5e96a66cSDavid du Colombier fsysPut(fid->fsys); 124*5e96a66cSDavid du Colombier fid->fsys = nil; 125*5e96a66cSDavid du Colombier } 126*5e96a66cSDavid du Colombier if(fid->cuname != nil){ 127*5e96a66cSDavid du Colombier vtMemFree(fid->cuname); 128*5e96a66cSDavid du Colombier fid->cuname = nil; 129*5e96a66cSDavid du Colombier } 130*5e96a66cSDavid du Colombier 131*5e96a66cSDavid du Colombier vtLock(fbox.lock); 132*5e96a66cSDavid du Colombier fbox.inuse--; 133*5e96a66cSDavid du Colombier if(fbox.nfree < 10){ 134*5e96a66cSDavid du Colombier fid->hash = fbox.free; 135*5e96a66cSDavid du Colombier fbox.free = fid; 136*5e96a66cSDavid du Colombier fbox.nfree++; 137*5e96a66cSDavid du Colombier } 138*5e96a66cSDavid du Colombier else{ 139*5e96a66cSDavid du Colombier vtLockFree(fid->alock); 140*5e96a66cSDavid du Colombier vtLockFree(fid->lock); 141*5e96a66cSDavid du Colombier vtMemFree(fid); 142*5e96a66cSDavid du Colombier } 143*5e96a66cSDavid du Colombier vtUnlock(fbox.lock); 144*5e96a66cSDavid du Colombier } 145*5e96a66cSDavid du Colombier 146*5e96a66cSDavid du Colombier static void 147*5e96a66cSDavid du Colombier fidUnHash(Fid* fid) 148*5e96a66cSDavid du Colombier { 149*5e96a66cSDavid du Colombier Fid *fp, **hash; 150*5e96a66cSDavid du Colombier 151*5e96a66cSDavid du Colombier assert(fid->ref == 0); 152*5e96a66cSDavid du Colombier 153*5e96a66cSDavid du Colombier hash = &fid->con->fidhash[fid->fidno % NFidHash]; 154*5e96a66cSDavid du Colombier for(fp = *hash; fp != nil; fp = fp->hash){ 155*5e96a66cSDavid du Colombier if(fp == fid){ 156*5e96a66cSDavid du Colombier *hash = fp->hash; 157*5e96a66cSDavid du Colombier break; 158*5e96a66cSDavid du Colombier } 159*5e96a66cSDavid du Colombier hash = &fp->hash; 160*5e96a66cSDavid du Colombier } 161*5e96a66cSDavid du Colombier assert(fp == fid); 162*5e96a66cSDavid du Colombier 163*5e96a66cSDavid du Colombier if(fid->prev != nil) 164*5e96a66cSDavid du Colombier fid->prev->next = fid->next; 165*5e96a66cSDavid du Colombier else 166*5e96a66cSDavid du Colombier fid->con->fhead = fid->next; 167*5e96a66cSDavid du Colombier if(fid->next != nil) 168*5e96a66cSDavid du Colombier fid->next->prev = fid->prev; 169*5e96a66cSDavid du Colombier else 170*5e96a66cSDavid du Colombier fid->con->ftail = fid->prev; 171*5e96a66cSDavid du Colombier fid->prev = fid->next = nil; 172*5e96a66cSDavid du Colombier 173*5e96a66cSDavid du Colombier fid->con->nfid--; 174*5e96a66cSDavid du Colombier } 175*5e96a66cSDavid du Colombier 176*5e96a66cSDavid du Colombier Fid* 177*5e96a66cSDavid du Colombier fidGet(Con* con, u32int fidno, int flags) 178*5e96a66cSDavid du Colombier { 179*5e96a66cSDavid du Colombier Fid *fid, **hash; 180*5e96a66cSDavid du Colombier 181*5e96a66cSDavid du Colombier if(fidno == NOFID) 182*5e96a66cSDavid du Colombier return nil; 183*5e96a66cSDavid du Colombier 184*5e96a66cSDavid du Colombier hash = &con->fidhash[fidno % NFidHash]; 185*5e96a66cSDavid du Colombier vtLock(con->fidlock); 186*5e96a66cSDavid du Colombier for(fid = *hash; fid != nil; fid = fid->hash){ 187*5e96a66cSDavid du Colombier if(fid->fidno != fidno) 188*5e96a66cSDavid du Colombier continue; 189*5e96a66cSDavid du Colombier 190*5e96a66cSDavid du Colombier /* 191*5e96a66cSDavid du Colombier * Already in use is an error 192*5e96a66cSDavid du Colombier * when called from attach, clone or walk. 193*5e96a66cSDavid du Colombier */ 194*5e96a66cSDavid du Colombier if(flags & FidFCreate){ 195*5e96a66cSDavid du Colombier vtUnlock(con->fidlock); 196*5e96a66cSDavid du Colombier vtSetError("fid in use"); 197*5e96a66cSDavid du Colombier return nil; 198*5e96a66cSDavid du Colombier } 199*5e96a66cSDavid du Colombier fid->ref++; 200*5e96a66cSDavid du Colombier vtUnlock(con->fidlock); 201*5e96a66cSDavid du Colombier 202*5e96a66cSDavid du Colombier fidLock(fid, flags); 203*5e96a66cSDavid du Colombier if((fid->open & FidOCreate) || fid->fidno == NOFID){ 204*5e96a66cSDavid du Colombier fidPut(fid); 205*5e96a66cSDavid du Colombier vtSetError("fid invalid"); 206*5e96a66cSDavid du Colombier return nil; 207*5e96a66cSDavid du Colombier } 208*5e96a66cSDavid du Colombier return fid; 209*5e96a66cSDavid du Colombier } 210*5e96a66cSDavid du Colombier 211*5e96a66cSDavid du Colombier if((flags & FidFCreate) && (fid = fidAlloc()) != nil){ 212*5e96a66cSDavid du Colombier assert(flags & FidFWlock); 213*5e96a66cSDavid du Colombier fid->con = con; 214*5e96a66cSDavid du Colombier fid->fidno = fidno; 215*5e96a66cSDavid du Colombier fid->ref = 1; 216*5e96a66cSDavid du Colombier 217*5e96a66cSDavid du Colombier fid->hash = *hash; 218*5e96a66cSDavid du Colombier *hash = fid; 219*5e96a66cSDavid du Colombier if(con->ftail != nil){ 220*5e96a66cSDavid du Colombier fid->prev = con->ftail; 221*5e96a66cSDavid du Colombier con->ftail->next = fid; 222*5e96a66cSDavid du Colombier } 223*5e96a66cSDavid du Colombier else{ 224*5e96a66cSDavid du Colombier con->fhead = fid; 225*5e96a66cSDavid du Colombier fid->prev = nil; 226*5e96a66cSDavid du Colombier } 227*5e96a66cSDavid du Colombier con->ftail = fid; 228*5e96a66cSDavid du Colombier fid->next = nil; 229*5e96a66cSDavid du Colombier 230*5e96a66cSDavid du Colombier con->nfid++; 231*5e96a66cSDavid du Colombier vtUnlock(con->fidlock); 232*5e96a66cSDavid du Colombier 233*5e96a66cSDavid du Colombier /* 234*5e96a66cSDavid du Colombier * The FidOCreate flag is used to prevent any 235*5e96a66cSDavid du Colombier * accidental access to the Fid between unlocking the 236*5e96a66cSDavid du Colombier * hash and acquiring the Fid lock for return. 237*5e96a66cSDavid du Colombier */ 238*5e96a66cSDavid du Colombier fidLock(fid, flags); 239*5e96a66cSDavid du Colombier fid->open &= ~FidOCreate; 240*5e96a66cSDavid du Colombier return fid; 241*5e96a66cSDavid du Colombier } 242*5e96a66cSDavid du Colombier vtUnlock(con->fidlock); 243*5e96a66cSDavid du Colombier 244*5e96a66cSDavid du Colombier vtSetError("fid not found"); 245*5e96a66cSDavid du Colombier return nil; 246*5e96a66cSDavid du Colombier } 247*5e96a66cSDavid du Colombier 248*5e96a66cSDavid du Colombier void 249*5e96a66cSDavid du Colombier fidPut(Fid* fid) 250*5e96a66cSDavid du Colombier { 251*5e96a66cSDavid du Colombier vtLock(fid->con->fidlock); 252*5e96a66cSDavid du Colombier assert(fid->ref > 0); 253*5e96a66cSDavid du Colombier fid->ref--; 254*5e96a66cSDavid du Colombier vtUnlock(fid->con->fidlock); 255*5e96a66cSDavid du Colombier 256*5e96a66cSDavid du Colombier if(fid->ref == 0 && fid->fidno == NOFID){ 257*5e96a66cSDavid du Colombier fidFree(fid); 258*5e96a66cSDavid du Colombier return; 259*5e96a66cSDavid du Colombier } 260*5e96a66cSDavid du Colombier fidUnlock(fid); 261*5e96a66cSDavid du Colombier } 262*5e96a66cSDavid du Colombier 263*5e96a66cSDavid du Colombier void 264*5e96a66cSDavid du Colombier fidClunk(Fid* fid) 265*5e96a66cSDavid du Colombier { 266*5e96a66cSDavid du Colombier assert(fid->flags & FidFWlock); 267*5e96a66cSDavid du Colombier 268*5e96a66cSDavid du Colombier vtLock(fid->con->fidlock); 269*5e96a66cSDavid du Colombier assert(fid->ref > 0); 270*5e96a66cSDavid du Colombier fid->ref--; 271*5e96a66cSDavid du Colombier fidUnHash(fid); 272*5e96a66cSDavid du Colombier fid->fidno = NOFID; 273*5e96a66cSDavid du Colombier vtUnlock(fid->con->fidlock); 274*5e96a66cSDavid du Colombier 275*5e96a66cSDavid du Colombier if(fid->ref > 0){ 276*5e96a66cSDavid du Colombier fidUnlock(fid); 277*5e96a66cSDavid du Colombier return; 278*5e96a66cSDavid du Colombier } 279*5e96a66cSDavid du Colombier fidFree(fid); 280*5e96a66cSDavid du Colombier } 281*5e96a66cSDavid du Colombier 282*5e96a66cSDavid du Colombier void 283*5e96a66cSDavid du Colombier fidInit(void) 284*5e96a66cSDavid du Colombier { 285*5e96a66cSDavid du Colombier fbox.lock = vtLockAlloc(); 286*5e96a66cSDavid du Colombier } 287