scoutos / prex-0.9.0 / usr / server / fs / vfs / vfs_vnode.c @ 03e9c04a
History | View | Annotate | Download (9.34 KB)
1 |
/*
|
---|---|
2 |
* Copyright (c) 2005-2008, Kohsuke Ohtani
|
3 |
* All rights reserved.
|
4 |
*
|
5 |
* Redistribution and use in source and binary forms, with or without
|
6 |
* modification, are permitted provided that the following conditions
|
7 |
* are met:
|
8 |
* 1. Redistributions of source code must retain the above copyright
|
9 |
* notice, this list of conditions and the following disclaimer.
|
10 |
* 2. Redistributions in binary form must reproduce the above copyright
|
11 |
* notice, this list of conditions and the following disclaimer in the
|
12 |
* documentation and/or other materials provided with the distribution.
|
13 |
* 3. Neither the name of the author nor the names of any co-contributors
|
14 |
* may be used to endorse or promote products derived from this software
|
15 |
* without specific prior written permission.
|
16 |
*
|
17 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
18 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
21 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
23 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
24 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
26 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
27 |
* SUCH DAMAGE.
|
28 |
*/
|
29 |
|
30 |
/*
|
31 |
* vfs_vnode.c - vnode service
|
32 |
*/
|
33 |
|
34 |
#include <sys/prex.h> |
35 |
#include <sys/list.h> |
36 |
#include <sys/vnode.h> |
37 |
#include <sys/mount.h> |
38 |
|
39 |
#include <limits.h> |
40 |
#include <unistd.h> |
41 |
#include <string.h> |
42 |
#include <stdlib.h> |
43 |
#include <stdio.h> |
44 |
#include <errno.h> |
45 |
|
46 |
#include "vfs.h" |
47 |
|
48 |
/*
|
49 |
* Memo:
|
50 |
*
|
51 |
* Function Ref count Lock
|
52 |
* ---------- --------- ----------
|
53 |
* vn_lock * Lock
|
54 |
* vn_unlock * Unlock
|
55 |
* vget 1 Lock
|
56 |
* vput -1 Unlock
|
57 |
* vref +1 *
|
58 |
* vrele -1 *
|
59 |
*/
|
60 |
|
61 |
#define VNODE_BUCKETS 32 /* size of vnode hash table */ |
62 |
|
63 |
/*
|
64 |
* vnode table.
|
65 |
* All active (opened) vnodes are stored on this hash table.
|
66 |
* They can be accessed by its path name.
|
67 |
*/
|
68 |
static struct list vnode_table[VNODE_BUCKETS]; |
69 |
|
70 |
/*
|
71 |
* Global lock to access all vnodes and vnode table.
|
72 |
* If a vnode is already locked, there is no need to
|
73 |
* lock this global lock to access internal data.
|
74 |
*/
|
75 |
#if CONFIG_FS_THREADS > 1 |
76 |
static mutex_t vnode_lock = MUTEX_INITIALIZER;
|
77 |
#define VNODE_LOCK() mutex_lock(&vnode_lock)
|
78 |
#define VNODE_UNLOCK() mutex_unlock(&vnode_lock)
|
79 |
#else
|
80 |
#define VNODE_LOCK()
|
81 |
#define VNODE_UNLOCK()
|
82 |
#endif
|
83 |
|
84 |
|
85 |
/*
|
86 |
* Get the hash value from the mount point and path name.
|
87 |
*/
|
88 |
static u_int
|
89 |
vn_hash(mount_t mp, char *path)
|
90 |
{ |
91 |
u_int val = 0;
|
92 |
|
93 |
if (path) {
|
94 |
while (*path)
|
95 |
val = ((val << 5) + val) + *path++;
|
96 |
} |
97 |
return (val ^ (u_int)mp) & (VNODE_BUCKETS - 1); |
98 |
} |
99 |
|
100 |
/*
|
101 |
* Returns locked vnode for specified mount point and path.
|
102 |
* vn_lock() will increment the reference count of vnode.
|
103 |
*/
|
104 |
vnode_t |
105 |
vn_lookup(mount_t mp, char *path)
|
106 |
{ |
107 |
list_t head, n; |
108 |
vnode_t vp; |
109 |
|
110 |
VNODE_LOCK(); |
111 |
head = &vnode_table[vn_hash(mp, path)]; |
112 |
for (n = list_first(head); n != head; n = list_next(n)) {
|
113 |
vp = list_entry(n, struct vnode, v_link);
|
114 |
if (vp->v_mount == mp &&
|
115 |
!strncmp(vp->v_path, path, PATH_MAX)) { |
116 |
vp->v_refcnt++; |
117 |
VNODE_UNLOCK(); |
118 |
mutex_lock(&vp->v_lock); |
119 |
vp->v_nrlocks++; |
120 |
return vp;
|
121 |
} |
122 |
} |
123 |
VNODE_UNLOCK(); |
124 |
return NULL; /* not found */ |
125 |
} |
126 |
|
127 |
/*
|
128 |
* Lock vnode
|
129 |
*/
|
130 |
void
|
131 |
vn_lock(vnode_t vp) |
132 |
{ |
133 |
ASSERT(vp); |
134 |
ASSERT(vp->v_refcnt > 0);
|
135 |
|
136 |
mutex_lock(&vp->v_lock); |
137 |
vp->v_nrlocks++; |
138 |
DPRINTF(VFSDB_VNODE, ("vn_lock: %s\n", vp->v_path));
|
139 |
} |
140 |
|
141 |
/*
|
142 |
* Unlock vnode
|
143 |
*/
|
144 |
void
|
145 |
vn_unlock(vnode_t vp) |
146 |
{ |
147 |
ASSERT(vp); |
148 |
ASSERT(vp->v_refcnt > 0);
|
149 |
ASSERT(vp->v_nrlocks > 0);
|
150 |
|
151 |
DPRINTF(VFSDB_VNODE, ("vn_unlock: %s\n", vp->v_path));
|
152 |
vp->v_nrlocks--; |
153 |
mutex_unlock(&vp->v_lock); |
154 |
} |
155 |
|
156 |
/*
|
157 |
* Allocate new vnode for specified path.
|
158 |
* Increment its reference count and lock it.
|
159 |
*/
|
160 |
vnode_t |
161 |
vget(mount_t mp, char *path)
|
162 |
{ |
163 |
vnode_t vp; |
164 |
int error;
|
165 |
size_t len; |
166 |
|
167 |
DPRINTF(VFSDB_VNODE, ("vget: %s\n", path));
|
168 |
|
169 |
if (!(vp = malloc(sizeof(struct vnode)))) |
170 |
return NULL; |
171 |
memset(vp, 0, sizeof(struct vnode)); |
172 |
|
173 |
len = strlen(path) + 1;
|
174 |
if (!(vp->v_path = malloc(len))) {
|
175 |
free(vp); |
176 |
return NULL; |
177 |
} |
178 |
vp->v_mount = mp; |
179 |
vp->v_refcnt = 1;
|
180 |
vp->v_op = mp->m_op->vfs_vnops; |
181 |
strlcpy(vp->v_path, path, len); |
182 |
mutex_init(&vp->v_lock); |
183 |
vp->v_nrlocks = 0;
|
184 |
|
185 |
/*
|
186 |
* Request to allocate fs specific data for vnode.
|
187 |
*/
|
188 |
if ((error = VFS_VGET(mp, vp)) != 0) { |
189 |
mutex_destroy(&vp->v_lock); |
190 |
free(vp->v_path); |
191 |
free(vp); |
192 |
return NULL; |
193 |
} |
194 |
vfs_busy(vp->v_mount); |
195 |
mutex_lock(&vp->v_lock); |
196 |
vp->v_nrlocks++; |
197 |
|
198 |
VNODE_LOCK(); |
199 |
list_insert(&vnode_table[vn_hash(mp, path)], &vp->v_link); |
200 |
VNODE_UNLOCK(); |
201 |
return vp;
|
202 |
} |
203 |
|
204 |
/*
|
205 |
* Unlock vnode and decrement its reference count.
|
206 |
*/
|
207 |
void
|
208 |
vput(vnode_t vp) |
209 |
{ |
210 |
ASSERT(vp); |
211 |
ASSERT(vp->v_nrlocks > 0);
|
212 |
ASSERT(vp->v_refcnt > 0);
|
213 |
DPRINTF(VFSDB_VNODE, ("vput: ref=%d %s\n", vp->v_refcnt,
|
214 |
vp->v_path)); |
215 |
|
216 |
vp->v_refcnt--; |
217 |
if (vp->v_refcnt > 0) { |
218 |
vn_unlock(vp); |
219 |
return;
|
220 |
} |
221 |
VNODE_LOCK(); |
222 |
list_remove(&vp->v_link); |
223 |
VNODE_UNLOCK(); |
224 |
|
225 |
/*
|
226 |
* Deallocate fs specific vnode data
|
227 |
*/
|
228 |
VOP_INACTIVE(vp); |
229 |
vfs_unbusy(vp->v_mount); |
230 |
vp->v_nrlocks--; |
231 |
ASSERT(vp->v_nrlocks == 0);
|
232 |
mutex_unlock(&vp->v_lock); |
233 |
mutex_destroy(&vp->v_lock); |
234 |
free(vp->v_path); |
235 |
free(vp); |
236 |
} |
237 |
|
238 |
/*
|
239 |
* Increment the reference count on an active vnode.
|
240 |
*/
|
241 |
void
|
242 |
vref(vnode_t vp) |
243 |
{ |
244 |
ASSERT(vp); |
245 |
ASSERT(vp->v_refcnt > 0); /* Need vget */ |
246 |
|
247 |
VNODE_LOCK(); |
248 |
DPRINTF(VFSDB_VNODE, ("vref: ref=%d %s\n", vp->v_refcnt,
|
249 |
vp->v_path)); |
250 |
vp->v_refcnt++; |
251 |
VNODE_UNLOCK(); |
252 |
} |
253 |
|
254 |
/*
|
255 |
* Decrement the reference count of the vnode.
|
256 |
* Any code in the system which is using vnode should call vrele()
|
257 |
* when it is finished with the vnode.
|
258 |
* If count drops to zero, call inactive routine and return to freelist.
|
259 |
*/
|
260 |
void
|
261 |
vrele(vnode_t vp) |
262 |
{ |
263 |
ASSERT(vp); |
264 |
ASSERT(vp->v_refcnt > 0);
|
265 |
|
266 |
VNODE_LOCK(); |
267 |
DPRINTF(VFSDB_VNODE, ("vrele: ref=%d %s\n", vp->v_refcnt,
|
268 |
vp->v_path)); |
269 |
vp->v_refcnt--; |
270 |
if (vp->v_refcnt > 0) { |
271 |
VNODE_UNLOCK(); |
272 |
return;
|
273 |
} |
274 |
list_remove(&vp->v_link); |
275 |
VNODE_UNLOCK(); |
276 |
|
277 |
/*
|
278 |
* Deallocate fs specific vnode data
|
279 |
*/
|
280 |
VOP_INACTIVE(vp); |
281 |
vfs_unbusy(vp->v_mount); |
282 |
mutex_destroy(&vp->v_lock); |
283 |
free(vp->v_path); |
284 |
free(vp); |
285 |
} |
286 |
|
287 |
/*
|
288 |
* vgone() is called when unlocked vnode is no longer valid.
|
289 |
*/
|
290 |
void
|
291 |
vgone(vnode_t vp) |
292 |
{ |
293 |
ASSERT(vp->v_nrlocks == 0);
|
294 |
|
295 |
VNODE_LOCK(); |
296 |
DPRINTF(VFSDB_VNODE, ("vgone: %s\n", vp->v_path));
|
297 |
list_remove(&vp->v_link); |
298 |
vfs_unbusy(vp->v_mount); |
299 |
mutex_destroy(&vp->v_lock); |
300 |
free(vp->v_path); |
301 |
free(vp); |
302 |
VNODE_UNLOCK(); |
303 |
} |
304 |
|
305 |
/*
|
306 |
* Return reference count.
|
307 |
*/
|
308 |
int
|
309 |
vcount(vnode_t vp) |
310 |
{ |
311 |
int count;
|
312 |
|
313 |
vn_lock(vp); |
314 |
count = vp->v_refcnt; |
315 |
vn_unlock(vp); |
316 |
return count;
|
317 |
} |
318 |
|
319 |
/*
|
320 |
* Remove all vnode in the vnode table for unmount.
|
321 |
*/
|
322 |
void
|
323 |
vflush(mount_t mp) |
324 |
{ |
325 |
int i;
|
326 |
list_t head, n; |
327 |
vnode_t vp; |
328 |
|
329 |
VNODE_LOCK(); |
330 |
for (i = 0; i < VNODE_BUCKETS; i++) { |
331 |
head = &vnode_table[i]; |
332 |
for (n = list_first(head); n != head; n = list_next(n)) {
|
333 |
vp = list_entry(n, struct vnode, v_link);
|
334 |
if (vp->v_mount == mp) {
|
335 |
/* XXX: */
|
336 |
} |
337 |
} |
338 |
} |
339 |
VNODE_UNLOCK(); |
340 |
} |
341 |
|
342 |
int
|
343 |
vn_stat(vnode_t vp, struct stat *st)
|
344 |
{ |
345 |
mode_t mode; |
346 |
|
347 |
memset(st, 0, sizeof(struct stat)); |
348 |
|
349 |
st->st_ino = (ino_t)vp; |
350 |
st->st_size = vp->v_size; |
351 |
mode = vp->v_mode; |
352 |
switch (vp->v_type) {
|
353 |
case VREG:
|
354 |
mode |= S_IFREG; |
355 |
break;
|
356 |
case VDIR:
|
357 |
mode |= S_IFDIR; |
358 |
break;
|
359 |
case VBLK:
|
360 |
mode |= S_IFBLK; |
361 |
break;
|
362 |
case VCHR:
|
363 |
mode |= S_IFCHR; |
364 |
break;
|
365 |
case VLNK:
|
366 |
mode |= S_IFLNK; |
367 |
break;
|
368 |
case VSOCK:
|
369 |
mode |= S_IFSOCK; |
370 |
break;
|
371 |
case VFIFO:
|
372 |
mode |= S_IFIFO; |
373 |
break;
|
374 |
default:
|
375 |
return EBADF;
|
376 |
}; |
377 |
st->st_mode = mode; |
378 |
st->st_blksize = BSIZE; |
379 |
st->st_blocks = vp->v_size / S_BLKSIZE; |
380 |
st->st_uid = 0;
|
381 |
st->st_gid = 0;
|
382 |
if (vp->v_type == VCHR || vp->v_type == VBLK)
|
383 |
st->st_rdev = (dev_t)vp->v_data; |
384 |
|
385 |
return 0; |
386 |
} |
387 |
|
388 |
/*
|
389 |
* Chceck permission on vnode pointer.
|
390 |
*/
|
391 |
int
|
392 |
vn_access(vnode_t vp, int flags)
|
393 |
{ |
394 |
int error = 0; |
395 |
|
396 |
if ((flags & VEXEC) && (vp->v_mode & 0111) == 0) { |
397 |
error = EACCES; |
398 |
goto out;
|
399 |
} |
400 |
if ((flags & VREAD) && (vp->v_mode & 0444) == 0) { |
401 |
error = EACCES; |
402 |
goto out;
|
403 |
} |
404 |
if (flags & VWRITE) {
|
405 |
if (vp->v_mount->m_flags & MNT_RDONLY) {
|
406 |
error = EROFS; |
407 |
goto out;
|
408 |
} |
409 |
if ((vp->v_mode & 0222) == 0) { |
410 |
error = EACCES; |
411 |
goto out;
|
412 |
} |
413 |
} |
414 |
out:
|
415 |
return error;
|
416 |
} |
417 |
|
418 |
#ifdef DEBUG_VFS
|
419 |
/*
|
420 |
* Dump all all vnode.
|
421 |
*/
|
422 |
void
|
423 |
vnode_dump(void)
|
424 |
{ |
425 |
int i;
|
426 |
list_t head, n; |
427 |
vnode_t vp; |
428 |
mount_t mp; |
429 |
char type[][6] = { "VNON ", "VREG ", "VDIR ", "VBLK ", "VCHR ", |
430 |
"VLNK ", "VSOCK", "VFIFO" }; |
431 |
|
432 |
VNODE_LOCK(); |
433 |
dprintf("Dump vnode\n");
|
434 |
dprintf(" vnode mount type refcnt blkno path\n");
|
435 |
dprintf(" -------- -------- ----- ------ -------- ------------------------------\n");
|
436 |
|
437 |
for (i = 0; i < VNODE_BUCKETS; i++) { |
438 |
head = &vnode_table[i]; |
439 |
for (n = list_first(head); n != head; n = list_next(n)) {
|
440 |
vp = list_entry(n, struct vnode, v_link);
|
441 |
mp = vp->v_mount; |
442 |
|
443 |
dprintf(" %08x %08x %s %6d %8d %s%s\n", (u_int)vp,
|
444 |
(u_int)mp, type[vp->v_type], vp->v_refcnt, |
445 |
(u_int)vp->v_blkno, |
446 |
(strlen(mp->m_path) == 1) ? "\0" : mp->m_path, |
447 |
vp->v_path); |
448 |
} |
449 |
} |
450 |
dprintf("\n");
|
451 |
VNODE_UNLOCK(); |
452 |
} |
453 |
#endif
|
454 |
|
455 |
int
|
456 |
vop_nullop(void)
|
457 |
{ |
458 |
|
459 |
return 0; |
460 |
} |
461 |
|
462 |
int
|
463 |
vop_einval(void)
|
464 |
{ |
465 |
|
466 |
return EINVAL;
|
467 |
} |
468 |
|
469 |
/*
|
470 |
* vnode_init() is called once (from vfs_init)
|
471 |
* in initialization.
|
472 |
*/
|
473 |
void
|
474 |
vnode_init(void)
|
475 |
{ |
476 |
int i;
|
477 |
|
478 |
for (i = 0; i < VNODE_BUCKETS; i++) |
479 |
list_init(&vnode_table[i]); |
480 |
} |