xref: /plan9-contrib/sys/src/cmd/fossil/9fid.c (revision 5e96a66c77eb9140492ca53f857cbbf108e128ed)
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