Prex Home / Browse Source - Prex Version: 0.9.0

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

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

DEFINITIONS

This source file includes following definitions.
  1. fs_getfs
  2. sys_mount
  3. sys_umount
  4. sys_sync
  5. count_match
  6. vfs_findroot
  7. vfs_busy
  8. vfs_unbusy
  9. vfs_nullop
  10. vfs_einval
  11. mount_dump

   1 /*
   2  * Copyright (c) 2005-2007, 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_mount.c - mount operations
  32  */
  33 
  34 #include <sys/prex.h>
  35 
  36 #include <sys/stat.h>
  37 #include <sys/vnode.h>
  38 #include <sys/file.h>
  39 #include <sys/mount.h>
  40 #include <sys/dirent.h>
  41 #include <sys/list.h>
  42 #include <sys/buf.h>
  43 
  44 #include <limits.h>
  45 #include <unistd.h>
  46 #include <stdlib.h>
  47 #include <string.h>
  48 #include <stdio.h>
  49 #include <errno.h>
  50 #include <fcntl.h>
  51 
  52 #include "vfs.h"
  53 
  54 /*
  55  * List for VFS mount points.
  56  */
  57 static struct list mount_list = LIST_INIT(mount_list);
  58 
  59 /*
  60  * Global lock to access mount point.
  61  */
  62 #if CONFIG_FS_THREADS > 1
  63 static mutex_t mount_lock = MUTEX_INITIALIZER;
  64 #define MOUNT_LOCK()    mutex_lock(&mount_lock)
  65 #define MOUNT_UNLOCK()  mutex_unlock(&mount_lock)
  66 #else
  67 #define MOUNT_LOCK()
  68 #define MOUNT_UNLOCK()
  69 #endif
  70 
  71 /*
  72  * Lookup file system.
  73  */
  74 static const struct vfssw *
  75 fs_getfs(char *name)
  76 {
  77         const struct vfssw *fs;
  78 
  79         for (fs = vfssw; fs->vs_name; fs++) {
  80                 if (!strncmp(name, fs->vs_name, FSMAXNAMES))
  81                         break;
  82         }
  83         if (!fs->vs_name)
  84                 return NULL;
  85         return fs;
  86 }
  87 
  88 int
  89 sys_mount(char *dev, char *dir, char *fsname, int flags, void *data)
  90 {
  91         const struct vfssw *fs;
  92         mount_t mp;
  93         list_t head, n;
  94         device_t device;
  95         vnode_t vp, vp_covered;
  96         int error;
  97 
  98 #ifdef DEBUG
  99         dprintf("VFS: mounting %s at %s\n", fsname, dir);
 100 #endif
 101 
 102         if (!dir || *dir == '\0')
 103                 return ENOENT;
 104 
 105         /* Find a file system. */
 106         if (!(fs = fs_getfs(fsname)))
 107                 return ENODEV;  /* No such file system */
 108 
 109         /* Open device. NULL can be specified as a device. */
 110         device = 0;
 111         if (*dev != '\0') {
 112                 if (strncmp(dev, "/dev/", 5))
 113                         return ENOTBLK;
 114                 if ((error = device_open(dev + 5, DO_RDWR, &device)) != 0)
 115                         return error;
 116         }
 117 
 118         MOUNT_LOCK();
 119 
 120         /* Check if device or directory has already been mounted. */
 121         head = &mount_list;
 122         for (n = list_first(head); n != head; n = list_next(n)) {
 123                 mp = list_entry(n, struct mount, m_link);
 124                 if (!strcmp(mp->m_path, dir) ||
 125                     (device && mp->m_dev == (dev_t)device)) {
 126                         error = EBUSY;  /* Already mounted */
 127                         goto err1;
 128                 }
 129         }
 130         /*
 131          * Create VFS mount entry.
 132          */
 133         if (!(mp = malloc(sizeof(struct mount)))) {
 134                 error = ENOMEM;
 135                 goto err1;
 136         }
 137         mp->m_count = 0;
 138         mp->m_op = fs->vs_op;
 139         mp->m_flags = flags;
 140         mp->m_dev = (dev_t)device;
 141         strlcpy(mp->m_path, dir, sizeof(mp->m_path));
 142 
 143         /*
 144          * Get vnode to be covered in the upper file system.
 145          */
 146         if (*dir == '/' && *(dir + 1) == '\0') {
 147                 /* Ignore if it mounts to global root directory. */
 148                 vp_covered = NULL;
 149         } else {
 150                 if ((error = namei(dir, &vp_covered)) != 0) {
 151 
 152                         error = ENOENT;
 153                         goto err2;
 154                 }
 155                 if (vp_covered->v_type != VDIR) {
 156                         error = ENOTDIR;
 157                         goto err3;
 158                 }
 159         }
 160         mp->m_covered = vp_covered;
 161 
 162         /*
 163          * Create a root vnode for this file system.
 164          */
 165         if ((vp = vget(mp, "/")) == NULL) {
 166                 error = ENOMEM;
 167                 goto err3;
 168         }
 169         vp->v_type = VDIR;
 170         vp->v_flags = VROOT;
 171         vp->v_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR;
 172         mp->m_root = vp;
 173 
 174         /*
 175          * Call a file system specific routine.
 176          */
 177         if ((error = VFS_MOUNT(mp, dev, flags, data)) != 0)
 178                 goto err4;
 179 
 180         if (mp->m_flags & MNT_RDONLY)
 181                 vp->v_mode &=~S_IWUSR;
 182 
 183         /*
 184          * Keep reference count for root/covered vnode.
 185          */
 186         vn_unlock(vp);
 187         if (vp_covered)
 188                 vn_unlock(vp_covered);
 189 
 190         /*
 191          * Insert to mount list
 192          */
 193         list_insert(&mount_list, &mp->m_link);
 194         MOUNT_UNLOCK();
 195 
 196         return 0;       /* success */
 197  err4:
 198         vput(vp);
 199  err3:
 200         if (vp_covered)
 201                 vput(vp_covered);
 202  err2:
 203         free(mp);
 204  err1:
 205         device_close(device);
 206 
 207         MOUNT_UNLOCK();
 208         return error;
 209 }
 210 
 211 int
 212 sys_umount(char *path)
 213 {
 214         mount_t mp;
 215         list_t head, n;
 216         int error;
 217 
 218         DPRINTF(VFSDB_SYSCALL, ("sys_umount: path=%s\n", path));
 219 
 220         MOUNT_LOCK();
 221 
 222         /* Get mount entry */
 223         head = &mount_list;
 224         for (n = list_first(head); n != head; n = list_next(n)) {
 225                 mp = list_entry(n, struct mount, m_link);
 226                 if (!strcmp(path, mp->m_path))
 227                         break;
 228         }
 229         if (n == head) {
 230                 error = EINVAL;
 231                 goto out;
 232         }
 233         /*
 234          * Root fs can not be unmounted.
 235          */
 236         if (mp->m_covered == NULL) {
 237                 error = EINVAL;
 238                 goto out;
 239         }
 240         if ((error = VFS_UNMOUNT(mp)) != 0)
 241                 goto out;
 242         list_remove(&mp->m_link);
 243 
 244         /* Decrement referece count of root vnode */
 245         vrele(mp->m_covered);
 246 
 247         /* Release all vnodes */
 248         vflush(mp);
 249 
 250         /* Flush all buffers */
 251         binval(mp->m_dev);
 252 
 253         if (mp->m_dev)
 254                 device_close((device_t)mp->m_dev);
 255         free(mp);
 256  out:
 257         MOUNT_UNLOCK();
 258         return error;
 259 }
 260 
 261 int
 262 sys_sync(void)
 263 {
 264         mount_t mp;
 265         list_t head, n;
 266 
 267         /* Call each mounted file system. */
 268         MOUNT_LOCK();
 269         head = &mount_list;
 270         for (n = list_first(head); n != head; n = list_next(n)) {
 271                 mp = list_entry(n, struct mount, m_link);
 272                 VFS_SYNC(mp);
 273         }
 274         MOUNT_UNLOCK();
 275         bio_sync();
 276         return 0;
 277 }
 278 
 279 /*
 280  * Compare two path strings. Return matched length.
 281  * @path: target path.
 282  * @root: vfs root path as mount point.
 283  */
 284 static size_t
 285 count_match(char *path, char *mount_root)
 286 {
 287         size_t len = 0;
 288 
 289         while (*path && *mount_root) {
 290                 if (*path++ != *mount_root++)
 291                         break;
 292                 len++;
 293         }
 294         if (*mount_root != '\0')
 295                 return 0;
 296 
 297         if (len == 1 && *(path - 1) == '/')
 298                 return 1;
 299 
 300         if (*path == '\0' || *path == '/')
 301                 return len;
 302         return 0;
 303 }
 304 
 305 /*
 306  * Get the root directory and mount point for specified path.
 307  * @path: full path.
 308  * @mp: mount point to return.
 309  * @root: pointer to root directory in path.
 310  */
 311 int
 312 vfs_findroot(char *path, mount_t *mp, char **root)
 313 {
 314         mount_t m, tmp;
 315         list_t head, n;
 316         size_t len, max_len = 0;
 317 
 318         if (!path)
 319                 return -1;
 320 
 321         /* Find mount point from nearest path */
 322         MOUNT_LOCK();
 323         m = NULL;
 324         head = &mount_list;
 325         for (n = list_first(head); n != head; n = list_next(n)) {
 326                 tmp = list_entry(n, struct mount, m_link);
 327                 len = count_match(path, tmp->m_path);
 328                 if (len > max_len) {
 329                         max_len = len;
 330                         m = tmp;
 331                 }
 332         }
 333         MOUNT_UNLOCK();
 334         if (m == NULL)
 335                 return -1;
 336         *root = (char *)(path + max_len);
 337         if (**root == '/')
 338                 (*root)++;
 339         *mp = m;
 340         return 0;
 341 }
 342 
 343 /*
 344  * Mark a mount point as busy.
 345  */
 346 void
 347 vfs_busy(mount_t mp)
 348 {
 349 
 350         MOUNT_LOCK();
 351         mp->m_count++;
 352         MOUNT_UNLOCK();
 353 }
 354 
 355 
 356 /*
 357  * Mark a mount point as busy.
 358  */
 359 void
 360 vfs_unbusy(mount_t mp)
 361 {
 362 
 363         MOUNT_LOCK();
 364         mp->m_count--;
 365         MOUNT_UNLOCK();
 366 }
 367 
 368 int
 369 vfs_nullop(void)
 370 {
 371         return 0;
 372 }
 373 
 374 int
 375 vfs_einval(void)
 376 {
 377         return EINVAL;
 378 }
 379 
 380 #ifdef DEBUG_VFS
 381 void
 382 mount_dump(void)
 383 {
 384         list_t head, n;
 385         mount_t mp;
 386 
 387         MOUNT_LOCK();
 388 
 389         dprintf("mount_dump\n");
 390         dprintf("dev      count root\n");
 391         dprintf("-------- ----- --------\n");
 392         head = &mount_list;
 393         for (n = list_first(head); n != head; n = list_next(n)) {
 394                 mp = list_entry(n, struct mount, m_link);
 395                 dprintf("%8x %5d %s\n", mp->m_dev, mp->m_count, mp->m_path);
 396         }
 397         MOUNT_UNLOCK();
 398 }
 399 #endif

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