Annotation of prex/usr/server/fs/vfs/vfs_vnode.c, Revision 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