Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "stdinc.h"
2
 
3
#include "9.h"
4
 
5
static struct {
6
	VtLock*	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
		vtLock(fid->lock);
18
		fid->flags = flags;
19
	}
20
	else
21
		vtRLock(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
		vtUnlock(fid->lock);
51
		return;
52
	}
53
	vtRUnlock(fid->lock);
54
}
55
 
56
static Fid*
57
fidAlloc(void)
58
{
59
	Fid *fid;
60
 
61
	vtLock(fbox.lock);
62
	if(fbox.nfree > 0){
63
		fid = fbox.free;
64
		fbox.free = fid->hash;
65
		fbox.nfree--;
66
	}
67
	else{
68
		fid = vtMemAllocZ(sizeof(Fid));
69
		fid->lock = vtLockAlloc();
70
		fid->alock = vtLockAlloc();
71
	}
72
	fbox.inuse++;
73
	vtUnlock(fbox.lock);
74
 
75
	fid->con = nil;
76
	fid->fidno = NOFID;
77
	fid->ref = 0;
78
	fid->flags = 0;
79
	fid->open = FidOCreate;
80
	assert(fid->fsys == nil);
81
	assert(fid->file == nil);
82
	fid->qid = (Qid){0, 0, 0};
83
	assert(fid->uid == nil);
84
	assert(fid->uname == nil);
85
	assert(fid->db == nil);
86
	assert(fid->excl == nil);
87
	assert(fid->rpc == nil);
88
	assert(fid->cuname == nil);
89
	fid->hash = fid->next = fid->prev = nil;
90
 
91
	return fid;
92
}
93
 
94
static void
95
fidFree(Fid* fid)
96
{
97
	if(fid->file != nil){
98
		fileDecRef(fid->file);
99
		fid->file = nil;
100
	}
101
	if(fid->db != nil){
102
		dirBufFree(fid->db);
103
		fid->db = nil;
104
	}
105
	fidUnlock(fid);
106
 
107
	if(fid->uid != nil){
108
		vtMemFree(fid->uid);
109
		fid->uid = nil;
110
	}
111
	if(fid->uname != nil){
112
		vtMemFree(fid->uname);
113
		fid->uname = nil;
114
	}
115
	if(fid->excl != nil)
116
		exclFree(fid);
117
	if(fid->rpc != nil){
118
		close(fid->rpc->afd);
119
		auth_freerpc(fid->rpc);
120
		fid->rpc = nil;
121
	}
122
	if(fid->fsys != nil){
123
		fsysPut(fid->fsys);
124
		fid->fsys = nil;
125
	}
126
	if(fid->cuname != nil){
127
		vtMemFree(fid->cuname);
128
		fid->cuname = nil;
129
	}
130
 
131
	vtLock(fbox.lock);
132
	fbox.inuse--;
133
	if(fbox.nfree < 10){
134
		fid->hash = fbox.free;
135
		fbox.free = fid;
136
		fbox.nfree++;
137
	}
138
	else{
139
		vtLockFree(fid->alock);
140
		vtLockFree(fid->lock);
141
		vtMemFree(fid);
142
	}
143
	vtUnlock(fbox.lock);
144
}
145
 
146
static void
147
fidUnHash(Fid* fid)
148
{
149
	Fid *fp, **hash;
150
 
151
	assert(fid->ref == 0);
152
 
153
	hash = &fid->con->fidhash[fid->fidno % NFidHash];
154
	for(fp = *hash; fp != nil; fp = fp->hash){
155
		if(fp == fid){
156
			*hash = fp->hash;
157
			break;
158
		}
159
		hash = &fp->hash;
160
	}
161
	assert(fp == fid);
162
 
163
	if(fid->prev != nil)
164
		fid->prev->next = fid->next;
165
	else
166
		fid->con->fhead = fid->next;
167
	if(fid->next != nil)
168
		fid->next->prev = fid->prev;
169
	else
170
		fid->con->ftail = fid->prev;
171
	fid->prev = fid->next = nil;
172
 
173
	fid->con->nfid--;
174
}
175
 
