plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }