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