176
Fid*
177
fidGet(Con* con, u32int fidno, int flags)
178
{
179
	Fid *fid, **hash;
180
 
181
	if(fidno == NOFID)
182
		return nil;
183
 
184
	hash = &con->fidhash[fidno % NFidHash];
185
	vtLock(con->fidlock);
186
	for(fid = *hash; fid != nil; fid = fid->hash){
187
		if(fid->fidno != fidno)
188
			continue;
189
 
190
		/*
191
		 * Already in use is an error
192
		 * when called from attach, clone or walk.
193
		 */
194
		if(flags & FidFCreate){
195
			vtUnlock(con->fidlock);
196
			vtSetError("%s: fid 0x%ud in use", argv0, fidno);
197
			return nil;
198
		}
199
		fid->ref++;
200
		vtUnlock(con->fidlock);
201
 
202
		fidLock(fid, flags);
203
		if((fid->open & FidOCreate) || fid->fidno == NOFID){
204
			fidPut(fid);
205
			vtSetError("%s: fid invalid", argv0);
206
			return nil;
207
		}
208
		return fid;
209
	}
210
 
211
	if((flags & FidFCreate) && (fid = fidAlloc()) != nil){
212
		assert(flags & FidFWlock);
213
		fid->con = con;
214
		fid->fidno = fidno;
215
		fid->ref = 1;
216
 
217
		fid->hash = *hash;
218
		*hash = fid;
219
		if(con->ftail != nil){
220
			fid->prev = con->ftail;
221
			con->ftail->next = fid;
222
		}
223
		else{
224
			con->fhead = fid;
225
			fid->prev = nil;
226
		}
227
		con->ftail = fid;
228
		fid->next = nil;
229
 
230
		con->nfid++;
231
		vtUnlock(con->fidlock);
232
 
233
		/*
234
		 * The FidOCreate flag is used to prevent any
235
		 * accidental access to the Fid between unlocking the
236
		 * hash and acquiring the Fid lock for return.
237
		 */
238
		fidLock(fid, flags);
239
		fid->open &= ~FidOCreate;
240
		return fid;
241
	}
242
	vtUnlock(con->fidlock);
243
 
244
	vtSetError("%s: fid not found", argv0);
245
	return nil;
246
}
247
 
248
void
249
fidPut(Fid* fid)
250
{
251
	vtLock(fid->con->fidlock);
252
	assert(fid->ref > 0);
253
	fid->ref--;
254
	vtUnlock(fid->con->fidlock);
255
 
256
	if(fid->ref == 0 && fid->fidno == NOFID){
257
		fidFree(fid);
258
		return;
259
	}
260
	fidUnlock(fid);
261
}
262
 
263
void
264
fidClunk(Fid* fid)
265
{
266
	assert(fid->flags & FidFWlock);
267
 
268
	vtLock(fid->con->fidlock);
269
	assert(fid->ref > 0);
270
	fid->ref--;
271
	fidUnHash(fid);
272
	fid->fidno = NOFID;
273
	vtUnlock(fid->con->fidlock);
274
 
275
	if(fid->ref > 0){
276
		/* not reached - fidUnHash requires ref == 0 */
277
		fidUnlock(fid);
278
		return;
279
	}
280
	fidFree(fid);
281
}
282
 
283
void
284
fidClunkAll(Con* con)
285
{
286
	Fid *fid;
287
	u32int fidno;
288
 
289
	vtLock(con->fidlock);
290
	while(con->fhead != nil){
291
		fidno = con->fhead->fidno;
292
		vtUnlock(con->fidlock);
293
		if((fid = fidGet(con, fidno, FidFWlock)) != nil)
294
			fidClunk(fid);
295
		vtLock(con->fidlock);
296
	}
297
	vtUnlock(con->fidlock);
298
}
299
 
300
void
301
fidInit(void)
302
{
303
	fbox.lock = vtLockAlloc();
304
}