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