Wed Sep 24 10:07:19 2008 UTC ()
PR kern/30525 remounting ffs read-only (mount -ur) does not sync metadata

Prevent r/w to r/o downgrade until such time as someone has verified all
the relevant file system code.


(ad)
diff -r1.372 -r1.373 src/sys/kern/vfs_syscalls.c

cvs diff -r1.372 -r1.373 src/sys/kern/vfs_syscalls.c (switch to unified diff)

--- src/sys/kern/vfs_syscalls.c 2008/09/24 09:44:09 1.372
+++ src/sys/kern/vfs_syscalls.c 2008/09/24 10:07:19 1.373
@@ -1,1175 +1,1177 @@ @@ -1,1175 +1,1177 @@
1/* $NetBSD: vfs_syscalls.c,v 1.372 2008/09/24 09:44:09 ad Exp $ */ 1/* $NetBSD: vfs_syscalls.c,v 1.373 2008/09/24 10:07:19 ad Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29/* 29/*
30 * Copyright (c) 1989, 1993 30 * Copyright (c) 1989, 1993
31 * The Regents of the University of California. All rights reserved. 31 * The Regents of the University of California. All rights reserved.
32 * (c) UNIX System Laboratories, Inc. 32 * (c) UNIX System Laboratories, Inc.
33 * All or some portions of this file are derived from material licensed 33 * All or some portions of this file are derived from material licensed
34 * to the University of California by American Telephone and Telegraph 34 * to the University of California by American Telephone and Telegraph
35 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 35 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
36 * the permission of UNIX System Laboratories, Inc. 36 * the permission of UNIX System Laboratories, Inc.
37 * 37 *
38 * Redistribution and use in source and binary forms, with or without 38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions 39 * modification, are permitted provided that the following conditions
40 * are met: 40 * are met:
41 * 1. Redistributions of source code must retain the above copyright 41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer. 42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright 43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the 44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution. 45 * documentation and/or other materials provided with the distribution.
46 * 3. Neither the name of the University nor the names of its contributors 46 * 3. Neither the name of the University nor the names of its contributors
47 * may be used to endorse or promote products derived from this software 47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission. 48 * without specific prior written permission.
49 * 49 *
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE. 60 * SUCH DAMAGE.
61 * 61 *
62 * @(#)vfs_syscalls.c 8.42 (Berkeley) 7/31/95 62 * @(#)vfs_syscalls.c 8.42 (Berkeley) 7/31/95
63 */ 63 */
64 64
65#include <sys/cdefs.h> 65#include <sys/cdefs.h>
66__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.372 2008/09/24 09:44:09 ad Exp $"); 66__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.373 2008/09/24 10:07:19 ad Exp $");
67 67
68#include "opt_compat_netbsd.h" 68#include "opt_compat_netbsd.h"
69#include "opt_compat_43.h" 69#include "opt_compat_43.h"
70#include "opt_fileassoc.h" 70#include "opt_fileassoc.h"
71#include "veriexec.h" 71#include "veriexec.h"
72 72
73#include <sys/param.h> 73#include <sys/param.h>
74#include <sys/systm.h> 74#include <sys/systm.h>
75#include <sys/namei.h> 75#include <sys/namei.h>
76#include <sys/filedesc.h> 76#include <sys/filedesc.h>
77#include <sys/kernel.h> 77#include <sys/kernel.h>
78#include <sys/file.h> 78#include <sys/file.h>
79#include <sys/stat.h> 79#include <sys/stat.h>
80#include <sys/vnode.h> 80#include <sys/vnode.h>
81#include <sys/mount.h> 81#include <sys/mount.h>
82#include <sys/proc.h> 82#include <sys/proc.h>
83#include <sys/uio.h> 83#include <sys/uio.h>
84#include <sys/malloc.h> 84#include <sys/malloc.h>
85#include <sys/kmem.h> 85#include <sys/kmem.h>
86#include <sys/dirent.h> 86#include <sys/dirent.h>
87#include <sys/sysctl.h> 87#include <sys/sysctl.h>
88#include <sys/syscallargs.h> 88#include <sys/syscallargs.h>
89#include <sys/vfs_syscalls.h> 89#include <sys/vfs_syscalls.h>
90#include <sys/ktrace.h> 90#include <sys/ktrace.h>
91#ifdef FILEASSOC 91#ifdef FILEASSOC
92#include <sys/fileassoc.h> 92#include <sys/fileassoc.h>
93#endif /* FILEASSOC */ 93#endif /* FILEASSOC */
94#include <sys/verified_exec.h> 94#include <sys/verified_exec.h>
95#include <sys/kauth.h> 95#include <sys/kauth.h>
96#include <sys/atomic.h> 96#include <sys/atomic.h>
97#include <sys/module.h> 97#include <sys/module.h>
98 98
99#include <miscfs/genfs/genfs.h> 99#include <miscfs/genfs/genfs.h>
100#include <miscfs/syncfs/syncfs.h> 100#include <miscfs/syncfs/syncfs.h>
101#include <miscfs/specfs/specdev.h> 101#include <miscfs/specfs/specdev.h>
102 102
103#ifdef COMPAT_30 103#ifdef COMPAT_30
104#include "opt_nfsserver.h" 104#include "opt_nfsserver.h"
105#include <nfs/rpcv2.h> 105#include <nfs/rpcv2.h>
106#endif 106#endif
107#include <nfs/nfsproto.h> 107#include <nfs/nfsproto.h>
108#ifdef COMPAT_30 108#ifdef COMPAT_30
109#include <nfs/nfs.h> 109#include <nfs/nfs.h>
110#include <nfs/nfs_var.h> 110#include <nfs/nfs_var.h>
111#endif 111#endif
112 112
113MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct"); 113MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct");
114 114
115static int change_dir(struct nameidata *, struct lwp *); 115static int change_dir(struct nameidata *, struct lwp *);
116static int change_flags(struct vnode *, u_long, struct lwp *); 116static int change_flags(struct vnode *, u_long, struct lwp *);
117static int change_mode(struct vnode *, int, struct lwp *l); 117static int change_mode(struct vnode *, int, struct lwp *l);
118static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int); 118static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int);
119 119
120void checkdirs(struct vnode *); 120void checkdirs(struct vnode *);
121 121
122int dovfsusermount = 0; 122int dovfsusermount = 0;
123 123
124/* 124/*
125 * Virtual File System System Calls 125 * Virtual File System System Calls
126 */ 126 */
127 127
128/* 128/*
129 * Mount a file system. 129 * Mount a file system.
130 */ 130 */
131 131
132#if defined(COMPAT_09) || defined(COMPAT_43) 132#if defined(COMPAT_09) || defined(COMPAT_43)
133/* 133/*
134 * This table is used to maintain compatibility with 4.3BSD 134 * This table is used to maintain compatibility with 4.3BSD
135 * and NetBSD 0.9 mount syscalls. Note, the order is important! 135 * and NetBSD 0.9 mount syscalls. Note, the order is important!
136 * 136 *
137 * Do not modify this table. It should only contain filesystems 137 * Do not modify this table. It should only contain filesystems
138 * supported by NetBSD 0.9 and 4.3BSD. 138 * supported by NetBSD 0.9 and 4.3BSD.
139 */ 139 */
140const char * const mountcompatnames[] = { 140const char * const mountcompatnames[] = {
141 NULL, /* 0 = MOUNT_NONE */ 141 NULL, /* 0 = MOUNT_NONE */
142 MOUNT_FFS, /* 1 = MOUNT_UFS */ 142 MOUNT_FFS, /* 1 = MOUNT_UFS */
143 MOUNT_NFS, /* 2 */ 143 MOUNT_NFS, /* 2 */
144 MOUNT_MFS, /* 3 */ 144 MOUNT_MFS, /* 3 */
145 MOUNT_MSDOS, /* 4 */ 145 MOUNT_MSDOS, /* 4 */
146 MOUNT_CD9660, /* 5 = MOUNT_ISOFS */ 146 MOUNT_CD9660, /* 5 = MOUNT_ISOFS */
147 MOUNT_FDESC, /* 6 */ 147 MOUNT_FDESC, /* 6 */
148 MOUNT_KERNFS, /* 7 */ 148 MOUNT_KERNFS, /* 7 */
149 NULL, /* 8 = MOUNT_DEVFS */ 149 NULL, /* 8 = MOUNT_DEVFS */
150 MOUNT_AFS, /* 9 */ 150 MOUNT_AFS, /* 9 */
151}; 151};
152const int nmountcompatnames = sizeof(mountcompatnames) / 152const int nmountcompatnames = sizeof(mountcompatnames) /
153 sizeof(mountcompatnames[0]); 153 sizeof(mountcompatnames[0]);
154#endif /* COMPAT_09 || COMPAT_43 */ 154#endif /* COMPAT_09 || COMPAT_43 */
155 155
156static int 156static int
157mount_update(struct lwp *l, struct vnode *vp, const char *path, int flags, 157mount_update(struct lwp *l, struct vnode *vp, const char *path, int flags,
158 void *data, size_t *data_len) 158 void *data, size_t *data_len)
159{ 159{
160 struct mount *mp; 160 struct mount *mp;
161 int error = 0, saved_flags; 161 int error = 0, saved_flags;
162 162
163 mp = vp->v_mount; 163 mp = vp->v_mount;
164 saved_flags = mp->mnt_flag; 164 saved_flags = mp->mnt_flag;
165 165
166 /* We can operate only on VV_ROOT nodes. */ 166 /* We can operate only on VV_ROOT nodes. */
167 if ((vp->v_vflag & VV_ROOT) == 0) { 167 if ((vp->v_vflag & VV_ROOT) == 0) {
168 error = EINVAL; 168 error = EINVAL;
169 goto out; 169 goto out;
170 } 170 }
171 171
172 /* 172 /*
173 * We only allow the filesystem to be reloaded if it 173 * We only allow the filesystem to be reloaded if it
174 * is currently mounted read-only. 174 * is currently mounted read-only. Additionally, we
 175 * prevent read-write to read-only downgrades.
175 */ 176 */
176 if (flags & MNT_RELOAD && !(mp->mnt_flag & MNT_RDONLY)) { 177 if ((flags & (MNT_RELOAD | MNT_RDONLY)) != 0 &&
 178 (mp->mnt_flag & MNT_RDONLY) == 0) {
177 error = EOPNOTSUPP; /* Needs translation */ 179 error = EOPNOTSUPP; /* Needs translation */
178 goto out; 180 goto out;
179 } 181 }
180 182
181 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, 183 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
182 KAUTH_REQ_SYSTEM_MOUNT_UPDATE, mp, KAUTH_ARG(flags), data); 184 KAUTH_REQ_SYSTEM_MOUNT_UPDATE, mp, KAUTH_ARG(flags), data);
183 if (error) 185 if (error)
184 goto out; 186 goto out;
185 187
186 if (vfs_busy(mp, NULL)) { 188 if (vfs_busy(mp, NULL)) {
187 error = EPERM; 189 error = EPERM;
188 goto out; 190 goto out;
189 } 191 }
190 192
191 mutex_enter(&mp->mnt_updating); 193 mutex_enter(&mp->mnt_updating);
192 194
193 mp->mnt_flag &= ~MNT_OP_FLAGS; 195 mp->mnt_flag &= ~MNT_OP_FLAGS;
194 mp->mnt_flag |= flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE); 196 mp->mnt_flag |= flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
195 197
196 /* 198 /*
197 * Set the mount level flags. 199 * Set the mount level flags.
198 */ 200 */
199 if (flags & MNT_RDONLY) 201 if (flags & MNT_RDONLY)
200 mp->mnt_flag |= MNT_RDONLY; 202 mp->mnt_flag |= MNT_RDONLY;
201 else if (mp->mnt_flag & MNT_RDONLY) 203 else if (mp->mnt_flag & MNT_RDONLY)
202 mp->mnt_iflag |= IMNT_WANTRDWR; 204 mp->mnt_iflag |= IMNT_WANTRDWR;
203 mp->mnt_flag &= 205 mp->mnt_flag &=
204 ~(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 206 ~(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
205 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP | 207 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
206 MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP | 208 MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |
207 MNT_LOG); 209 MNT_LOG);
208 mp->mnt_flag |= flags & 210 mp->mnt_flag |= flags &
209 (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 211 (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
210 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP | 212 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
211 MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP | 213 MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |
212 MNT_LOG | MNT_IGNORE); 214 MNT_LOG | MNT_IGNORE);
213 215
214 error = VFS_MOUNT(mp, path, data, data_len); 216 error = VFS_MOUNT(mp, path, data, data_len);
215 217
216#if defined(COMPAT_30) && defined(NFSSERVER) 218#if defined(COMPAT_30) && defined(NFSSERVER)
217 if (error && data != NULL) { 219 if (error && data != NULL) {
218 int error2; 220 int error2;
219 221
220 /* Update failed; let's try and see if it was an 222 /* Update failed; let's try and see if it was an
221 * export request. */ 223 * export request. */
222 error2 = nfs_update_exports_30(mp, path, data, l); 224 error2 = nfs_update_exports_30(mp, path, data, l);
223 225
224 /* Only update error code if the export request was 226 /* Only update error code if the export request was
225 * understood but some problem occurred while 227 * understood but some problem occurred while
226 * processing it. */ 228 * processing it. */
227 if (error2 != EJUSTRETURN) 229 if (error2 != EJUSTRETURN)
228 error = error2; 230 error = error2;
229 } 231 }
230#endif 232#endif
231 if (mp->mnt_iflag & IMNT_WANTRDWR) 233 if (mp->mnt_iflag & IMNT_WANTRDWR)
232 mp->mnt_flag &= ~MNT_RDONLY; 234 mp->mnt_flag &= ~MNT_RDONLY;
233 if (error) 235 if (error)
234 mp->mnt_flag = saved_flags; 236 mp->mnt_flag = saved_flags;
235 mp->mnt_flag &= ~MNT_OP_FLAGS; 237 mp->mnt_flag &= ~MNT_OP_FLAGS;
236 mp->mnt_iflag &= ~IMNT_WANTRDWR; 238 mp->mnt_iflag &= ~IMNT_WANTRDWR;
237 if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) { 239 if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) {
238 if (mp->mnt_syncer == NULL) 240 if (mp->mnt_syncer == NULL)
239 error = vfs_allocate_syncvnode(mp); 241 error = vfs_allocate_syncvnode(mp);
240 } else { 242 } else {
241 if (mp->mnt_syncer != NULL) 243 if (mp->mnt_syncer != NULL)
242 vfs_deallocate_syncvnode(mp); 244 vfs_deallocate_syncvnode(mp);
243 } 245 }
244 mutex_exit(&mp->mnt_updating); 246 mutex_exit(&mp->mnt_updating);
245 vfs_unbusy(mp, false, NULL); 247 vfs_unbusy(mp, false, NULL);
246 248
247 out: 249 out:
248 return (error); 250 return (error);
249} 251}
250 252
251static int 253static int
252mount_get_vfsops(const char *fstype, struct vfsops **vfsops) 254mount_get_vfsops(const char *fstype, struct vfsops **vfsops)
253{ 255{
254 char fstypename[sizeof(((struct statvfs *)NULL)->f_fstypename)]; 256 char fstypename[sizeof(((struct statvfs *)NULL)->f_fstypename)];
255 int error; 257 int error;
256 258
257 /* Copy file-system type from userspace. */ 259 /* Copy file-system type from userspace. */
258 error = copyinstr(fstype, fstypename, sizeof(fstypename), NULL); 260 error = copyinstr(fstype, fstypename, sizeof(fstypename), NULL);
259 if (error) { 261 if (error) {
260#if defined(COMPAT_09) || defined(COMPAT_43) 262#if defined(COMPAT_09) || defined(COMPAT_43)
261 /* 263 /*
262 * Historically, filesystem types were identified by numbers. 264 * Historically, filesystem types were identified by numbers.
263 * If we get an integer for the filesystem type instead of a 265 * If we get an integer for the filesystem type instead of a
264 * string, we check to see if it matches one of the historic 266 * string, we check to see if it matches one of the historic
265 * filesystem types. 267 * filesystem types.
266 */ 268 */
267 u_long fsindex = (u_long)fstype; 269 u_long fsindex = (u_long)fstype;
268 if (fsindex >= nmountcompatnames || 270 if (fsindex >= nmountcompatnames ||
269 mountcompatnames[fsindex] == NULL) 271 mountcompatnames[fsindex] == NULL)
270 return ENODEV; 272 return ENODEV;
271 strlcpy(fstypename, mountcompatnames[fsindex], 273 strlcpy(fstypename, mountcompatnames[fsindex],
272 sizeof(fstypename)); 274 sizeof(fstypename));
273#else 275#else
274 return error; 276 return error;
275#endif 277#endif
276 } 278 }
277 279
278#ifdef COMPAT_10 280#ifdef COMPAT_10
279 /* Accept `ufs' as an alias for `ffs'. */ 281 /* Accept `ufs' as an alias for `ffs'. */
280 if (strcmp(fstypename, "ufs") == 0) 282 if (strcmp(fstypename, "ufs") == 0)
281 fstypename[0] = 'f'; 283 fstypename[0] = 'f';
282#endif 284#endif
283 285
284 if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL) 286 if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL)
285 return 0; 287 return 0;
286 288
287 /* If we can autoload a vfs module, try again */ 289 /* If we can autoload a vfs module, try again */
288 (void)module_load(fstype, 0, NULL, MODULE_CLASS_VFS, true); 290 (void)module_load(fstype, 0, NULL, MODULE_CLASS_VFS, true);
289 291
290 if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL) 292 if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL)
291 return 0; 293 return 0;
292 294
293 return ENODEV; 295 return ENODEV;
294} 296}
295 297
296static int 298static int
297mount_domount(struct lwp *l, struct vnode **vpp, struct vfsops *vfsops, 299mount_domount(struct lwp *l, struct vnode **vpp, struct vfsops *vfsops,
298 const char *path, int flags, void *data, size_t *data_len, u_int recurse) 300 const char *path, int flags, void *data, size_t *data_len, u_int recurse)
299{ 301{
300 struct mount *mp; 302 struct mount *mp;
301 struct vnode *vp = *vpp; 303 struct vnode *vp = *vpp;
302 struct vattr va; 304 struct vattr va;
303 int error; 305 int error;
304 306
305 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, 307 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
306 KAUTH_REQ_SYSTEM_MOUNT_NEW, vp, KAUTH_ARG(flags), data); 308 KAUTH_REQ_SYSTEM_MOUNT_NEW, vp, KAUTH_ARG(flags), data);
307 if (error) 309 if (error)
308 return error; 310 return error;
309 311
310 /* Can't make a non-dir a mount-point (from here anyway). */ 312 /* Can't make a non-dir a mount-point (from here anyway). */
311 if (vp->v_type != VDIR) 313 if (vp->v_type != VDIR)
312 return ENOTDIR; 314 return ENOTDIR;
313 315
314 /* 316 /*
315 * If the user is not root, ensure that they own the directory 317 * If the user is not root, ensure that they own the directory
316 * onto which we are attempting to mount. 318 * onto which we are attempting to mount.
317 */ 319 */
318 if ((error = VOP_GETATTR(vp, &va, l->l_cred)) != 0 || 320 if ((error = VOP_GETATTR(vp, &va, l->l_cred)) != 0 ||
319 (va.va_uid != kauth_cred_geteuid(l->l_cred) && 321 (va.va_uid != kauth_cred_geteuid(l->l_cred) &&
320 (error = kauth_authorize_generic(l->l_cred, 322 (error = kauth_authorize_generic(l->l_cred,
321 KAUTH_GENERIC_ISSUSER, NULL)) != 0)) { 323 KAUTH_GENERIC_ISSUSER, NULL)) != 0)) {
322 return error; 324 return error;
323 } 325 }
324 326
325 if (flags & MNT_EXPORTED) 327 if (flags & MNT_EXPORTED)
326 return EINVAL; 328 return EINVAL;
327 329
328 if ((error = vinvalbuf(vp, V_SAVE, l->l_cred, l, 0, 0)) != 0) 330 if ((error = vinvalbuf(vp, V_SAVE, l->l_cred, l, 0, 0)) != 0)
329 return error; 331 return error;
330 332
331 /* 333 /*
332 * Check if a file-system is not already mounted on this vnode. 334 * Check if a file-system is not already mounted on this vnode.
333 */ 335 */
334 if (vp->v_mountedhere != NULL) 336 if (vp->v_mountedhere != NULL)
335 return EBUSY; 337 return EBUSY;
336 338
337 mp = kmem_zalloc(sizeof(*mp), KM_SLEEP); 339 mp = kmem_zalloc(sizeof(*mp), KM_SLEEP);
338 if (mp == NULL) 340 if (mp == NULL)
339 return ENOMEM; 341 return ENOMEM;
340 342
341 mp->mnt_op = vfsops; 343 mp->mnt_op = vfsops;
342 mp->mnt_refcnt = 1; 344 mp->mnt_refcnt = 1;
343 345
344 TAILQ_INIT(&mp->mnt_vnodelist); 346 TAILQ_INIT(&mp->mnt_vnodelist);
345 rw_init(&mp->mnt_unmounting); 347 rw_init(&mp->mnt_unmounting);
346 mutex_init(&mp->mnt_renamelock, MUTEX_DEFAULT, IPL_NONE); 348 mutex_init(&mp->mnt_renamelock, MUTEX_DEFAULT, IPL_NONE);
347 mutex_init(&mp->mnt_updating, MUTEX_DEFAULT, IPL_NONE); 349 mutex_init(&mp->mnt_updating, MUTEX_DEFAULT, IPL_NONE);
348 error = vfs_busy(mp, NULL); 350 error = vfs_busy(mp, NULL);
349 KASSERT(error == 0); 351 KASSERT(error == 0);
350 mutex_enter(&mp->mnt_updating); 352 mutex_enter(&mp->mnt_updating);
351 353
352 mp->mnt_vnodecovered = vp; 354 mp->mnt_vnodecovered = vp;
353 mp->mnt_stat.f_owner = kauth_cred_geteuid(l->l_cred); 355 mp->mnt_stat.f_owner = kauth_cred_geteuid(l->l_cred);
354 mount_initspecific(mp); 356 mount_initspecific(mp);
355 357
356 /* 358 /*
357 * The underlying file system may refuse the mount for 359 * The underlying file system may refuse the mount for
358 * various reasons. Allow the user to force it to happen. 360 * various reasons. Allow the user to force it to happen.
359 * 361 *
360 * Set the mount level flags. 362 * Set the mount level flags.
361 */ 363 */
362 mp->mnt_flag = flags & 364 mp->mnt_flag = flags &
363 (MNT_FORCE | MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | 365 (MNT_FORCE | MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
364 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP | 366 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
365 MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP | 367 MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |
366 MNT_LOG | MNT_IGNORE | MNT_RDONLY); 368 MNT_LOG | MNT_IGNORE | MNT_RDONLY);
367 369
368 error = VFS_MOUNT(mp, path, data, data_len); 370 error = VFS_MOUNT(mp, path, data, data_len);
369 mp->mnt_flag &= ~MNT_OP_FLAGS; 371 mp->mnt_flag &= ~MNT_OP_FLAGS;
370 372
371 /* 373 /*
372 * Put the new filesystem on the mount list after root. 374 * Put the new filesystem on the mount list after root.
373 */ 375 */
374 cache_purge(vp); 376 cache_purge(vp);
375 if (error != 0) { 377 if (error != 0) {
376 vp->v_mountedhere = NULL; 378 vp->v_mountedhere = NULL;
377 mutex_exit(&mp->mnt_updating); 379 mutex_exit(&mp->mnt_updating);
378 vfs_unbusy(mp, false, NULL); 380 vfs_unbusy(mp, false, NULL);
379 vfs_destroy(mp); 381 vfs_destroy(mp);
380 return error; 382 return error;
381 } 383 }
382 384
383 mp->mnt_iflag &= ~IMNT_WANTRDWR; 385 mp->mnt_iflag &= ~IMNT_WANTRDWR;
384 mutex_enter(&mountlist_lock); 386 mutex_enter(&mountlist_lock);
385 vp->v_mountedhere = mp; 387 vp->v_mountedhere = mp;
386 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 388 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
387 mutex_exit(&mountlist_lock); 389 mutex_exit(&mountlist_lock);
388 vn_restorerecurse(vp, recurse); 390 vn_restorerecurse(vp, recurse);
389 VOP_UNLOCK(vp, 0); 391 VOP_UNLOCK(vp, 0);
390 checkdirs(vp); 392 checkdirs(vp);
391 if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) 393 if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0)
392 error = vfs_allocate_syncvnode(mp); 394 error = vfs_allocate_syncvnode(mp);
393 /* Hold an additional reference to the mount across VFS_START(). */ 395 /* Hold an additional reference to the mount across VFS_START(). */
394 mutex_exit(&mp->mnt_updating); 396 mutex_exit(&mp->mnt_updating);
395 vfs_unbusy(mp, true, NULL); 397 vfs_unbusy(mp, true, NULL);
396 (void) VFS_STATVFS(mp, &mp->mnt_stat); 398 (void) VFS_STATVFS(mp, &mp->mnt_stat);
397 error = VFS_START(mp, 0); 399 error = VFS_START(mp, 0);
398 if (error) 400 if (error)
399 vrele(vp); 401 vrele(vp);
400 /* Drop reference held for VFS_START(). */ 402 /* Drop reference held for VFS_START(). */
401 vfs_destroy(mp); 403 vfs_destroy(mp);
402 *vpp = NULL; 404 *vpp = NULL;
403 return error; 405 return error;
404} 406}
405 407
406static int 408static int
407mount_getargs(struct lwp *l, struct vnode *vp, const char *path, int flags, 409mount_getargs(struct lwp *l, struct vnode *vp, const char *path, int flags,
408 void *data, size_t *data_len) 410 void *data, size_t *data_len)
409{ 411{
410 struct mount *mp; 412 struct mount *mp;
411 int error; 413 int error;
412 414
413 /* If MNT_GETARGS is specified, it should be the only flag. */ 415 /* If MNT_GETARGS is specified, it should be the only flag. */
414 if (flags & ~MNT_GETARGS) 416 if (flags & ~MNT_GETARGS)
415 return EINVAL; 417 return EINVAL;
416 418
417 mp = vp->v_mount; 419 mp = vp->v_mount;
418 420
419 /* XXX: probably some notion of "can see" here if we want isolation. */  421 /* XXX: probably some notion of "can see" here if we want isolation. */
420 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, 422 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
421 KAUTH_REQ_SYSTEM_MOUNT_GET, mp, data, NULL); 423 KAUTH_REQ_SYSTEM_MOUNT_GET, mp, data, NULL);
422 if (error) 424 if (error)
423 return error; 425 return error;
424 426
425 if ((vp->v_vflag & VV_ROOT) == 0) 427 if ((vp->v_vflag & VV_ROOT) == 0)
426 return EINVAL; 428 return EINVAL;
427 429
428 if (vfs_busy(mp, NULL)) 430 if (vfs_busy(mp, NULL))
429 return EPERM; 431 return EPERM;
430 432
431 mutex_enter(&mp->mnt_updating); 433 mutex_enter(&mp->mnt_updating);
432 mp->mnt_flag &= ~MNT_OP_FLAGS; 434 mp->mnt_flag &= ~MNT_OP_FLAGS;
433 mp->mnt_flag |= MNT_GETARGS; 435 mp->mnt_flag |= MNT_GETARGS;
434 error = VFS_MOUNT(mp, path, data, data_len); 436 error = VFS_MOUNT(mp, path, data, data_len);
435 mp->mnt_flag &= ~MNT_OP_FLAGS; 437 mp->mnt_flag &= ~MNT_OP_FLAGS;
436 mutex_exit(&mp->mnt_updating); 438 mutex_exit(&mp->mnt_updating);
437 439
438 vfs_unbusy(mp, false, NULL); 440 vfs_unbusy(mp, false, NULL);
439 return (error); 441 return (error);
440} 442}
441 443
442#ifdef COMPAT_40 444#ifdef COMPAT_40
443/* ARGSUSED */ 445/* ARGSUSED */
444int 446int
445compat_40_sys_mount(struct lwp *l, const struct compat_40_sys_mount_args *uap, register_t *retval) 447compat_40_sys_mount(struct lwp *l, const struct compat_40_sys_mount_args *uap, register_t *retval)
446{ 448{
447 /* { 449 /* {
448 syscallarg(const char *) type; 450 syscallarg(const char *) type;
449 syscallarg(const char *) path; 451 syscallarg(const char *) path;
450 syscallarg(int) flags; 452 syscallarg(int) flags;
451 syscallarg(void *) data; 453 syscallarg(void *) data;
452 } */ 454 } */
453 register_t dummy; 455 register_t dummy;
454 456
455 return do_sys_mount(l, NULL, SCARG(uap, type), SCARG(uap, path), 457 return do_sys_mount(l, NULL, SCARG(uap, type), SCARG(uap, path),
456 SCARG(uap, flags), SCARG(uap, data), UIO_USERSPACE, 0, &dummy); 458 SCARG(uap, flags), SCARG(uap, data), UIO_USERSPACE, 0, &dummy);
457} 459}
458#endif 460#endif
459 461
460int 462int
461sys___mount50(struct lwp *l, const struct sys___mount50_args *uap, register_t *retval) 463sys___mount50(struct lwp *l, const struct sys___mount50_args *uap, register_t *retval)
462{ 464{
463 /* { 465 /* {
464 syscallarg(const char *) type; 466 syscallarg(const char *) type;
465 syscallarg(const char *) path; 467 syscallarg(const char *) path;
466 syscallarg(int) flags; 468 syscallarg(int) flags;
467 syscallarg(void *) data; 469 syscallarg(void *) data;
468 syscallarg(size_t) data_len; 470 syscallarg(size_t) data_len;
469 } */ 471 } */
470 472
471 return do_sys_mount(l, NULL, SCARG(uap, type), SCARG(uap, path), 473 return do_sys_mount(l, NULL, SCARG(uap, type), SCARG(uap, path),
472 SCARG(uap, flags), SCARG(uap, data), UIO_USERSPACE, 474 SCARG(uap, flags), SCARG(uap, data), UIO_USERSPACE,
473 SCARG(uap, data_len), retval); 475 SCARG(uap, data_len), retval);
474} 476}
475 477
476int 478int
477do_sys_mount(struct lwp *l, struct vfsops *vfsops, const char *type, 479do_sys_mount(struct lwp *l, struct vfsops *vfsops, const char *type,
478 const char *path, int flags, void *data, enum uio_seg data_seg, 480 const char *path, int flags, void *data, enum uio_seg data_seg,
479 size_t data_len, register_t *retval) 481 size_t data_len, register_t *retval)
480{ 482{
481 struct vnode *vp; 483 struct vnode *vp;
482 struct nameidata nd; 484 struct nameidata nd;
483 void *data_buf = data; 485 void *data_buf = data;
484 u_int recurse; 486 u_int recurse;
485 int error; 487 int error;
486 488
487 /* 489 /*
488 * Get vnode to be covered 490 * Get vnode to be covered
489 */ 491 */
490 NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, path); 492 NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, path);
491 if ((error = namei(&nd)) != 0) 493 if ((error = namei(&nd)) != 0)
492 return (error); 494 return (error);
493 vp = nd.ni_vp; 495 vp = nd.ni_vp;
494 496
495 /* 497 /*
496 * A lookup in VFS_MOUNT might result in an attempt to 498 * A lookup in VFS_MOUNT might result in an attempt to
497 * lock this vnode again, so make the lock recursive. 499 * lock this vnode again, so make the lock recursive.
498 */ 500 */
499 if (vfsops == NULL) { 501 if (vfsops == NULL) {
500 if (flags & (MNT_GETARGS | MNT_UPDATE)) { 502 if (flags & (MNT_GETARGS | MNT_UPDATE)) {
501 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 503 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
502 recurse = vn_setrecurse(vp); 504 recurse = vn_setrecurse(vp);
503 vfsops = vp->v_mount->mnt_op; 505 vfsops = vp->v_mount->mnt_op;
504 } else { 506 } else {
505 /* 'type' is userspace */ 507 /* 'type' is userspace */
506 error = mount_get_vfsops(type, &vfsops); 508 error = mount_get_vfsops(type, &vfsops);
507 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 509 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
508 recurse = vn_setrecurse(vp); 510 recurse = vn_setrecurse(vp);
509 if (error != 0) 511 if (error != 0)
510 goto done; 512 goto done;
511 } 513 }
512 } else { 514 } else {
513 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 515 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
514 recurse = vn_setrecurse(vp); 516 recurse = vn_setrecurse(vp);
515 } 517 }
516 518
517 if (data != NULL && data_seg == UIO_USERSPACE) { 519 if (data != NULL && data_seg == UIO_USERSPACE) {
518 if (data_len == 0) { 520 if (data_len == 0) {
519 /* No length supplied, use default for filesystem */ 521 /* No length supplied, use default for filesystem */
520 data_len = vfsops->vfs_min_mount_data; 522 data_len = vfsops->vfs_min_mount_data;
521 if (data_len > VFS_MAX_MOUNT_DATA) { 523 if (data_len > VFS_MAX_MOUNT_DATA) {
522 /* maybe a force loaded old LKM */ 524 /* maybe a force loaded old LKM */
523 error = EINVAL; 525 error = EINVAL;
524 goto done; 526 goto done;
525 } 527 }
526#ifdef COMPAT_30 528#ifdef COMPAT_30
527 /* Hopefully a longer buffer won't make copyin() fail */ 529 /* Hopefully a longer buffer won't make copyin() fail */
528 if (flags & MNT_UPDATE 530 if (flags & MNT_UPDATE
529 && data_len < sizeof (struct mnt_export_args30)) 531 && data_len < sizeof (struct mnt_export_args30))
530 data_len = sizeof (struct mnt_export_args30); 532 data_len = sizeof (struct mnt_export_args30);
531#endif 533#endif
532 } 534 }
533 data_buf = malloc(data_len, M_TEMP, M_WAITOK); 535 data_buf = malloc(data_len, M_TEMP, M_WAITOK);
534 536
535 /* NFS needs the buffer even for mnt_getargs .... */ 537 /* NFS needs the buffer even for mnt_getargs .... */
536 error = copyin(data, data_buf, data_len); 538 error = copyin(data, data_buf, data_len);
537 if (error != 0) 539 if (error != 0)
538 goto done; 540 goto done;
539 } 541 }
540 542
541 if (flags & MNT_GETARGS) { 543 if (flags & MNT_GETARGS) {
542 if (data_len == 0) { 544 if (data_len == 0) {
543 error = EINVAL; 545 error = EINVAL;
544 goto done; 546 goto done;
545 } 547 }
546 error = mount_getargs(l, vp, path, flags, data_buf, &data_len); 548 error = mount_getargs(l, vp, path, flags, data_buf, &data_len);
547 if (error != 0) 549 if (error != 0)
548 goto done; 550 goto done;
549 if (data_seg == UIO_USERSPACE) 551 if (data_seg == UIO_USERSPACE)
550 error = copyout(data_buf, data, data_len); 552 error = copyout(data_buf, data, data_len);
551 *retval = data_len; 553 *retval = data_len;
552 } else if (flags & MNT_UPDATE) { 554 } else if (flags & MNT_UPDATE) {
553 error = mount_update(l, vp, path, flags, data_buf, &data_len); 555 error = mount_update(l, vp, path, flags, data_buf, &data_len);
554 } else { 556 } else {
555 /* Locking is handled internally in mount_domount(). */ 557 /* Locking is handled internally in mount_domount(). */
556 error = mount_domount(l, &vp, vfsops, path, flags, data_buf, 558 error = mount_domount(l, &vp, vfsops, path, flags, data_buf,
557 &data_len, recurse); 559 &data_len, recurse);
558 } 560 }
559 561
560 done: 562 done:
561 if (vp != NULL) { 563 if (vp != NULL) {
562 vn_restorerecurse(vp, recurse); 564 vn_restorerecurse(vp, recurse);
563 vput(vp); 565 vput(vp);
564 } 566 }
565 if (data_buf != data) 567 if (data_buf != data)
566 free(data_buf, M_TEMP); 568 free(data_buf, M_TEMP);
567 return (error); 569 return (error);
568} 570}
569 571
570/* 572/*
571 * Scan all active processes to see if any of them have a current 573 * Scan all active processes to see if any of them have a current
572 * or root directory onto which the new filesystem has just been 574 * or root directory onto which the new filesystem has just been
573 * mounted. If so, replace them with the new mount point. 575 * mounted. If so, replace them with the new mount point.
574 */ 576 */
575void 577void
576checkdirs(struct vnode *olddp) 578checkdirs(struct vnode *olddp)
577{ 579{
578 struct cwdinfo *cwdi; 580 struct cwdinfo *cwdi;
579 struct vnode *newdp, *rele1, *rele2; 581 struct vnode *newdp, *rele1, *rele2;
580 struct proc *p; 582 struct proc *p;
581 bool retry; 583 bool retry;
582 584
583 if (olddp->v_usecount == 1) 585 if (olddp->v_usecount == 1)
584 return; 586 return;
585 if (VFS_ROOT(olddp->v_mountedhere, &newdp)) 587 if (VFS_ROOT(olddp->v_mountedhere, &newdp))
586 panic("mount: lost mount"); 588 panic("mount: lost mount");
587 589
588 do { 590 do {
589 retry = false; 591 retry = false;
590 mutex_enter(proc_lock); 592 mutex_enter(proc_lock);
591 PROCLIST_FOREACH(p, &allproc) { 593 PROCLIST_FOREACH(p, &allproc) {
592 if ((p->p_flag & PK_MARKER) != 0) 594 if ((p->p_flag & PK_MARKER) != 0)
593 continue; 595 continue;
594 if ((cwdi = p->p_cwdi) == NULL) 596 if ((cwdi = p->p_cwdi) == NULL)
595 continue; 597 continue;
596 /* 598 /*
597 * Can't change to the old directory any more, 599 * Can't change to the old directory any more,
598 * so even if we see a stale value it's not a 600 * so even if we see a stale value it's not a
599 * problem. 601 * problem.
600 */ 602 */
601 if (cwdi->cwdi_cdir != olddp && 603 if (cwdi->cwdi_cdir != olddp &&
602 cwdi->cwdi_rdir != olddp) 604 cwdi->cwdi_rdir != olddp)
603 continue; 605 continue;
604 retry = true; 606 retry = true;
605 rele1 = NULL; 607 rele1 = NULL;
606 rele2 = NULL; 608 rele2 = NULL;
607 atomic_inc_uint(&cwdi->cwdi_refcnt); 609 atomic_inc_uint(&cwdi->cwdi_refcnt);
608 mutex_exit(proc_lock); 610 mutex_exit(proc_lock);
609 rw_enter(&cwdi->cwdi_lock, RW_WRITER); 611 rw_enter(&cwdi->cwdi_lock, RW_WRITER);
610 if (cwdi->cwdi_cdir == olddp) { 612 if (cwdi->cwdi_cdir == olddp) {
611 rele1 = cwdi->cwdi_cdir; 613 rele1 = cwdi->cwdi_cdir;
612 VREF(newdp); 614 VREF(newdp);
613 cwdi->cwdi_cdir = newdp; 615 cwdi->cwdi_cdir = newdp;
614 } 616 }
615 if (cwdi->cwdi_rdir == olddp) { 617 if (cwdi->cwdi_rdir == olddp) {
616 rele2 = cwdi->cwdi_rdir; 618 rele2 = cwdi->cwdi_rdir;
617 VREF(newdp); 619 VREF(newdp);
618 cwdi->cwdi_rdir = newdp; 620 cwdi->cwdi_rdir = newdp;
619 } 621 }
620 rw_exit(&cwdi->cwdi_lock); 622 rw_exit(&cwdi->cwdi_lock);
621 cwdfree(cwdi); 623 cwdfree(cwdi);
622 if (rele1 != NULL) 624 if (rele1 != NULL)
623 vrele(rele1); 625 vrele(rele1);
624 if (rele2 != NULL) 626 if (rele2 != NULL)
625 vrele(rele2); 627 vrele(rele2);
626 mutex_enter(proc_lock); 628 mutex_enter(proc_lock);
627 break; 629 break;
628 } 630 }
629 mutex_exit(proc_lock); 631 mutex_exit(proc_lock);
630 } while (retry); 632 } while (retry);
631 633
632 if (rootvnode == olddp) { 634 if (rootvnode == olddp) {
633 vrele(rootvnode); 635 vrele(rootvnode);
634 VREF(newdp); 636 VREF(newdp);
635 rootvnode = newdp; 637 rootvnode = newdp;
636 } 638 }
637 vput(newdp); 639 vput(newdp);
638} 640}
639 641
640/* 642/*
641 * Unmount a file system. 643 * Unmount a file system.
642 * 644 *
643 * Note: unmount takes a path to the vnode mounted on as argument, 645 * Note: unmount takes a path to the vnode mounted on as argument,
644 * not special file (as before). 646 * not special file (as before).
645 */ 647 */
646/* ARGSUSED */ 648/* ARGSUSED */
647int 649int
648sys_unmount(struct lwp *l, const struct sys_unmount_args *uap, register_t *retval) 650sys_unmount(struct lwp *l, const struct sys_unmount_args *uap, register_t *retval)
649{ 651{
650 /* { 652 /* {
651 syscallarg(const char *) path; 653 syscallarg(const char *) path;
652 syscallarg(int) flags; 654 syscallarg(int) flags;
653 } */ 655 } */
654 struct vnode *vp; 656 struct vnode *vp;
655 struct mount *mp; 657 struct mount *mp;
656 int error; 658 int error;
657 struct nameidata nd; 659 struct nameidata nd;
658 660
659 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE, 661 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE,
660 SCARG(uap, path)); 662 SCARG(uap, path));
661 if ((error = namei(&nd)) != 0) 663 if ((error = namei(&nd)) != 0)
662 return (error); 664 return (error);
663 vp = nd.ni_vp; 665 vp = nd.ni_vp;
664 mp = vp->v_mount; 666 mp = vp->v_mount;
665 atomic_inc_uint(&mp->mnt_refcnt); 667 atomic_inc_uint(&mp->mnt_refcnt);
666 VOP_UNLOCK(vp, 0); 668 VOP_UNLOCK(vp, 0);
667 669
668 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT, 670 error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
669 KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, mp, NULL, NULL); 671 KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, mp, NULL, NULL);
670 if (error) { 672 if (error) {
671 vrele(vp); 673 vrele(vp);
672 vfs_destroy(mp); 674 vfs_destroy(mp);
673 return (error); 675 return (error);
674 } 676 }
675 677
676 /* 678 /*
677 * Don't allow unmounting the root file system. 679 * Don't allow unmounting the root file system.
678 */ 680 */
679 if (mp->mnt_flag & MNT_ROOTFS) { 681 if (mp->mnt_flag & MNT_ROOTFS) {
680 vrele(vp); 682 vrele(vp);
681 vfs_destroy(mp); 683 vfs_destroy(mp);
682 return (EINVAL); 684 return (EINVAL);
683 } 685 }
684 686
685 /* 687 /*
686 * Must be the root of the filesystem 688 * Must be the root of the filesystem
687 */ 689 */
688 if ((vp->v_vflag & VV_ROOT) == 0) { 690 if ((vp->v_vflag & VV_ROOT) == 0) {
689 vrele(vp); 691 vrele(vp);
690 vfs_destroy(mp); 692 vfs_destroy(mp);
691 return (EINVAL); 693 return (EINVAL);
692 } 694 }
693 695
694 vrele(vp); 696 vrele(vp);
695 error = dounmount(mp, SCARG(uap, flags), l); 697 error = dounmount(mp, SCARG(uap, flags), l);
696 return error; 698 return error;
697} 699}
698 700
699/* 701/*
700 * Do the actual file system unmount. File system is assumed to have 702 * Do the actual file system unmount. File system is assumed to have
701 * been locked by the caller. 703 * been locked by the caller.
702 * 704 *
703 * => Caller gain reference to the mount, explicility for unmount. 705 * => Caller gain reference to the mount, explicility for unmount.
704 * => Reference will be dropped in all cases. 706 * => Reference will be dropped in all cases.
705 */ 707 */
706int 708int
707dounmount(struct mount *mp, int flags, struct lwp *l) 709dounmount(struct mount *mp, int flags, struct lwp *l)
708{ 710{
709 struct vnode *coveredvp; 711 struct vnode *coveredvp;
710 int error; 712 int error;
711 int async; 713 int async;
712 int used_syncer; 714 int used_syncer;
713 715
714#if NVERIEXEC > 0 716#if NVERIEXEC > 0
715 error = veriexec_unmountchk(mp); 717 error = veriexec_unmountchk(mp);
716 if (error) 718 if (error)
717 return (error); 719 return (error);
718#endif /* NVERIEXEC > 0 */ 720#endif /* NVERIEXEC > 0 */
719 721
720 /* 722 /*
721 * XXX Freeze syncer. Must do this before locking the 723 * XXX Freeze syncer. Must do this before locking the
722 * mount point. See dounmount() for details. 724 * mount point. See dounmount() for details.
723 */ 725 */
724 mutex_enter(&syncer_mutex); 726 mutex_enter(&syncer_mutex);
725 rw_enter(&mp->mnt_unmounting, RW_WRITER); 727 rw_enter(&mp->mnt_unmounting, RW_WRITER);
726 if ((mp->mnt_iflag & IMNT_GONE) != 0) { 728 if ((mp->mnt_iflag & IMNT_GONE) != 0) {
727 rw_exit(&mp->mnt_unmounting); 729 rw_exit(&mp->mnt_unmounting);
728 mutex_exit(&syncer_mutex); 730 mutex_exit(&syncer_mutex);
729 vfs_destroy(mp); 731 vfs_destroy(mp);
730 return ENOENT; 732 return ENOENT;
731 } 733 }
732 734
733 used_syncer = (mp->mnt_syncer != NULL); 735 used_syncer = (mp->mnt_syncer != NULL);
734 736
735 /* 737 /*
736 * XXX Syncer must be frozen when we get here. This should really 738 * XXX Syncer must be frozen when we get here. This should really
737 * be done on a per-mountpoint basis, but especially the softdep 739 * be done on a per-mountpoint basis, but especially the softdep
738 * code possibly called from the syncer doesn't exactly work on a 740 * code possibly called from the syncer doesn't exactly work on a
739 * per-mountpoint basis, so the softdep code would become a maze 741 * per-mountpoint basis, so the softdep code would become a maze
740 * of vfs_busy() calls. 742 * of vfs_busy() calls.
741 * 743 *
742 * The caller of dounmount() must acquire syncer_mutex because 744 * The caller of dounmount() must acquire syncer_mutex because
743 * the syncer itself acquires locks in syncer_mutex -> vfs_busy 745 * the syncer itself acquires locks in syncer_mutex -> vfs_busy
744 * order, and we must preserve that order to avoid deadlock. 746 * order, and we must preserve that order to avoid deadlock.
745 * 747 *
746 * So, if the file system did not use the syncer, now is 748 * So, if the file system did not use the syncer, now is
747 * the time to release the syncer_mutex. 749 * the time to release the syncer_mutex.
748 */ 750 */
749 if (used_syncer == 0) 751 if (used_syncer == 0)
750 mutex_exit(&syncer_mutex); 752 mutex_exit(&syncer_mutex);
751 753
752 mp->mnt_iflag |= IMNT_UNMOUNT; 754 mp->mnt_iflag |= IMNT_UNMOUNT;
753 async = mp->mnt_flag & MNT_ASYNC; 755 async = mp->mnt_flag & MNT_ASYNC;
754 mp->mnt_flag &= ~MNT_ASYNC; 756 mp->mnt_flag &= ~MNT_ASYNC;
755 cache_purgevfs(mp); /* remove cache entries for this file sys */ 757 cache_purgevfs(mp); /* remove cache entries for this file sys */
756 if (mp->mnt_syncer != NULL) 758 if (mp->mnt_syncer != NULL)
757 vfs_deallocate_syncvnode(mp); 759 vfs_deallocate_syncvnode(mp);
758 error = 0; 760 error = 0;
759 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 761 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
760 error = VFS_SYNC(mp, MNT_WAIT, l->l_cred); 762 error = VFS_SYNC(mp, MNT_WAIT, l->l_cred);
761 } 763 }
762 vfs_scrubvnlist(mp); 764 vfs_scrubvnlist(mp);
763 if (error == 0 || (flags & MNT_FORCE)) 765 if (error == 0 || (flags & MNT_FORCE))
764 error = VFS_UNMOUNT(mp, flags); 766 error = VFS_UNMOUNT(mp, flags);
765 if (error) { 767 if (error) {
766 if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) 768 if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0)
767 (void) vfs_allocate_syncvnode(mp); 769 (void) vfs_allocate_syncvnode(mp);
768 mp->mnt_iflag &= ~IMNT_UNMOUNT; 770 mp->mnt_iflag &= ~IMNT_UNMOUNT;
769 mp->mnt_flag |= async; 771 mp->mnt_flag |= async;
770 rw_exit(&mp->mnt_unmounting); 772 rw_exit(&mp->mnt_unmounting);
771 if (used_syncer) 773 if (used_syncer)
772 mutex_exit(&syncer_mutex); 774 mutex_exit(&syncer_mutex);
773 return (error); 775 return (error);
774 } 776 }
775 vfs_scrubvnlist(mp); 777 vfs_scrubvnlist(mp);
776 mutex_enter(&mountlist_lock); 778 mutex_enter(&mountlist_lock);
777 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) 779 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP)
778 coveredvp->v_mountedhere = NULL; 780 coveredvp->v_mountedhere = NULL;
779 CIRCLEQ_REMOVE(&mountlist, mp, mnt_list); 781 CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
780 mp->mnt_iflag |= IMNT_GONE; 782 mp->mnt_iflag |= IMNT_GONE;
781 mutex_exit(&mountlist_lock); 783 mutex_exit(&mountlist_lock);
782 if (TAILQ_FIRST(&mp->mnt_vnodelist) != NULL) 784 if (TAILQ_FIRST(&mp->mnt_vnodelist) != NULL)
783 panic("unmount: dangling vnode"); 785 panic("unmount: dangling vnode");
784 if (used_syncer) 786 if (used_syncer)
785 mutex_exit(&syncer_mutex); 787 mutex_exit(&syncer_mutex);
786 vfs_hooks_unmount(mp); 788 vfs_hooks_unmount(mp);
787 rw_exit(&mp->mnt_unmounting); 789 rw_exit(&mp->mnt_unmounting);
788 vfs_destroy(mp); /* caller provided reference */ 790 vfs_destroy(mp); /* caller provided reference */
789 vfs_destroy(mp); /* from mount(), final nail in coffin */ 791 vfs_destroy(mp); /* from mount(), final nail in coffin */
790 if (coveredvp != NULLVP) 792 if (coveredvp != NULLVP)
791 vrele(coveredvp); 793 vrele(coveredvp);
792 return (0); 794 return (0);
793} 795}
794 796
795/* 797/*
796 * Sync each mounted filesystem. 798 * Sync each mounted filesystem.
797 */ 799 */
798#ifdef DEBUG 800#ifdef DEBUG
799int syncprt = 0; 801int syncprt = 0;
800struct ctldebug debug0 = { "syncprt", &syncprt }; 802struct ctldebug debug0 = { "syncprt", &syncprt };
801#endif 803#endif
802 804
803/* ARGSUSED */ 805/* ARGSUSED */
804int 806int
805sys_sync(struct lwp *l, const void *v, register_t *retval) 807sys_sync(struct lwp *l, const void *v, register_t *retval)
806{ 808{
807 struct mount *mp, *nmp; 809 struct mount *mp, *nmp;
808 int asyncflag; 810 int asyncflag;
809 811
810 if (l == NULL) 812 if (l == NULL)
811 l = &lwp0; 813 l = &lwp0;
812 814
813 mutex_enter(&mountlist_lock); 815 mutex_enter(&mountlist_lock);
814 for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist; 816 for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
815 mp = nmp) { 817 mp = nmp) {
816 if (vfs_busy(mp, &nmp)) { 818 if (vfs_busy(mp, &nmp)) {
817 continue; 819 continue;
818 } 820 }
819 mutex_enter(&mp->mnt_updating); 821 mutex_enter(&mp->mnt_updating);
820 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 822 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
821 asyncflag = mp->mnt_flag & MNT_ASYNC; 823 asyncflag = mp->mnt_flag & MNT_ASYNC;
822 mp->mnt_flag &= ~MNT_ASYNC; 824 mp->mnt_flag &= ~MNT_ASYNC;
823 VFS_SYNC(mp, MNT_NOWAIT, l->l_cred); 825 VFS_SYNC(mp, MNT_NOWAIT, l->l_cred);
824 if (asyncflag) 826 if (asyncflag)
825 mp->mnt_flag |= MNT_ASYNC; 827 mp->mnt_flag |= MNT_ASYNC;
826 } 828 }
827 mutex_exit(&mp->mnt_updating); 829 mutex_exit(&mp->mnt_updating);
828 vfs_unbusy(mp, false, &nmp); 830 vfs_unbusy(mp, false, &nmp);
829 } 831 }
830 mutex_exit(&mountlist_lock); 832 mutex_exit(&mountlist_lock);
831#ifdef DEBUG 833#ifdef DEBUG
832 if (syncprt) 834 if (syncprt)
833 vfs_bufstats(); 835 vfs_bufstats();
834#endif /* DEBUG */ 836#endif /* DEBUG */
835 return (0); 837 return (0);
836} 838}
837 839
838/* 840/*
839 * Change filesystem quotas. 841 * Change filesystem quotas.
840 */ 842 */
841/* ARGSUSED */ 843/* ARGSUSED */
842int 844int
843sys_quotactl(struct lwp *l, const struct sys_quotactl_args *uap, register_t *retval) 845sys_quotactl(struct lwp *l, const struct sys_quotactl_args *uap, register_t *retval)
844{ 846{
845 /* { 847 /* {
846 syscallarg(const char *) path; 848 syscallarg(const char *) path;
847 syscallarg(int) cmd; 849 syscallarg(int) cmd;
848 syscallarg(int) uid; 850 syscallarg(int) uid;
849 syscallarg(void *) arg; 851 syscallarg(void *) arg;
850 } */ 852 } */
851 struct mount *mp; 853 struct mount *mp;
852 int error; 854 int error;
853 struct nameidata nd; 855 struct nameidata nd;
854 856
855 NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, 857 NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,
856 SCARG(uap, path)); 858 SCARG(uap, path));
857 if ((error = namei(&nd)) != 0) 859 if ((error = namei(&nd)) != 0)
858 return (error); 860 return (error);
859 mp = nd.ni_vp->v_mount; 861 mp = nd.ni_vp->v_mount;
860 error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid), 862 error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
861 SCARG(uap, arg)); 863 SCARG(uap, arg));
862 vrele(nd.ni_vp); 864 vrele(nd.ni_vp);
863 return (error); 865 return (error);
864} 866}
865 867
866int 868int
867dostatvfs(struct mount *mp, struct statvfs *sp, struct lwp *l, int flags, 869dostatvfs(struct mount *mp, struct statvfs *sp, struct lwp *l, int flags,
868 int root) 870 int root)
869{ 871{
870 struct cwdinfo *cwdi = l->l_proc->p_cwdi; 872 struct cwdinfo *cwdi = l->l_proc->p_cwdi;
871 int error = 0; 873 int error = 0;
872 874
873 /* 875 /*
874 * If MNT_NOWAIT or MNT_LAZY is specified, do not 876 * If MNT_NOWAIT or MNT_LAZY is specified, do not
875 * refresh the fsstat cache. MNT_WAIT or MNT_LAZY 877 * refresh the fsstat cache. MNT_WAIT or MNT_LAZY
876 * overrides MNT_NOWAIT. 878 * overrides MNT_NOWAIT.
877 */ 879 */
878 if (flags == MNT_NOWAIT || flags == MNT_LAZY || 880 if (flags == MNT_NOWAIT || flags == MNT_LAZY ||
879 (flags != MNT_WAIT && flags != 0)) { 881 (flags != MNT_WAIT && flags != 0)) {
880 memcpy(sp, &mp->mnt_stat, sizeof(*sp)); 882 memcpy(sp, &mp->mnt_stat, sizeof(*sp));
881 goto done; 883 goto done;
882 } 884 }
883 885
884 /* Get the filesystem stats now */ 886 /* Get the filesystem stats now */
885 memset(sp, 0, sizeof(*sp)); 887 memset(sp, 0, sizeof(*sp));
886 if ((error = VFS_STATVFS(mp, sp)) != 0) { 888 if ((error = VFS_STATVFS(mp, sp)) != 0) {
887 return error; 889 return error;
888 } 890 }
889 891
890 if (cwdi->cwdi_rdir == NULL) 892 if (cwdi->cwdi_rdir == NULL)
891 (void)memcpy(&mp->mnt_stat, sp, sizeof(mp->mnt_stat)); 893 (void)memcpy(&mp->mnt_stat, sp, sizeof(mp->mnt_stat));
892done: 894done:
893 if (cwdi->cwdi_rdir != NULL) { 895 if (cwdi->cwdi_rdir != NULL) {
894 size_t len; 896 size_t len;
895 char *bp; 897 char *bp;
896 char c; 898 char c;
897 char *path = PNBUF_GET(); 899 char *path = PNBUF_GET();
898 900
899 bp = path + MAXPATHLEN; 901 bp = path + MAXPATHLEN;
900 *--bp = '\0'; 902 *--bp = '\0';
901 rw_enter(&cwdi->cwdi_lock, RW_READER); 903 rw_enter(&cwdi->cwdi_lock, RW_READER);
902 error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp, path, 904 error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp, path,
903 MAXPATHLEN / 2, 0, l); 905 MAXPATHLEN / 2, 0, l);
904 rw_exit(&cwdi->cwdi_lock); 906 rw_exit(&cwdi->cwdi_lock);
905 if (error) { 907 if (error) {
906 PNBUF_PUT(path); 908 PNBUF_PUT(path);
907 return error; 909 return error;
908 } 910 }
909 len = strlen(bp); 911 len = strlen(bp);
910 /* 912 /*
911 * for mount points that are below our root, we can see 913 * for mount points that are below our root, we can see
912 * them, so we fix up the pathname and return them. The 914 * them, so we fix up the pathname and return them. The
913 * rest we cannot see, so we don't allow viewing the 915 * rest we cannot see, so we don't allow viewing the
914 * data. 916 * data.
915 */ 917 */
916 if (strncmp(bp, sp->f_mntonname, len) == 0 && 918 if (strncmp(bp, sp->f_mntonname, len) == 0 &&
917 ((c = sp->f_mntonname[len]) == '/' || c == '\0')) { 919 ((c = sp->f_mntonname[len]) == '/' || c == '\0')) {
918 (void)strlcpy(sp->f_mntonname, &sp->f_mntonname[len], 920 (void)strlcpy(sp->f_mntonname, &sp->f_mntonname[len],
919 sizeof(sp->f_mntonname)); 921 sizeof(sp->f_mntonname));
920 if (sp->f_mntonname[0] == '\0') 922 if (sp->f_mntonname[0] == '\0')
921 (void)strlcpy(sp->f_mntonname, "/", 923 (void)strlcpy(sp->f_mntonname, "/",
922 sizeof(sp->f_mntonname)); 924 sizeof(sp->f_mntonname));
923 } else { 925 } else {
924 if (root) 926 if (root)
925 (void)strlcpy(sp->f_mntonname, "/", 927 (void)strlcpy(sp->f_mntonname, "/",
926 sizeof(sp->f_mntonname)); 928 sizeof(sp->f_mntonname));
927 else 929 else
928 error = EPERM; 930 error = EPERM;
929 } 931 }
930 PNBUF_PUT(path); 932 PNBUF_PUT(path);
931 } 933 }
932 sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK; 934 sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
933 return error; 935 return error;
934} 936}
935 937
936/* 938/*
937 * Get filesystem statistics by path. 939 * Get filesystem statistics by path.
938 */ 940 */
939int 941int
940do_sys_pstatvfs(struct lwp *l, const char *path, int flags, struct statvfs *sb) 942do_sys_pstatvfs(struct lwp *l, const char *path, int flags, struct statvfs *sb)
941{ 943{
942 struct mount *mp; 944 struct mount *mp;
943 int error; 945 int error;
944 struct nameidata nd; 946 struct nameidata nd;
945 947
946 NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, path); 948 NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, path);
947 if ((error = namei(&nd)) != 0) 949 if ((error = namei(&nd)) != 0)
948 return error; 950 return error;
949 mp = nd.ni_vp->v_mount; 951 mp = nd.ni_vp->v_mount;
950 error = dostatvfs(mp, sb, l, flags, 1); 952 error = dostatvfs(mp, sb, l, flags, 1);
951 vrele(nd.ni_vp); 953 vrele(nd.ni_vp);
952 return error; 954 return error;
953} 955}
954 956
955/* ARGSUSED */ 957/* ARGSUSED */
956int 958int
957sys_statvfs1(struct lwp *l, const struct sys_statvfs1_args *uap, register_t *retval) 959sys_statvfs1(struct lwp *l, const struct sys_statvfs1_args *uap, register_t *retval)
958{ 960{
959 /* { 961 /* {
960 syscallarg(const char *) path; 962 syscallarg(const char *) path;
961 syscallarg(struct statvfs *) buf; 963 syscallarg(struct statvfs *) buf;
962 syscallarg(int) flags; 964 syscallarg(int) flags;
963 } */ 965 } */
964 struct statvfs *sb; 966 struct statvfs *sb;
965 int error; 967 int error;
966 968
967 sb = STATVFSBUF_GET(); 969 sb = STATVFSBUF_GET();
968 error = do_sys_pstatvfs(l, SCARG(uap, path), SCARG(uap, flags), sb); 970 error = do_sys_pstatvfs(l, SCARG(uap, path), SCARG(uap, flags), sb);
969 if (error == 0) 971 if (error == 0)
970 error = copyout(sb, SCARG(uap, buf), sizeof(*sb)); 972 error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
971 STATVFSBUF_PUT(sb); 973 STATVFSBUF_PUT(sb);
972 return error; 974 return error;
973} 975}
974 976
975/* 977/*
976 * Get filesystem statistics by fd. 978 * Get filesystem statistics by fd.
977 */ 979 */
978int 980int
979do_sys_fstatvfs(struct lwp *l, int fd, int flags, struct statvfs *sb) 981do_sys_fstatvfs(struct lwp *l, int fd, int flags, struct statvfs *sb)
980{ 982{
981 file_t *fp; 983 file_t *fp;
982 struct mount *mp; 984 struct mount *mp;
983 int error; 985 int error;
984 986
985 /* fd_getvnode() will use the descriptor for us */ 987 /* fd_getvnode() will use the descriptor for us */
986 if ((error = fd_getvnode(fd, &fp)) != 0) 988 if ((error = fd_getvnode(fd, &fp)) != 0)
987 return (error); 989 return (error);
988 mp = ((struct vnode *)fp->f_data)->v_mount; 990 mp = ((struct vnode *)fp->f_data)->v_mount;
989 error = dostatvfs(mp, sb, curlwp, flags, 1); 991 error = dostatvfs(mp, sb, curlwp, flags, 1);
990 fd_putfile(fd); 992 fd_putfile(fd);
991 return error; 993 return error;
992} 994}
993 995
994/* ARGSUSED */ 996/* ARGSUSED */
995int 997int
996sys_fstatvfs1(struct lwp *l, const struct sys_fstatvfs1_args *uap, register_t *retval) 998sys_fstatvfs1(struct lwp *l, const struct sys_fstatvfs1_args *uap, register_t *retval)
997{ 999{
998 /* { 1000 /* {
999 syscallarg(int) fd; 1001 syscallarg(int) fd;
1000 syscallarg(struct statvfs *) buf; 1002 syscallarg(struct statvfs *) buf;
1001 syscallarg(int) flags; 1003 syscallarg(int) flags;
1002 } */ 1004 } */
1003 struct statvfs *sb; 1005 struct statvfs *sb;
1004 int error; 1006 int error;
1005 1007
1006 sb = STATVFSBUF_GET(); 1008 sb = STATVFSBUF_GET();
1007 error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb); 1009 error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb);
1008 if (error == 0) 1010 if (error == 0)
1009 error = copyout(sb, SCARG(uap, buf), sizeof(*sb)); 1011 error = copyout(sb, SCARG(uap, buf), sizeof(*sb));
1010 STATVFSBUF_PUT(sb); 1012 STATVFSBUF_PUT(sb);
1011 return error; 1013 return error;
1012} 1014}
1013 1015
1014 1016
1015/* 1017/*
1016 * Get statistics on all filesystems. 1018 * Get statistics on all filesystems.
1017 */ 1019 */
1018int 1020int
1019do_sys_getvfsstat(struct lwp *l, void *sfsp, size_t bufsize, int flags, 1021do_sys_getvfsstat(struct lwp *l, void *sfsp, size_t bufsize, int flags,
1020 int (*copyfn)(const void *, void *, size_t), size_t entry_sz, 1022 int (*copyfn)(const void *, void *, size_t), size_t entry_sz,
1021 register_t *retval) 1023 register_t *retval)
1022{ 1024{
1023 int root = 0; 1025 int root = 0;
1024 struct proc *p = l->l_proc; 1026 struct proc *p = l->l_proc;
1025 struct mount *mp, *nmp; 1027 struct mount *mp, *nmp;
1026 struct statvfs *sb; 1028 struct statvfs *sb;
1027 size_t count, maxcount; 1029 size_t count, maxcount;
1028 int error = 0; 1030 int error = 0;
1029 1031
1030 sb = STATVFSBUF_GET(); 1032 sb = STATVFSBUF_GET();
1031 maxcount = bufsize / entry_sz; 1033 maxcount = bufsize / entry_sz;
1032 mutex_enter(&mountlist_lock); 1034 mutex_enter(&mountlist_lock);
1033 count = 0; 1035 count = 0;
1034 for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist; 1036 for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
1035 mp = nmp) { 1037 mp = nmp) {
1036 if (vfs_busy(mp, &nmp)) { 1038 if (vfs_busy(mp, &nmp)) {
1037 continue; 1039 continue;
1038 } 1040 }
1039 if (sfsp && count < maxcount) { 1041 if (sfsp && count < maxcount) {
1040 error = dostatvfs(mp, sb, l, flags, 0); 1042 error = dostatvfs(mp, sb, l, flags, 0);
1041 if (error) { 1043 if (error) {
1042 vfs_unbusy(mp, false, &nmp); 1044 vfs_unbusy(mp, false, &nmp);
1043 error = 0; 1045 error = 0;
1044 continue; 1046 continue;
1045 } 1047 }
1046 error = copyfn(sb, sfsp, entry_sz); 1048 error = copyfn(sb, sfsp, entry_sz);
1047 if (error) { 1049 if (error) {
1048 vfs_unbusy(mp, false, NULL); 1050 vfs_unbusy(mp, false, NULL);
1049 goto out; 1051 goto out;
1050 } 1052 }
1051 sfsp = (char *)sfsp + entry_sz; 1053 sfsp = (char *)sfsp + entry_sz;
1052 root |= strcmp(sb->f_mntonname, "/") == 0; 1054 root |= strcmp(sb->f_mntonname, "/") == 0;
1053 } 1055 }
1054 count++; 1056 count++;
1055 vfs_unbusy(mp, false, &nmp); 1057 vfs_unbusy(mp, false, &nmp);
1056 } 1058 }
1057 mutex_exit(&mountlist_lock); 1059 mutex_exit(&mountlist_lock);
1058 1060
1059 if (root == 0 && p->p_cwdi->cwdi_rdir) { 1061 if (root == 0 && p->p_cwdi->cwdi_rdir) {
1060 /* 1062 /*
1061 * fake a root entry 1063 * fake a root entry
1062 */ 1064 */
1063 error = dostatvfs(p->p_cwdi->cwdi_rdir->v_mount, 1065 error = dostatvfs(p->p_cwdi->cwdi_rdir->v_mount,
1064 sb, l, flags, 1); 1066 sb, l, flags, 1);
1065 if (error != 0) 1067 if (error != 0)
1066 goto out; 1068 goto out;
1067 if (sfsp) { 1069 if (sfsp) {
1068 error = copyfn(sb, sfsp, entry_sz); 1070 error = copyfn(sb, sfsp, entry_sz);
1069 if (error != 0) 1071 if (error != 0)
1070 goto out; 1072 goto out;
1071 } 1073 }
1072 count++; 1074 count++;
1073 } 1075 }
1074 if (sfsp && count > maxcount) 1076 if (sfsp && count > maxcount)
1075 *retval = maxcount; 1077 *retval = maxcount;
1076 else 1078 else
1077 *retval = count; 1079 *retval = count;
1078out: 1080out:
1079 STATVFSBUF_PUT(sb); 1081 STATVFSBUF_PUT(sb);
1080 return error; 1082 return error;
1081} 1083}
1082 1084
1083int 1085int
1084sys_getvfsstat(struct lwp *l, const struct sys_getvfsstat_args *uap, register_t *retval) 1086sys_getvfsstat(struct lwp *l, const struct sys_getvfsstat_args *uap, register_t *retval)
1085{ 1087{
1086 /* { 1088 /* {
1087 syscallarg(struct statvfs *) buf; 1089 syscallarg(struct statvfs *) buf;
1088 syscallarg(size_t) bufsize; 1090 syscallarg(size_t) bufsize;
1089 syscallarg(int) flags; 1091 syscallarg(int) flags;
1090 } */ 1092 } */
1091 1093
1092 return do_sys_getvfsstat(l, SCARG(uap, buf), SCARG(uap, bufsize), 1094 return do_sys_getvfsstat(l, SCARG(uap, buf), SCARG(uap, bufsize),
1093 SCARG(uap, flags), copyout, sizeof (struct statvfs), retval); 1095 SCARG(uap, flags), copyout, sizeof (struct statvfs), retval);
1094} 1096}
1095 1097
1096/* 1098/*
1097 * Change current working directory to a given file descriptor. 1099 * Change current working directory to a given file descriptor.
1098 */ 1100 */
1099/* ARGSUSED */ 1101/* ARGSUSED */
1100int 1102int
1101sys_fchdir(struct lwp *l, const struct sys_fchdir_args *uap, register_t *retval) 1103sys_fchdir(struct lwp *l, const struct sys_fchdir_args *uap, register_t *retval)
1102{ 1104{
1103 /* { 1105 /* {
1104 syscallarg(int) fd; 1106 syscallarg(int) fd;
1105 } */ 1107 } */
1106 struct proc *p = l->l_proc; 1108 struct proc *p = l->l_proc;
1107 struct cwdinfo *cwdi; 1109 struct cwdinfo *cwdi;
1108 struct vnode *vp, *tdp; 1110 struct vnode *vp, *tdp;
1109 struct mount *mp; 1111 struct mount *mp;
1110 file_t *fp; 1112 file_t *fp;
1111 int error, fd; 1113 int error, fd;
1112 1114
1113 /* fd_getvnode() will use the descriptor for us */ 1115 /* fd_getvnode() will use the descriptor for us */
1114 fd = SCARG(uap, fd); 1116 fd = SCARG(uap, fd);
1115 if ((error = fd_getvnode(fd, &fp)) != 0) 1117 if ((error = fd_getvnode(fd, &fp)) != 0)
1116 return (error); 1118 return (error);
1117 vp = fp->f_data; 1119 vp = fp->f_data;
1118 1120
1119 VREF(vp); 1121 VREF(vp);
1120 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 1122 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1121 if (vp->v_type != VDIR) 1123 if (vp->v_type != VDIR)
1122 error = ENOTDIR; 1124 error = ENOTDIR;
1123 else 1125 else
1124 error = VOP_ACCESS(vp, VEXEC, l->l_cred); 1126 error = VOP_ACCESS(vp, VEXEC, l->l_cred);
1125 if (error) { 1127 if (error) {
1126 vput(vp); 1128 vput(vp);
1127 goto out; 1129 goto out;
1128 } 1130 }
1129 while ((mp = vp->v_mountedhere) != NULL) { 1131 while ((mp = vp->v_mountedhere) != NULL) {
1130 error = vfs_busy(mp, NULL); 1132 error = vfs_busy(mp, NULL);
1131 vput(vp); 1133 vput(vp);
1132 if (error != 0) 1134 if (error != 0)
1133 goto out; 1135 goto out;
1134 error = VFS_ROOT(mp, &tdp); 1136 error = VFS_ROOT(mp, &tdp);
1135 vfs_unbusy(mp, false, NULL); 1137 vfs_unbusy(mp, false, NULL);
1136 if (error) 1138 if (error)
1137 goto out; 1139 goto out;
1138 vp = tdp; 1140 vp = tdp;
1139 } 1141 }
1140 VOP_UNLOCK(vp, 0); 1142 VOP_UNLOCK(vp, 0);
1141 1143
1142 /* 1144 /*
1143 * Disallow changing to a directory not under the process's 1145 * Disallow changing to a directory not under the process's
1144 * current root directory (if there is one). 1146 * current root directory (if there is one).
1145 */ 1147 */
1146 cwdi = p->p_cwdi; 1148 cwdi = p->p_cwdi;
1147 rw_enter(&cwdi->cwdi_lock, RW_WRITER); 1149 rw_enter(&cwdi->cwdi_lock, RW_WRITER);
1148 if (cwdi->cwdi_rdir && !vn_isunder(vp, NULL, l)) { 1150 if (cwdi->cwdi_rdir && !vn_isunder(vp, NULL, l)) {
1149 vrele(vp); 1151 vrele(vp);
1150 error = EPERM; /* operation not permitted */ 1152 error = EPERM; /* operation not permitted */
1151 } else { 1153 } else {
1152 vrele(cwdi->cwdi_cdir); 1154 vrele(cwdi->cwdi_cdir);
1153 cwdi->cwdi_cdir = vp; 1155 cwdi->cwdi_cdir = vp;
1154 } 1156 }
1155 rw_exit(&cwdi->cwdi_lock); 1157 rw_exit(&cwdi->cwdi_lock);
1156 1158
1157 out: 1159 out:
1158 fd_putfile(fd); 1160 fd_putfile(fd);
1159 return (error); 1161 return (error);
1160} 1162}
1161 1163
1162/* 1164/*
1163 * Change this process's notion of the root directory to a given file 1165 * Change this process's notion of the root directory to a given file
1164 * descriptor. 1166 * descriptor.
1165 */ 1167 */
1166int 1168int
1167sys_fchroot(struct lwp *l, const struct sys_fchroot_args *uap, register_t *retval) 1169sys_fchroot(struct lwp *l, const struct sys_fchroot_args *uap, register_t *retval)
1168{ 1170{
1169 struct proc *p = l->l_proc; 1171 struct proc *p = l->l_proc;
1170 struct cwdinfo *cwdi; 1172 struct cwdinfo *cwdi;
1171 struct vnode *vp; 1173 struct vnode *vp;
1172 file_t *fp; 1174 file_t *fp;
1173 int error, fd = SCARG(uap, fd); 1175 int error, fd = SCARG(uap, fd);
1174 1176
1175 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT, 1177 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT,