1 /* $NetBSD: vfs.c,v 1.6 2015/05/06 15:57:07 hannken Exp $ */
2
3 /*-
4 * Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
15 *
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
26 * SUCH DAMAGE.
27 */
28
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 $"); */
31
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/mount.h>
36 #include <sys/cred.h>
37 #include <sys/vfs.h>
38 #include <sys/pathname.h>
39 #include <sys/priv.h>
40 #include <lib/libkern/libkern.h>
41
42 int
lookupname(char * dirname,enum uio_seg seg,vnode_t ** dirvpp,vnode_t ** compvpp)43 lookupname(char *dirname, enum uio_seg seg, vnode_t **dirvpp, vnode_t **compvpp)
44 {
45 struct nameidata nd;
46 int error;
47
48 error = 0;
49
50 KASSERT(dirvpp == NULL);
51
52 error = namei_simple_kernel(dirname, NSM_FOLLOW_NOEMULROOT, compvpp);
53
54 return error;
55 }
56
57
58 int
lookupnameat(char * dirname,enum uio_seg seg,vnode_t ** dirvpp,vnode_t ** compvpp,vnode_t * startvp)59 lookupnameat(char *dirname, enum uio_seg seg, vnode_t **dirvpp,
60 vnode_t **compvpp, vnode_t *startvp)
61 {
62
63 struct nameidata nd;
64 int error;
65
66 error = EOPNOTSUPP;
67
68 /* XXX Disable until I upgrade testing kernel.
69 KASSERT(dirvpp == NULL);
70
71 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, dirname);
72
73 if ((error = nameiat(&nd, startvp)) != 0)
74 return error;
75
76 *compvpp = nd.ni_vp;*/
77
78 return (error);
79 }
80
81
82 void
vfs_setmntopt(vfs_t * vfsp,const char * name,const char * arg,int flags)83 vfs_setmntopt(vfs_t *vfsp, const char *name, const char *arg,
84 int flags)
85 {
86
87 if (strcmp("ro", name) == 0)
88 vfsp->mnt_flag |= MNT_RDONLY;
89
90 if (strcmp("rw", name) == 0)
91 vfsp->mnt_flag &= ~MNT_RDONLY;
92
93 if (strcmp("nodevices", name) == 0)
94 vfsp->mnt_flag |= MNT_NODEV;
95
96 if (strcmp("noatime", name) == 0)
97 vfsp->mnt_flag |= MNT_NOATIME;
98
99 if (strcmp("atime", name) == 0)
100 vfsp->mnt_flag &= ~MNT_NOATIME;
101
102 if (strcmp("nosuid", name) == 0)
103 vfsp->mnt_flag |= MNT_NOSUID;
104
105 if (strcmp("suid", name) == 0)
106 vfsp->mnt_flag &= ~MNT_NOSUID;
107
108 if (strcmp("noexec", name) == 0)
109 vfsp->mnt_flag |= MNT_NOEXEC;
110
111 if (strcmp("exec", name) == 0)
112 vfsp->mnt_flag &= ~MNT_NOEXEC;
113
114 vfsp->mnt_flag |= MNT_LOCAL;
115 }
116
117 void
vfs_clearmntopt(vfs_t * vfsp,const char * name)118 vfs_clearmntopt(vfs_t *vfsp, const char *name)
119 {
120
121 if (strcmp("ro", name) == 0)
122 vfsp->mnt_flag |= MNT_RDONLY;
123
124 if (strcmp("rw", name) == 0)
125 vfsp->mnt_flag &= ~MNT_RDONLY;
126
127 if (strcmp("nodevices", name) == 0)
128 vfsp->mnt_flag &= ~MNT_NODEV;
129
130 if (strcmp("noatime", name) == 0)
131 vfsp->mnt_flag &= ~MNT_NOATIME;
132
133 if (strcmp("atime", name) == 0)
134 vfsp->mnt_flag |= MNT_NOATIME;
135
136 if (strcmp("nosuid", name) == 0)
137 vfsp->mnt_flag &= ~MNT_NOSUID;
138
139 if (strcmp("suid", name) == 0)
140 vfsp->mnt_flag |= MNT_NOSUID;
141
142 if (strcmp("noexec", name) == 0)
143 vfsp->mnt_flag &= ~MNT_NOEXEC;
144
145 if (strcmp("exec", name) == 0)
146 vfsp->mnt_flag |= MNT_NOEXEC;
147 }
148
149 int
vfs_optionisset(const vfs_t * vfsp,const char * name,char ** argp)150 vfs_optionisset(const vfs_t *vfsp, const char *name, char **argp)
151 {
152
153 if (strcmp("ro", name) == 0)
154 return (vfsp->mnt_flag & MNT_RDONLY) != 0;
155
156 if (strcmp("rw", name) == 0)
157 return (vfsp->mnt_flag & MNT_RDONLY) == 0;
158
159 if (strcmp("nodevices", name) == 0)
160 return (vfsp->mnt_flag & MNT_NODEV) != 0;
161
162 if (strcmp("noatime", name) == 0)
163 return (vfsp->mnt_flag & MNT_NOATIME) != 0;
164
165 if (strcmp("atime", name) == 0)
166 return (vfsp->mnt_flag & MNT_NOATIME) == 0;
167
168 if (strcmp("nosuid", name) == 0)
169 return (vfsp->mnt_flag & MNT_NOSUID) != 0;
170
171 if (strcmp("suid", name) == 0)
172 return (vfsp->mnt_flag & MNT_NOSUID) == 0;
173
174 if (strcmp("noexec", name) == 0)
175 return (vfsp->mnt_flag & MNT_NOEXEC) != 0;
176
177 if (strcmp("exec", name) == 0)
178 return (vfsp->mnt_flag & MNT_NOEXEC) == 0;
179
180 return 0;
181 }
182
183 #ifdef PORT_FREEBSD
184 int
traverse(vnode_t ** cvpp,int lktype)185 traverse(vnode_t **cvpp, int lktype)
186 {
187 kthread_t *td = curthread;
188 vnode_t *cvp;
189 vnode_t *tvp;
190 vfs_t *vfsp;
191 int error;
192
193 cvp = *cvpp;
194 tvp = NULL;
195
196 /*
197 * If this vnode is mounted on, then we transparently indirect
198 * to the vnode which is the root of the mounted file system.
199 * Before we do this we must check that an unmount is not in
200 * progress on this vnode.
201 */
202
203 for (;;) {
204 /*
205 * Reached the end of the mount chain?
206 */
207 vfsp = vn_mountedvfs(cvp);
208 if (vfsp == NULL)
209 break;
210 /*
211 * tvp is NULL for *cvpp vnode, which we can't unlock.
212 */
213 if (tvp != NULL)
214 vput(cvp);
215 else
216 vrele(cvp);
217
218 /*
219 * The read lock must be held across the call to VFS_ROOT() to
220 * prevent a concurrent unmount from destroying the vfs.
221 */
222 error = VFS_ROOT(vfsp, &tvp);
223 if (error != 0)
224 return (error);
225 cvp = tvp;
226 }
227
228 *cvpp = cvp;
229 return (0);
230 }
231
232 int
domount(kthread_t * td,vnode_t * vp,const char * fstype,char * fspath,char * fspec,int fsflags)233 domount(kthread_t *td, vnode_t *vp, const char *fstype, char *fspath,
234 char *fspec, int fsflags)
235 {
236 struct mount *mp;
237 struct vfsconf *vfsp;
238 struct ucred *newcr, *oldcr;
239 int error;
240
241 /*
242 * Be ultra-paranoid about making sure the type and fspath
243 * variables will fit in our mp buffers, including the
244 * terminating NUL.
245 */
246 if (strlen(fstype) >= MFSNAMELEN || strlen(fspath) >= MNAMELEN)
247 return (ENAMETOOLONG);
248
249 vfsp = vfs_byname_kld(fstype, td, &error);
250 if (vfsp == NULL)
251 return (ENODEV);
252
253 if (vp->v_type != VDIR)
254 return (ENOTDIR);
255 simple_lock(&vp->v_interlock);
256 if ((vp->v_iflag & VI_MOUNT) != 0 ||
257 vp->v_mountedhere != NULL) {
258 simple_unlock(&vp->v_interlock);
259 return (EBUSY);
260 }
261 vp->v_iflag |= VI_MOUNT;
262 simple_unlock(&vp->v_interlock);
263
264 /*
265 * Allocate and initialize the filesystem.
266 */
267 vn_lock(vp, LK_SHARED | LK_RETRY);
268 mp = vfs_mount_alloc(vp, vfsp, fspath, td);
269 VOP_UNLOCK(vp);
270
271 mp->mnt_optnew = NULL;
272 vfs_setmntopt(mp, "from", fspec, 0);
273 mp->mnt_optnew = mp->mnt_opt;
274 mp->mnt_opt = NULL;
275
276 /*
277 * Set the mount level flags.
278 * crdup() can sleep, so do it before acquiring a mutex.
279 */
280 newcr = crdup(kcred);
281 MNT_ILOCK(mp);
282 if (fsflags & MNT_RDONLY)
283 mp->mnt_flag |= MNT_RDONLY;
284 mp->mnt_flag &=~ MNT_UPDATEMASK;
285 mp->mnt_flag |= fsflags & (MNT_UPDATEMASK | MNT_FORCE | MNT_ROOTFS);
286 /*
287 * Unprivileged user can trigger mounting a snapshot, but we don't want
288 * him to unmount it, so we switch to privileged credentials.
289 */
290 oldcr = mp->mnt_cred;
291 mp->mnt_cred = newcr;
292 mp->mnt_stat.f_owner = mp->mnt_cred->cr_uid;
293 MNT_IUNLOCK(mp);
294 crfree(oldcr);
295 /*
296 * Mount the filesystem.
297 * XXX The final recipients of VFS_MOUNT just overwrite the ndp they
298 * get. No freeing of cn_pnbuf.
299 */
300 error = VFS_MOUNT(mp, td);
301
302 if (!error) {
303 if (mp->mnt_opt != NULL)
304 vfs_freeopts(mp->mnt_opt);
305 mp->mnt_opt = mp->mnt_optnew;
306 (void)VFS_STATFS(mp, &mp->mnt_stat, td);
307 }
308 /*
309 * Prevent external consumers of mount options from reading
310 * mnt_optnew.
311 */
312 mp->mnt_optnew = NULL;
313 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
314 /*
315 * Put the new filesystem on the mount list after root.
316 */
317 #ifdef FREEBSD_NAMECACHE
318 cache_purge(vp);
319 #endif
320 if (!error) {
321 vnode_t *mvp;
322
323 simple_lock(&vp->v_interlock);
324 vp->v_iflag &= ~VI_MOUNT;
325 simple_unlock(&vp->v_interlock);
326 vp->v_mountedhere = mp;
327 mountlist_append(mp);
328 vfs_event_signal(NULL, VQ_MOUNT, 0);
329 if (VFS_ROOT(mp, LK_EXCLUSIVE, &mvp, td))
330 panic("mount: lost mount");
331 mountcheckdirs(vp, mvp);
332 vput(mvp);
333 VOP_UNLOCK(vp);
334 if ((mp->mnt_flag & MNT_RDONLY) == 0)
335 vfs_syncer_add_to_worklist(mp);
336 vfs_unbusy(mp, td);
337 vfs_mountedfrom(mp, fspec);
338 } else {
339 simple_lock(&vp->v_interlock);
340 vp->v_iflag &= ~VI_MOUNT;
341 simple_unlock(&vp->v_interlock);
342 VOP_UNLOCK(vp);
343 vfs_unbusy(mp, td);
344 vfs_mount_destroy(mp);
345 }
346 return (error);
347 }
348 #endif
349