|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/usr/server/fs/vfs/vfs_vnode.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
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 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |