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