Annotation of prex/usr/server/fs/vfs/vfs_vnode.c, Revision 1.1.1.1
1.1 nbrk 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: * vnode.c - vnode service
32: */
33:
34: #include <prex/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 err;
165:
166: DPRINTF(VFSDB_VNODE, ("vget: %s\n", path));
167:
168: if (!(vp = malloc(sizeof(struct vnode))))
169: return NULL;
170: memset(vp, 0, sizeof(struct vnode));
171:
172: if (!(vp->v_path = malloc(strlen(path) + 1))) {
173: free(vp);
174: return NULL;
175: }
176: vp->v_mount = mp;
177: vp->v_refcnt = 1;
178: vp->v_op = mp->m_op->vfs_vnops;
179: strcpy(vp->v_path, path);
180: mutex_init(&vp->v_lock);
181: vp->v_nrlocks = 0;
182:
183: /*
184: * Request to allocate fs specific data for vnode.
185: */
186: if ((err = VFS_VGET(mp, vp)) != 0) {
187: mutex_destroy(&vp->v_lock);
188: free(vp->v_path);
189: free(vp);
190: return NULL;
191: }
192: vfs_busy(vp->v_mount);
193: mutex_lock(&vp->v_lock);
194: vp->v_nrlocks++;
195:
196: VNODE_LOCK();
197: list_insert(&vnode_table[vn_hash(mp, path)], &vp->v_link);
198: VNODE_UNLOCK();
199: return vp;
200: }
201:
202: /*
203: * Unlock vnode and decrement its reference count.
204: */
205: void
206: vput(vnode_t vp)
207: {
208: ASSERT(vp);
209: ASSERT(vp->v_nrlocks > 0);
210: ASSERT(vp->v_refcnt > 0);
211: DPRINTF(VFSDB_VNODE, ("vput: ref=%d %s\n", vp->v_refcnt,
212: vp->v_path));
213:
214: vp->v_refcnt--;
215: if (vp->v_refcnt > 0) {
216: vn_unlock(vp);
217: return;
218: }
219: VNODE_LOCK();
220: list_remove(&vp->v_link);
221: VNODE_UNLOCK();
222:
223: /*
224: * Deallocate fs specific vnode data
225: */
226: VOP_INACTIVE(vp);
227: vfs_unbusy(vp->v_mount);
228: vp->v_nrlocks--;
229: ASSERT(vp->v_nrlocks == 0);
230: mutex_unlock(&vp->v_lock);
231: mutex_destroy(&vp->v_lock);
232: free(vp->v_path);
233: free(vp);
234: }
235:
236: /*
237: * Increment the reference count on an active vnode.
238: */
239: void
240: vref(vnode_t vp)
241: {
242: ASSERT(vp);
243: ASSERT(vp->v_refcnt > 0); /* Need vget */
244:
245: VNODE_LOCK();
246: DPRINTF(VFSDB_VNODE, ("vref: ref=%d %s\n", vp->v_refcnt,
247: vp->v_path));
248: vp->v_refcnt++;
249: VNODE_UNLOCK();
250: }
251:
252: /*
253: * Decrement the reference count of unlocked vnode.
254: * Any code in the system which is using vnode should call vrele()
255: * when it is finished with the vnode.
256: * If count drops to zero, call inactive routine and return to freelist.
257: */
258: void
259: vrele(vnode_t vp)
260: {
261: ASSERT(vp);
262: ASSERT(vp->v_nrlocks == 0);
263: ASSERT(vp->v_refcnt > 0);
264:
265: VNODE_LOCK();
266: DPRINTF(VFSDB_VNODE, ("vrele: ref=%d %s\n", vp->v_refcnt,
267: vp->v_path));
268: vp->v_refcnt--;
269: if (vp->v_refcnt > 0) {
270: VNODE_UNLOCK();
271: return;
272: }
273: list_remove(&vp->v_link);
274: VNODE_UNLOCK();
275:
276: /*
277: * Deallocate fs specific vnode data
278: */
279: VOP_INACTIVE(vp);
280: vfs_unbusy(vp->v_mount);
281: mutex_destroy(&vp->v_lock);
282: free(vp->v_path);
283: free(vp);
284: }
285:
286: /*
287: * vgone() is called when unlocked vnode is no longer valid.
288: */
289: void
290: vgone(vnode_t vp)
291: {
292: ASSERT(vp->v_nrlocks == 0);
293:
294: VNODE_LOCK();
295: DPRINTF(VFSDB_VNODE, ("vgone: %s\n", vp->v_path));
296: list_remove(&vp->v_link);
297: vfs_unbusy(vp->v_mount);
298: mutex_destroy(&vp->v_lock);
299: free(vp->v_path);
300: free(vp);
301: VNODE_UNLOCK();
302: }
303:
304: /*
305: * Return reference count.
306: */
307: int
308: vcount(vnode_t vp)
309: {
310: int count;
311:
312: vn_lock(vp);
313: count = vp->v_refcnt;
314: vn_unlock(vp);
315: return count;
316: }
317:
318: /*
319: * Remove all vnode in the vnode table for unmount.
320: */
321: void
322: vflush(mount_t mp)
323: {
324: int i;
325: list_t head, n;
326: vnode_t vp;
327:
328: VNODE_LOCK();
329: for (i = 0; i < VNODE_BUCKETS; i++) {
330: head = &vnode_table[i];
331: for (n = list_first(head); n != head; n = list_next(n)) {
332: vp = list_entry(n, struct vnode, v_link);
333: if (vp->v_mount == mp) {
334: /* XXX: */
335: }
336: }
337: }
338: VNODE_UNLOCK();
339: }
340:
341: int
342: vn_stat(vnode_t vp, struct stat *st)
343: {
344: mode_t mode;
345:
346: memset(st, 0, sizeof(struct stat));
347:
348: st->st_ino = (ino_t)vp;
349: st->st_size = vp->v_size;
350: mode = vp->v_mode;
351: switch (vp->v_type) {
352: case VREG:
353: mode |= S_IFREG;
354: break;
355: case VDIR:
356: mode |= S_IFDIR;
357: break;
358: case VBLK:
359: mode |= S_IFBLK;
360: break;
361: case VCHR:
362: mode |= S_IFCHR;
363: break;
364: case VLNK:
365: mode |= S_IFLNK;
366: break;
367: case VSOCK:
368: mode |= S_IFSOCK;
369: break;
370: case VFIFO:
371: mode |= S_IFIFO;
372: break;
373: default:
374: return EBADF;
375: };
376: st->st_mode = mode;
377: st->st_blksize = BSIZE;
378: st->st_blocks = vp->v_size / S_BLKSIZE;
379: st->st_uid = 0;
380: st->st_gid = 0;
381: if (vp->v_type == VCHR || vp->v_type == VBLK)
382: st->st_rdev = (dev_t)vp->v_data;
383:
384: return 0;
385: }
386:
387: #ifdef DEBUG
388: /*
389: * Dump all all vnode.
390: */
391: void
392: vnode_dump(void)
393: {
394: int i;
395: list_t head, n;
396: vnode_t vp;
397: mount_t mp;
398: char type[][6] = { "VNON ", "VREG ", "VDIR ", "VBLK ", "VCHR ",
399: "VLNK ", "VSOCK", "VFIFO" };
400:
401: VNODE_LOCK();
402: dprintf("Dump vnode\n");
403: dprintf(" vnode mount type refcnt blkno path\n");
404: dprintf(" -------- -------- ----- ------ -------- ------------------------------\n");
405:
406: for (i = 0; i < VNODE_BUCKETS; i++) {
407: head = &vnode_table[i];
408: for (n = list_first(head); n != head; n = list_next(n)) {
409: vp = list_entry(n, struct vnode, v_link);
410: mp = vp->v_mount;
411:
412: dprintf(" %08x %08x %s %6d %8d %s%s\n", (u_int)vp,
413: (u_int)mp, type[vp->v_type], vp->v_refcnt,
414: (u_int)vp->v_blkno,
415: (strlen(mp->m_path) == 1) ? "\0" : mp->m_path,
416: vp->v_path);
417: }
418: }
419: dprintf("\n");
420: VNODE_UNLOCK();
421: }
422: #endif
423:
424: int
425: vop_nullop(void)
426: {
427:
428: return 0;
429: }
430:
431: int
432: vop_einval(void)
433: {
434:
435: return EINVAL;
436: }
437:
438: void
439: vnode_init(void)
440: {
441: int i;
442:
443: for (i = 0; i < VNODE_BUCKETS; i++)
444: list_init(&vnode_table[i]);
445: }
CVSweb