Project

General

Profile

Statistics
| Branch: | Revision:

root / 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