scoutos / prex-0.9.0 / usr / server / fs / vfs / vfs_mount.c @ 03e9c04a
History | View | Annotate | Download (7.8 KB)
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
|