1 /* $NetBSD: vfs.c,v 1.1 2009/08/07 20:57:57 haad Exp $ */
4 * Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 /* __FBSDID("$FreeBSD: src/sys/compat/opensolaris/kern/opensolaris_vfs.c,v 1.7 2007/11/01 08:58:29 pjd Exp $"); */
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/mount.h>
38 #include <sys/pathname.h>
40 #include <lib/libkern/libkern.h>
42 MALLOC_DECLARE(M_MOUNT
);
45 lookupname(char *dirname
, enum uio_seg seg
, vnode_t
**dirvpp
, vnode_t
**compvpp
)
52 KASSERT(dirvpp
== NULL
);
54 error
= namei_simple_kernel(dirname
, NSM_FOLLOW_NOEMULROOT
, compvpp
);
61 lookupnameat(char *dirname
, enum uio_seg seg
, vnode_t
**dirvpp
,
62 vnode_t
**compvpp
, vnode_t
*startvp
)
70 /* XXX Disable until I upgrade testing kernel.
71 KASSERT(dirvpp == NULL);
73 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, dirname);
75 if ((error = nameiat(&nd, startvp)) != 0)
78 *compvpp = nd.ni_vp;*/
85 vfs_setmntopt(vfs_t
*vfsp
, const char *name
, const char *arg
,
89 if (strcmp("ro", name
) == 0)
90 vfsp
->mnt_flag
|= MNT_RDONLY
;
92 if (strcmp("rw", name
) == 0)
93 vfsp
->mnt_flag
&= ~MNT_RDONLY
;
95 if (strcmp("nodevices", name
) == 0)
96 vfsp
->mnt_flag
|= MNT_NODEV
;
98 if (strcmp("noatime", name
) == 0)
99 vfsp
->mnt_flag
|= MNT_NOATIME
;
101 if (strcmp("atime", name
) == 0)
102 vfsp
->mnt_flag
&= ~MNT_NOATIME
;
104 if (strcmp("nosuid", name
) == 0)
105 vfsp
->mnt_flag
|= MNT_NOSUID
;
107 if (strcmp("suid", name
) == 0)
108 vfsp
->mnt_flag
&= ~MNT_NOSUID
;
110 if (strcmp("noexec", name
) == 0)
111 vfsp
->mnt_flag
|= MNT_NOEXEC
;
113 if (strcmp("exec", name
) == 0)
114 vfsp
->mnt_flag
&= ~MNT_NOEXEC
;
116 vfsp
->mnt_flag
|= MNT_LOCAL
;
120 vfs_clearmntopt(vfs_t
*vfsp
, const char *name
)
123 if (strcmp("ro", name
) == 0)
124 vfsp
->mnt_flag
|= MNT_RDONLY
;
126 if (strcmp("rw", name
) == 0)
127 vfsp
->mnt_flag
&= ~MNT_RDONLY
;
129 if (strcmp("nodevices", name
) == 0)
130 vfsp
->mnt_flag
&= ~MNT_NODEV
;
132 if (strcmp("noatime", name
) == 0)
133 vfsp
->mnt_flag
&= ~MNT_NOATIME
;
135 if (strcmp("atime", name
) == 0)
136 vfsp
->mnt_flag
|= MNT_NOATIME
;
138 if (strcmp("nosuid", name
) == 0)
139 vfsp
->mnt_flag
&= ~MNT_NOSUID
;
141 if (strcmp("suid", name
) == 0)
142 vfsp
->mnt_flag
|= MNT_NOSUID
;
144 if (strcmp("noexec", name
) == 0)
145 vfsp
->mnt_flag
&= ~MNT_NOEXEC
;
147 if (strcmp("exec", name
) == 0)
148 vfsp
->mnt_flag
|= MNT_NOEXEC
;
152 vfs_optionisset(const vfs_t
*vfsp
, const char *name
, char **argp
)
155 if (strcmp("ro", name
) == 0)
156 return (vfsp
->mnt_flag
& MNT_RDONLY
) != 0;
158 if (strcmp("rw", name
) == 0)
159 return (vfsp
->mnt_flag
& MNT_RDONLY
) == 0;
161 if (strcmp("nodevices", name
) == 0)
162 return (vfsp
->mnt_flag
& MNT_NODEV
) != 0;
164 if (strcmp("noatime", name
) == 0)
165 return (vfsp
->mnt_flag
& MNT_NOATIME
) != 0;
167 if (strcmp("atime", name
) == 0)
168 return (vfsp
->mnt_flag
& MNT_NOATIME
) == 0;
170 if (strcmp("nosuid", name
) == 0)
171 return (vfsp
->mnt_flag
& MNT_NOSUID
) != 0;
173 if (strcmp("suid", name
) == 0)
174 return (vfsp
->mnt_flag
& MNT_NOSUID
) == 0;
176 if (strcmp("noexec", name
) == 0)
177 return (vfsp
->mnt_flag
& MNT_NOEXEC
) != 0;
179 if (strcmp("exec", name
) == 0)
180 return (vfsp
->mnt_flag
& MNT_NOEXEC
) == 0;
187 traverse(vnode_t
**cvpp
, int lktype
)
189 kthread_t
*td
= curthread
;
199 * If this vnode is mounted on, then we transparently indirect
200 * to the vnode which is the root of the mounted file system.
201 * Before we do this we must check that an unmount is not in
202 * progress on this vnode.
207 * Reached the end of the mount chain?
209 vfsp
= vn_mountedvfs(cvp
);
213 * tvp is NULL for *cvpp vnode, which we can't unlock.
221 * The read lock must be held across the call to VFS_ROOT() to
222 * prevent a concurrent unmount from destroying the vfs.
224 error
= VFS_ROOT(vfsp
, &tvp
);
235 domount(kthread_t
*td
, vnode_t
*vp
, const char *fstype
, char *fspath
,
236 char *fspec
, int fsflags
)
239 struct vfsconf
*vfsp
;
240 struct ucred
*newcr
, *oldcr
;
244 * Be ultra-paranoid about making sure the type and fspath
245 * variables will fit in our mp buffers, including the
248 if (strlen(fstype
) >= MFSNAMELEN
|| strlen(fspath
) >= MNAMELEN
)
249 return (ENAMETOOLONG
);
251 vfsp
= vfs_byname_kld(fstype
, td
, &error
);
255 if (vp
->v_type
!= VDIR
)
257 simple_lock(&vp
->v_interlock
);
258 if ((vp
->v_iflag
& VI_MOUNT
) != 0 ||
259 vp
->v_mountedhere
!= NULL
) {
260 simple_unlock(&vp
->v_interlock
);
263 vp
->v_iflag
|= VI_MOUNT
;
264 simple_unlock(&vp
->v_interlock
);
267 * Allocate and initialize the filesystem.
269 vn_lock(vp
, LK_SHARED
| LK_RETRY
);
270 mp
= vfs_mount_alloc(vp
, vfsp
, fspath
, td
);
273 mp
->mnt_optnew
= NULL
;
274 vfs_setmntopt(mp
, "from", fspec
, 0);
275 mp
->mnt_optnew
= mp
->mnt_opt
;
279 * Set the mount level flags.
280 * crdup() can sleep, so do it before acquiring a mutex.
282 newcr
= crdup(kcred
);
284 if (fsflags
& MNT_RDONLY
)
285 mp
->mnt_flag
|= MNT_RDONLY
;
286 mp
->mnt_flag
&=~ MNT_UPDATEMASK
;
287 mp
->mnt_flag
|= fsflags
& (MNT_UPDATEMASK
| MNT_FORCE
| MNT_ROOTFS
);
289 * Unprivileged user can trigger mounting a snapshot, but we don't want
290 * him to unmount it, so we switch to privileged credentials.
292 oldcr
= mp
->mnt_cred
;
293 mp
->mnt_cred
= newcr
;
294 mp
->mnt_stat
.f_owner
= mp
->mnt_cred
->cr_uid
;
298 * Mount the filesystem.
299 * XXX The final recipients of VFS_MOUNT just overwrite the ndp they
300 * get. No freeing of cn_pnbuf.
302 error
= VFS_MOUNT(mp
, td
);
305 if (mp
->mnt_opt
!= NULL
)
306 vfs_freeopts(mp
->mnt_opt
);
307 mp
->mnt_opt
= mp
->mnt_optnew
;
308 (void)VFS_STATFS(mp
, &mp
->mnt_stat
, td
);
311 * Prevent external consumers of mount options from reading
314 mp
->mnt_optnew
= NULL
;
315 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
);
317 * Put the new filesystem on the mount list after root.
319 #ifdef FREEBSD_NAMECACHE
325 simple_lock(&vp
->v_interlock
);
326 vp
->v_iflag
&= ~VI_MOUNT
;
327 simple_unlock(&vp
->v_interlock
);
328 vp
->v_mountedhere
= mp
;
329 mutex_enter(&mountlist_lock
);
330 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
331 mutex_exit(&mountlist_lock
);
332 vfs_event_signal(NULL
, VQ_MOUNT
, 0);
333 if (VFS_ROOT(mp
, LK_EXCLUSIVE
, &mvp
, td
))
334 panic("mount: lost mount");
335 mountcheckdirs(vp
, mvp
);
338 if ((mp
->mnt_flag
& MNT_RDONLY
) == 0)
339 error
= vfs_allocate_syncvnode(mp
);
344 vfs_mountedfrom(mp
, fspec
);
346 simple_lock(&vp
->v_interlock
);
347 vp
->v_iflag
&= ~VI_MOUNT
;
348 simple_unlock(&vp
->v_interlock
);
351 vfs_mount_destroy(mp
);