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