Prex Home / Browse Source - Prex Version: 0.9.0

root/usr/server/fs/vfs/vfs_vnode.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vn_hash
  2. vn_lookup
  3. vn_lock
  4. vn_unlock
  5. vget
  6. vput
  7. vref
  8. vrele
  9. vgone
  10. vcount
  11. vflush
  12. vn_stat
  13. vn_access
  14. vnode_dump
  15. vop_nullop
  16. vop_einval
  17. vnode_init

   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] */