Print this page
10083 smatch fixes for common/fs/vfs.c
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/vfs.c
+++ new/usr/src/uts/common/fs/vfs.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
24 - * Copyright 2016 Joyent, Inc.
24 + * Copyright (c) 2018, Joyent, Inc.
25 25 * Copyright 2016 Toomas Soome <tsoome@me.com>
26 26 * Copyright (c) 2016, 2017 by Delphix. All rights reserved.
27 27 * Copyright 2016 Nexenta Systems, Inc.
28 28 * Copyright 2017 RackTop Systems.
29 29 */
30 30
31 31 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
32 32 /* All Rights Reserved */
33 33
34 34 /*
35 35 * University Copyright- Copyright (c) 1982, 1986, 1988
36 36 * The Regents of the University of California
37 37 * All Rights Reserved
38 38 *
39 39 * University Acknowledgment- Portions of this document are derived from
40 40 * software developed by the University of California, Berkeley, and its
41 41 * contributors.
42 42 */
43 43
44 44 #include <sys/types.h>
45 45 #include <sys/t_lock.h>
46 46 #include <sys/param.h>
47 47 #include <sys/errno.h>
48 48 #include <sys/user.h>
49 49 #include <sys/fstyp.h>
50 50 #include <sys/kmem.h>
51 51 #include <sys/systm.h>
52 52 #include <sys/proc.h>
53 53 #include <sys/mount.h>
54 54 #include <sys/vfs.h>
55 55 #include <sys/vfs_opreg.h>
56 56 #include <sys/fem.h>
57 57 #include <sys/mntent.h>
58 58 #include <sys/stat.h>
59 59 #include <sys/statvfs.h>
60 60 #include <sys/statfs.h>
61 61 #include <sys/cred.h>
62 62 #include <sys/vnode.h>
63 63 #include <sys/rwstlock.h>
64 64 #include <sys/dnlc.h>
65 65 #include <sys/file.h>
66 66 #include <sys/time.h>
67 67 #include <sys/atomic.h>
68 68 #include <sys/cmn_err.h>
69 69 #include <sys/buf.h>
70 70 #include <sys/swap.h>
71 71 #include <sys/debug.h>
72 72 #include <sys/vnode.h>
73 73 #include <sys/modctl.h>
74 74 #include <sys/ddi.h>
75 75 #include <sys/pathname.h>
76 76 #include <sys/bootconf.h>
77 77 #include <sys/dumphdr.h>
78 78 #include <sys/dc_ki.h>
79 79 #include <sys/poll.h>
80 80 #include <sys/sunddi.h>
81 81 #include <sys/sysmacros.h>
82 82 #include <sys/zone.h>
83 83 #include <sys/policy.h>
84 84 #include <sys/ctfs.h>
85 85 #include <sys/objfs.h>
86 86 #include <sys/console.h>
87 87 #include <sys/reboot.h>
88 88 #include <sys/attr.h>
89 89 #include <sys/zio.h>
90 90 #include <sys/spa.h>
91 91 #include <sys/lofi.h>
92 92 #include <sys/bootprops.h>
93 93
94 94 #include <vm/page.h>
95 95
96 96 #include <fs/fs_subr.h>
97 97 /* Private interfaces to create vopstats-related data structures */
98 98 extern void initialize_vopstats(vopstats_t *);
99 99 extern vopstats_t *get_fstype_vopstats(struct vfs *, struct vfssw *);
100 100 extern vsk_anchor_t *get_vskstat_anchor(struct vfs *);
101 101
102 102 static void vfs_clearmntopt_nolock(mntopts_t *, const char *, int);
103 103 static void vfs_setmntopt_nolock(mntopts_t *, const char *,
104 104 const char *, int, int);
105 105 static int vfs_optionisset_nolock(const mntopts_t *, const char *, char **);
106 106 static void vfs_freemnttab(struct vfs *);
107 107 static void vfs_freeopt(mntopt_t *);
108 108 static void vfs_swapopttbl_nolock(mntopts_t *, mntopts_t *);
109 109 static void vfs_swapopttbl(mntopts_t *, mntopts_t *);
110 110 static void vfs_copyopttbl_extend(const mntopts_t *, mntopts_t *, int);
111 111 static void vfs_createopttbl_extend(mntopts_t *, const char *,
112 112 const mntopts_t *);
113 113 static char **vfs_copycancelopt_extend(char **const, int);
114 114 static void vfs_freecancelopt(char **);
115 115 static void getrootfs(char **, char **);
116 116 static int getmacpath(dev_info_t *, void *);
117 117 static void vfs_mnttabvp_setup(void);
118 118
119 119 struct ipmnt {
120 120 struct ipmnt *mip_next;
121 121 dev_t mip_dev;
122 122 struct vfs *mip_vfsp;
123 123 };
124 124
125 125 static kmutex_t vfs_miplist_mutex;
126 126 static struct ipmnt *vfs_miplist = NULL;
127 127 static struct ipmnt *vfs_miplist_end = NULL;
128 128
129 129 static kmem_cache_t *vfs_cache; /* Pointer to VFS kmem cache */
130 130
131 131 /*
132 132 * VFS global data.
133 133 */
134 134 vnode_t *rootdir; /* pointer to root inode vnode. */
135 135 vnode_t *devicesdir; /* pointer to inode of devices root */
136 136 vnode_t *devdir; /* pointer to inode of dev root */
137 137
138 138 char *server_rootpath; /* root path for diskless clients */
139 139 char *server_hostname; /* hostname of diskless server */
140 140
141 141 static struct vfs root;
142 142 static struct vfs devices;
143 143 static struct vfs dev;
144 144 struct vfs *rootvfs = &root; /* pointer to root vfs; head of VFS list. */
145 145 rvfs_t *rvfs_list; /* array of vfs ptrs for vfs hash list */
146 146 int vfshsz = 512; /* # of heads/locks in vfs hash arrays */
147 147 /* must be power of 2! */
148 148 timespec_t vfs_mnttab_ctime; /* mnttab created time */
149 149 timespec_t vfs_mnttab_mtime; /* mnttab last modified time */
150 150 char *vfs_dummyfstype = "\0";
151 151 struct pollhead vfs_pollhd; /* for mnttab pollers */
152 152 struct vnode *vfs_mntdummyvp; /* to fake mnttab read/write for file events */
153 153 int mntfstype; /* will be set once mnt fs is mounted */
154 154
155 155 /*
156 156 * Table for generic options recognized in the VFS layer and acted
157 157 * on at this level before parsing file system specific options.
158 158 * The nosuid option is stronger than any of the devices and setuid
159 159 * options, so those are canceled when nosuid is seen.
160 160 *
161 161 * All options which are added here need to be added to the
162 162 * list of standard options in usr/src/cmd/fs.d/fslib.c as well.
163 163 */
164 164 /*
165 165 * VFS Mount options table
166 166 */
167 167 static char *ro_cancel[] = { MNTOPT_RW, NULL };
168 168 static char *rw_cancel[] = { MNTOPT_RO, NULL };
169 169 static char *suid_cancel[] = { MNTOPT_NOSUID, NULL };
170 170 static char *nosuid_cancel[] = { MNTOPT_SUID, MNTOPT_DEVICES, MNTOPT_NODEVICES,
171 171 MNTOPT_NOSETUID, MNTOPT_SETUID, NULL };
172 172 static char *devices_cancel[] = { MNTOPT_NODEVICES, NULL };
173 173 static char *nodevices_cancel[] = { MNTOPT_DEVICES, NULL };
174 174 static char *setuid_cancel[] = { MNTOPT_NOSETUID, NULL };
175 175 static char *nosetuid_cancel[] = { MNTOPT_SETUID, NULL };
176 176 static char *nbmand_cancel[] = { MNTOPT_NONBMAND, NULL };
177 177 static char *nonbmand_cancel[] = { MNTOPT_NBMAND, NULL };
178 178 static char *exec_cancel[] = { MNTOPT_NOEXEC, NULL };
179 179 static char *noexec_cancel[] = { MNTOPT_EXEC, NULL };
180 180
181 181 static const mntopt_t mntopts[] = {
182 182 /*
183 183 * option name cancel options default arg flags
184 184 */
185 185 { MNTOPT_REMOUNT, NULL, NULL,
186 186 MO_NODISPLAY, (void *)0 },
187 187 { MNTOPT_RO, ro_cancel, NULL, 0,
188 188 (void *)0 },
189 189 { MNTOPT_RW, rw_cancel, NULL, 0,
190 190 (void *)0 },
191 191 { MNTOPT_SUID, suid_cancel, NULL, 0,
192 192 (void *)0 },
193 193 { MNTOPT_NOSUID, nosuid_cancel, NULL, 0,
194 194 (void *)0 },
195 195 { MNTOPT_DEVICES, devices_cancel, NULL, 0,
196 196 (void *)0 },
197 197 { MNTOPT_NODEVICES, nodevices_cancel, NULL, 0,
198 198 (void *)0 },
199 199 { MNTOPT_SETUID, setuid_cancel, NULL, 0,
200 200 (void *)0 },
201 201 { MNTOPT_NOSETUID, nosetuid_cancel, NULL, 0,
202 202 (void *)0 },
203 203 { MNTOPT_NBMAND, nbmand_cancel, NULL, 0,
204 204 (void *)0 },
205 205 { MNTOPT_NONBMAND, nonbmand_cancel, NULL, 0,
206 206 (void *)0 },
207 207 { MNTOPT_EXEC, exec_cancel, NULL, 0,
208 208 (void *)0 },
209 209 { MNTOPT_NOEXEC, noexec_cancel, NULL, 0,
210 210 (void *)0 },
211 211 };
212 212
213 213 const mntopts_t vfs_mntopts = {
214 214 sizeof (mntopts) / sizeof (mntopt_t),
215 215 (mntopt_t *)&mntopts[0]
216 216 };
217 217
218 218 /*
219 219 * File system operation dispatch functions.
220 220 */
221 221
222 222 int
223 223 fsop_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
224 224 {
225 225 return (*(vfsp)->vfs_op->vfs_mount)(vfsp, mvp, uap, cr);
226 226 }
227 227
228 228 int
229 229 fsop_unmount(vfs_t *vfsp, int flag, cred_t *cr)
230 230 {
231 231 return (*(vfsp)->vfs_op->vfs_unmount)(vfsp, flag, cr);
232 232 }
233 233
234 234 int
235 235 fsop_root(vfs_t *vfsp, vnode_t **vpp)
236 236 {
237 237 refstr_t *mntpt;
238 238 int ret = (*(vfsp)->vfs_op->vfs_root)(vfsp, vpp);
239 239 /*
240 240 * Make sure this root has a path. With lofs, it is possible to have
241 241 * a NULL mountpoint.
242 242 */
243 243 if (ret == 0 && vfsp->vfs_mntpt != NULL &&
244 244 (*vpp)->v_path == vn_vpath_empty) {
245 245 const char *path;
246 246
247 247 mntpt = vfs_getmntpoint(vfsp);
248 248 path = refstr_value(mntpt);
249 249 vn_setpath_str(*vpp, path, strlen(path));
250 250 refstr_rele(mntpt);
251 251 }
252 252
253 253 return (ret);
254 254 }
255 255
256 256 int
257 257 fsop_statfs(vfs_t *vfsp, statvfs64_t *sp)
258 258 {
259 259 return (*(vfsp)->vfs_op->vfs_statvfs)(vfsp, sp);
260 260 }
261 261
262 262 int
263 263 fsop_sync(vfs_t *vfsp, short flag, cred_t *cr)
264 264 {
265 265 return (*(vfsp)->vfs_op->vfs_sync)(vfsp, flag, cr);
266 266 }
267 267
268 268 int
269 269 fsop_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp)
270 270 {
271 271 /*
272 272 * In order to handle system attribute fids in a manner
273 273 * transparent to the underlying fs, we embed the fid for
274 274 * the sysattr parent object in the sysattr fid and tack on
275 275 * some extra bytes that only the sysattr layer knows about.
276 276 *
277 277 * This guarantees that sysattr fids are larger than other fids
278 278 * for this vfs. If the vfs supports the sysattr view interface
279 279 * (as indicated by VFSFT_SYSATTR_VIEWS), we cannot have a size
280 280 * collision with XATTR_FIDSZ.
281 281 */
282 282 if (vfs_has_feature(vfsp, VFSFT_SYSATTR_VIEWS) &&
283 283 fidp->fid_len == XATTR_FIDSZ)
284 284 return (xattr_dir_vget(vfsp, vpp, fidp));
285 285
286 286 return (*(vfsp)->vfs_op->vfs_vget)(vfsp, vpp, fidp);
287 287 }
288 288
289 289 int
290 290 fsop_mountroot(vfs_t *vfsp, enum whymountroot reason)
291 291 {
292 292 return (*(vfsp)->vfs_op->vfs_mountroot)(vfsp, reason);
293 293 }
294 294
295 295 void
296 296 fsop_freefs(vfs_t *vfsp)
297 297 {
298 298 (*(vfsp)->vfs_op->vfs_freevfs)(vfsp);
299 299 }
300 300
301 301 int
302 302 fsop_vnstate(vfs_t *vfsp, vnode_t *vp, vntrans_t nstate)
303 303 {
304 304 return ((*(vfsp)->vfs_op->vfs_vnstate)(vfsp, vp, nstate));
305 305 }
306 306
307 307 int
308 308 fsop_sync_by_kind(int fstype, short flag, cred_t *cr)
309 309 {
310 310 ASSERT((fstype >= 0) && (fstype < nfstype));
311 311
312 312 if (ALLOCATED_VFSSW(&vfssw[fstype]) && VFS_INSTALLED(&vfssw[fstype]))
313 313 return (*vfssw[fstype].vsw_vfsops.vfs_sync) (NULL, flag, cr);
314 314 else
315 315 return (ENOTSUP);
316 316 }
317 317
318 318 /*
319 319 * File system initialization. vfs_setfsops() must be called from a file
320 320 * system's init routine.
321 321 */
322 322
323 323 static int
324 324 fs_copyfsops(const fs_operation_def_t *template, vfsops_t *actual,
325 325 int *unused_ops)
326 326 {
327 327 static const fs_operation_trans_def_t vfs_ops_table[] = {
328 328 VFSNAME_MOUNT, offsetof(vfsops_t, vfs_mount),
329 329 fs_nosys, fs_nosys,
330 330
331 331 VFSNAME_UNMOUNT, offsetof(vfsops_t, vfs_unmount),
332 332 fs_nosys, fs_nosys,
333 333
334 334 VFSNAME_ROOT, offsetof(vfsops_t, vfs_root),
335 335 fs_nosys, fs_nosys,
336 336
337 337 VFSNAME_STATVFS, offsetof(vfsops_t, vfs_statvfs),
338 338 fs_nosys, fs_nosys,
339 339
340 340 VFSNAME_SYNC, offsetof(vfsops_t, vfs_sync),
341 341 (fs_generic_func_p) fs_sync,
342 342 (fs_generic_func_p) fs_sync, /* No errors allowed */
343 343
344 344 VFSNAME_VGET, offsetof(vfsops_t, vfs_vget),
345 345 fs_nosys, fs_nosys,
346 346
347 347 VFSNAME_MOUNTROOT, offsetof(vfsops_t, vfs_mountroot),
348 348 fs_nosys, fs_nosys,
349 349
350 350 VFSNAME_FREEVFS, offsetof(vfsops_t, vfs_freevfs),
351 351 (fs_generic_func_p)fs_freevfs,
352 352 (fs_generic_func_p)fs_freevfs, /* Shouldn't fail */
353 353
354 354 VFSNAME_VNSTATE, offsetof(vfsops_t, vfs_vnstate),
355 355 (fs_generic_func_p)fs_nosys,
356 356 (fs_generic_func_p)fs_nosys,
357 357
358 358 NULL, 0, NULL, NULL
359 359 };
360 360
361 361 return (fs_build_vector(actual, unused_ops, vfs_ops_table, template));
362 362 }
363 363
364 364 void
365 365 zfs_boot_init(void)
366 366 {
367 367 if (strcmp(rootfs.bo_fstype, MNTTYPE_ZFS) == 0)
368 368 spa_boot_init();
369 369 }
370 370
371 371 int
372 372 vfs_setfsops(int fstype, const fs_operation_def_t *template, vfsops_t **actual)
373 373 {
374 374 int error;
375 375 int unused_ops;
376 376
377 377 /*
378 378 * Verify that fstype refers to a valid fs. Note that
379 379 * 0 is valid since it's used to set "stray" ops.
380 380 */
381 381 if ((fstype < 0) || (fstype >= nfstype))
382 382 return (EINVAL);
383 383
384 384 if (!ALLOCATED_VFSSW(&vfssw[fstype]))
385 385 return (EINVAL);
386 386
387 387 /* Set up the operations vector. */
388 388
389 389 error = fs_copyfsops(template, &vfssw[fstype].vsw_vfsops, &unused_ops);
390 390
391 391 if (error != 0)
392 392 return (error);
393 393
394 394 vfssw[fstype].vsw_flag |= VSW_INSTALLED;
395 395
396 396 if (actual != NULL)
397 397 *actual = &vfssw[fstype].vsw_vfsops;
398 398
399 399 #if DEBUG
400 400 if (unused_ops != 0)
401 401 cmn_err(CE_WARN, "vfs_setfsops: %s: %d operations supplied "
402 402 "but not used", vfssw[fstype].vsw_name, unused_ops);
403 403 #endif
404 404
405 405 return (0);
406 406 }
407 407
408 408 int
409 409 vfs_makefsops(const fs_operation_def_t *template, vfsops_t **actual)
410 410 {
411 411 int error;
412 412 int unused_ops;
413 413
414 414 *actual = (vfsops_t *)kmem_alloc(sizeof (vfsops_t), KM_SLEEP);
415 415
416 416 error = fs_copyfsops(template, *actual, &unused_ops);
417 417 if (error != 0) {
418 418 kmem_free(*actual, sizeof (vfsops_t));
419 419 *actual = NULL;
420 420 return (error);
421 421 }
422 422
423 423 return (0);
424 424 }
425 425
426 426 /*
427 427 * Free a vfsops structure created as a result of vfs_makefsops().
428 428 * NOTE: For a vfsops structure initialized by vfs_setfsops(), use
429 429 * vfs_freevfsops_by_type().
430 430 */
431 431 void
432 432 vfs_freevfsops(vfsops_t *vfsops)
433 433 {
434 434 kmem_free(vfsops, sizeof (vfsops_t));
435 435 }
436 436
437 437 /*
438 438 * Since the vfsops structure is part of the vfssw table and wasn't
439 439 * really allocated, we're not really freeing anything. We keep
440 440 * the name for consistency with vfs_freevfsops(). We do, however,
441 441 * need to take care of a little bookkeeping.
442 442 * NOTE: For a vfsops structure created by vfs_setfsops(), use
443 443 * vfs_freevfsops_by_type().
444 444 */
445 445 int
446 446 vfs_freevfsops_by_type(int fstype)
447 447 {
448 448
449 449 /* Verify that fstype refers to a loaded fs (and not fsid 0). */
450 450 if ((fstype <= 0) || (fstype >= nfstype))
451 451 return (EINVAL);
452 452
453 453 WLOCK_VFSSW();
454 454 if ((vfssw[fstype].vsw_flag & VSW_INSTALLED) == 0) {
455 455 WUNLOCK_VFSSW();
456 456 return (EINVAL);
457 457 }
458 458
459 459 vfssw[fstype].vsw_flag &= ~VSW_INSTALLED;
460 460 WUNLOCK_VFSSW();
461 461
462 462 return (0);
463 463 }
464 464
465 465 /* Support routines used to reference vfs_op */
466 466
467 467 /* Set the operations vector for a vfs */
468 468 void
469 469 vfs_setops(vfs_t *vfsp, vfsops_t *vfsops)
470 470 {
471 471 vfsops_t *op;
472 472
473 473 ASSERT(vfsp != NULL);
474 474 ASSERT(vfsops != NULL);
475 475
476 476 op = vfsp->vfs_op;
477 477 membar_consumer();
478 478 if (vfsp->vfs_femhead == NULL &&
479 479 atomic_cas_ptr(&vfsp->vfs_op, op, vfsops) == op) {
480 480 return;
481 481 }
482 482 fsem_setvfsops(vfsp, vfsops);
483 483 }
484 484
485 485 /* Retrieve the operations vector for a vfs */
486 486 vfsops_t *
487 487 vfs_getops(vfs_t *vfsp)
488 488 {
489 489 vfsops_t *op;
490 490
491 491 ASSERT(vfsp != NULL);
492 492
493 493 op = vfsp->vfs_op;
494 494 membar_consumer();
495 495 if (vfsp->vfs_femhead == NULL && op == vfsp->vfs_op) {
496 496 return (op);
497 497 } else {
498 498 return (fsem_getvfsops(vfsp));
499 499 }
500 500 }
501 501
502 502 /*
503 503 * Returns non-zero (1) if the vfsops matches that of the vfs.
504 504 * Returns zero (0) if not.
505 505 */
506 506 int
507 507 vfs_matchops(vfs_t *vfsp, vfsops_t *vfsops)
508 508 {
509 509 return (vfs_getops(vfsp) == vfsops);
510 510 }
511 511
512 512 /*
513 513 * Returns non-zero (1) if the file system has installed a non-default,
514 514 * non-error vfs_sync routine. Returns zero (0) otherwise.
515 515 */
516 516 int
517 517 vfs_can_sync(vfs_t *vfsp)
518 518 {
519 519 /* vfs_sync() routine is not the default/error function */
520 520 return (vfs_getops(vfsp)->vfs_sync != fs_sync);
521 521 }
522 522
523 523 /*
524 524 * Initialize a vfs structure.
525 525 */
526 526 void
527 527 vfs_init(vfs_t *vfsp, vfsops_t *op, void *data)
528 528 {
529 529 /* Other initialization has been moved to vfs_alloc() */
530 530 vfsp->vfs_count = 0;
531 531 vfsp->vfs_next = vfsp;
532 532 vfsp->vfs_prev = vfsp;
533 533 vfsp->vfs_zone_next = vfsp;
534 534 vfsp->vfs_zone_prev = vfsp;
535 535 vfsp->vfs_lofi_id = 0;
536 536 sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL);
537 537 vfsimpl_setup(vfsp);
538 538 vfsp->vfs_data = (data);
539 539 vfs_setops((vfsp), (op));
540 540 }
541 541
542 542 /*
543 543 * Allocate and initialize the vfs implementation private data
544 544 * structure, vfs_impl_t.
545 545 */
546 546 void
547 547 vfsimpl_setup(vfs_t *vfsp)
548 548 {
549 549 int i;
550 550
551 551 if (vfsp->vfs_implp != NULL) {
552 552 return;
553 553 }
554 554
555 555 vfsp->vfs_implp = kmem_alloc(sizeof (vfs_impl_t), KM_SLEEP);
556 556 /* Note that these are #define'd in vfs.h */
557 557 vfsp->vfs_vskap = NULL;
558 558 vfsp->vfs_fstypevsp = NULL;
559 559
560 560 /* Set size of counted array, then zero the array */
561 561 vfsp->vfs_featureset[0] = VFS_FEATURE_MAXSZ - 1;
562 562 for (i = 1; i < VFS_FEATURE_MAXSZ; i++) {
563 563 vfsp->vfs_featureset[i] = 0;
564 564 }
565 565 }
566 566
567 567 /*
568 568 * Release the vfs_impl_t structure, if it exists. Some unbundled
569 569 * filesystems may not use the newer version of vfs and thus
570 570 * would not contain this implementation private data structure.
571 571 */
572 572 void
573 573 vfsimpl_teardown(vfs_t *vfsp)
574 574 {
575 575 vfs_impl_t *vip = vfsp->vfs_implp;
576 576
577 577 if (vip == NULL)
578 578 return;
579 579
580 580 kmem_free(vfsp->vfs_implp, sizeof (vfs_impl_t));
581 581 vfsp->vfs_implp = NULL;
582 582 }
583 583
584 584 /*
585 585 * VFS system calls: mount, umount, syssync, statfs, fstatfs, statvfs,
586 586 * fstatvfs, and sysfs moved to common/syscall.
587 587 */
588 588
589 589 /*
590 590 * Update every mounted file system. We call the vfs_sync operation of
591 591 * each file system type, passing it a NULL vfsp to indicate that all
592 592 * mounted file systems of that type should be updated.
593 593 */
594 594 void
595 595 vfs_sync(int flag)
596 596 {
597 597 struct vfssw *vswp;
598 598 RLOCK_VFSSW();
599 599 for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
600 600 if (ALLOCATED_VFSSW(vswp) && VFS_INSTALLED(vswp)) {
601 601 vfs_refvfssw(vswp);
602 602 RUNLOCK_VFSSW();
603 603 (void) (*vswp->vsw_vfsops.vfs_sync)(NULL, flag,
604 604 CRED());
605 605 vfs_unrefvfssw(vswp);
606 606 RLOCK_VFSSW();
607 607 }
608 608 }
609 609 RUNLOCK_VFSSW();
610 610 }
611 611
612 612 void
613 613 sync(void)
614 614 {
615 615 vfs_sync(0);
616 616 }
617 617
618 618 /*
619 619 * External routines.
620 620 */
621 621
622 622 krwlock_t vfssw_lock; /* lock accesses to vfssw */
623 623
624 624 /*
625 625 * Lock for accessing the vfs linked list. Initialized in vfs_mountroot(),
626 626 * but otherwise should be accessed only via vfs_list_lock() and
627 627 * vfs_list_unlock(). Also used to protect the timestamp for mods to the list.
628 628 */
629 629 static krwlock_t vfslist;
630 630
631 631 /*
632 632 * Mount devfs on /devices. This is done right after root is mounted
633 633 * to provide device access support for the system
634 634 */
635 635 static void
636 636 vfs_mountdevices(void)
637 637 {
638 638 struct vfssw *vsw;
639 639 struct vnode *mvp;
640 640 struct mounta mounta = { /* fake mounta for devfs_mount() */
641 641 NULL,
642 642 NULL,
643 643 MS_SYSSPACE,
644 644 NULL,
645 645 NULL,
646 646 0,
647 647 NULL,
648 648 0
649 649 };
650 650
651 651 /*
652 652 * _init devfs module to fill in the vfssw
653 653 */
654 654 if (modload("fs", "devfs") == -1)
655 655 panic("Cannot _init devfs module");
656 656
657 657 /*
658 658 * Hold vfs
659 659 */
660 660 RLOCK_VFSSW();
661 661 vsw = vfs_getvfsswbyname("devfs");
662 662 VFS_INIT(&devices, &vsw->vsw_vfsops, NULL);
663 663 VFS_HOLD(&devices);
664 664
665 665 /*
666 666 * Locate mount point
667 667 */
668 668 if (lookupname("/devices", UIO_SYSSPACE, FOLLOW, NULLVPP, &mvp))
669 669 panic("Cannot find /devices");
670 670
671 671 /*
672 672 * Perform the mount of /devices
673 673 */
674 674 if (VFS_MOUNT(&devices, mvp, &mounta, CRED()))
675 675 panic("Cannot mount /devices");
676 676
677 677 RUNLOCK_VFSSW();
678 678
679 679 /*
680 680 * Set appropriate members and add to vfs list for mnttab display
681 681 */
682 682 vfs_setresource(&devices, "/devices", 0);
683 683 vfs_setmntpoint(&devices, "/devices", 0);
684 684
685 685 /*
686 686 * Hold the root of /devices so it won't go away
687 687 */
688 688 if (VFS_ROOT(&devices, &devicesdir))
689 689 panic("vfs_mountdevices: not devices root");
690 690
691 691 if (vfs_lock(&devices) != 0) {
692 692 VN_RELE(devicesdir);
693 693 cmn_err(CE_NOTE, "Cannot acquire vfs_lock of /devices");
694 694 return;
695 695 }
696 696
697 697 if (vn_vfswlock(mvp) != 0) {
698 698 vfs_unlock(&devices);
699 699 VN_RELE(devicesdir);
700 700 cmn_err(CE_NOTE, "Cannot acquire vfswlock of /devices");
701 701 return;
702 702 }
703 703
704 704 vfs_add(mvp, &devices, 0);
705 705 vn_vfsunlock(mvp);
706 706 vfs_unlock(&devices);
707 707 VN_RELE(devicesdir);
708 708 }
709 709
710 710 /*
711 711 * mount the first instance of /dev to root and remain mounted
712 712 */
713 713 static void
714 714 vfs_mountdev1(void)
715 715 {
716 716 struct vfssw *vsw;
717 717 struct vnode *mvp;
718 718 struct mounta mounta = { /* fake mounta for sdev_mount() */
719 719 NULL,
720 720 NULL,
721 721 MS_SYSSPACE | MS_OVERLAY,
722 722 NULL,
723 723 NULL,
724 724 0,
725 725 NULL,
726 726 0
727 727 };
728 728
729 729 /*
730 730 * _init dev module to fill in the vfssw
731 731 */
732 732 if (modload("fs", "dev") == -1)
733 733 cmn_err(CE_PANIC, "Cannot _init dev module\n");
734 734
735 735 /*
736 736 * Hold vfs
737 737 */
738 738 RLOCK_VFSSW();
739 739 vsw = vfs_getvfsswbyname("dev");
740 740 VFS_INIT(&dev, &vsw->vsw_vfsops, NULL);
741 741 VFS_HOLD(&dev);
742 742
743 743 /*
744 744 * Locate mount point
745 745 */
746 746 if (lookupname("/dev", UIO_SYSSPACE, FOLLOW, NULLVPP, &mvp))
747 747 cmn_err(CE_PANIC, "Cannot find /dev\n");
748 748
749 749 /*
750 750 * Perform the mount of /dev
751 751 */
752 752 if (VFS_MOUNT(&dev, mvp, &mounta, CRED()))
753 753 cmn_err(CE_PANIC, "Cannot mount /dev 1\n");
754 754
755 755 RUNLOCK_VFSSW();
756 756
757 757 /*
758 758 * Set appropriate members and add to vfs list for mnttab display
759 759 */
760 760 vfs_setresource(&dev, "/dev", 0);
761 761 vfs_setmntpoint(&dev, "/dev", 0);
762 762
763 763 /*
764 764 * Hold the root of /dev so it won't go away
765 765 */
766 766 if (VFS_ROOT(&dev, &devdir))
767 767 cmn_err(CE_PANIC, "vfs_mountdev1: not dev root");
768 768
769 769 if (vfs_lock(&dev) != 0) {
770 770 VN_RELE(devdir);
771 771 cmn_err(CE_NOTE, "Cannot acquire vfs_lock of /dev");
772 772 return;
773 773 }
774 774
775 775 if (vn_vfswlock(mvp) != 0) {
776 776 vfs_unlock(&dev);
777 777 VN_RELE(devdir);
778 778 cmn_err(CE_NOTE, "Cannot acquire vfswlock of /dev");
779 779 return;
780 780 }
781 781
782 782 vfs_add(mvp, &dev, 0);
783 783 vn_vfsunlock(mvp);
784 784 vfs_unlock(&dev);
785 785 VN_RELE(devdir);
786 786 }
787 787
788 788 /*
789 789 * Mount required filesystem. This is done right after root is mounted.
790 790 */
791 791 static void
792 792 vfs_mountfs(char *module, char *spec, char *path)
793 793 {
794 794 struct vnode *mvp;
795 795 struct mounta mounta;
796 796 vfs_t *vfsp;
797 797
798 798 bzero(&mounta, sizeof (mounta));
799 799 mounta.flags = MS_SYSSPACE | MS_DATA;
800 800 mounta.fstype = module;
801 801 mounta.spec = spec;
802 802 mounta.dir = path;
803 803 if (lookupname(path, UIO_SYSSPACE, FOLLOW, NULLVPP, &mvp)) {
804 804 cmn_err(CE_WARN, "Cannot find %s", path);
805 805 return;
806 806 }
807 807 if (domount(NULL, &mounta, mvp, CRED(), &vfsp))
808 808 cmn_err(CE_WARN, "Cannot mount %s", path);
809 809 else
810 810 VFS_RELE(vfsp);
811 811 VN_RELE(mvp);
812 812 }
813 813
814 814 /*
815 815 * vfs_mountroot is called by main() to mount the root filesystem.
816 816 */
817 817 void
818 818 vfs_mountroot(void)
819 819 {
820 820 struct vnode *rvp = NULL;
821 821 char *path;
822 822 size_t plen;
823 823 struct vfssw *vswp;
824 824 proc_t *p;
825 825
826 826 rw_init(&vfssw_lock, NULL, RW_DEFAULT, NULL);
827 827 rw_init(&vfslist, NULL, RW_DEFAULT, NULL);
828 828
829 829 /*
830 830 * Alloc the vfs hash bucket array and locks
831 831 */
832 832 rvfs_list = kmem_zalloc(vfshsz * sizeof (rvfs_t), KM_SLEEP);
833 833
834 834 /*
835 835 * Call machine-dependent routine "rootconf" to choose a root
836 836 * file system type.
837 837 */
838 838 if (rootconf())
839 839 panic("vfs_mountroot: cannot mount root");
840 840 /*
841 841 * Get vnode for '/'. Set up rootdir, u.u_rdir and u.u_cdir
842 842 * to point to it. These are used by lookuppn() so that it
843 843 * knows where to start from ('/' or '.').
844 844 */
845 845 vfs_setmntpoint(rootvfs, "/", 0);
846 846 if (VFS_ROOT(rootvfs, &rootdir))
847 847 panic("vfs_mountroot: no root vnode");
848 848
849 849 /*
850 850 * At this point, the process tree consists of p0 and possibly some
851 851 * direct children of p0. (i.e. there are no grandchildren)
852 852 *
853 853 * Walk through them all, setting their current directory.
854 854 */
855 855 mutex_enter(&pidlock);
856 856 for (p = practive; p != NULL; p = p->p_next) {
857 857 ASSERT(p == &p0 || p->p_parent == &p0);
858 858
859 859 PTOU(p)->u_cdir = rootdir;
860 860 VN_HOLD(PTOU(p)->u_cdir);
861 861 PTOU(p)->u_rdir = NULL;
862 862 }
863 863 mutex_exit(&pidlock);
864 864
865 865 /*
866 866 * Setup the global zone's rootvp, now that it exists.
867 867 */
868 868 global_zone->zone_rootvp = rootdir;
869 869 VN_HOLD(global_zone->zone_rootvp);
870 870
871 871 /*
872 872 * Notify the module code that it can begin using the
873 873 * root filesystem instead of the boot program's services.
874 874 */
875 875 modrootloaded = 1;
876 876
877 877 /*
878 878 * Special handling for a ZFS root file system.
879 879 */
880 880 zfs_boot_init();
881 881
882 882 /*
883 883 * Set up mnttab information for root
884 884 */
885 885 vfs_setresource(rootvfs, rootfs.bo_name, 0);
886 886
887 887 /*
888 888 * Notify cluster software that the root filesystem is available.
889 889 */
890 890 clboot_mountroot();
891 891
892 892 /* Now that we're all done with the root FS, set up its vopstats */
893 893 if ((vswp = vfs_getvfsswbyvfsops(vfs_getops(rootvfs))) != NULL) {
894 894 /* Set flag for statistics collection */
895 895 if (vswp->vsw_flag & VSW_STATS) {
896 896 initialize_vopstats(&rootvfs->vfs_vopstats);
897 897 rootvfs->vfs_flag |= VFS_STATS;
898 898 rootvfs->vfs_fstypevsp =
899 899 get_fstype_vopstats(rootvfs, vswp);
900 900 rootvfs->vfs_vskap = get_vskstat_anchor(rootvfs);
901 901 }
902 902 vfs_unrefvfssw(vswp);
903 903 }
904 904
905 905 /*
906 906 * Mount /devices, /dev instance 1, /system/contract, /etc/mnttab,
907 907 * /etc/svc/volatile, /etc/dfs/sharetab, /system/object, and /proc.
908 908 */
909 909 vfs_mountdevices();
910 910 vfs_mountdev1();
911 911
912 912 vfs_mountfs("ctfs", "ctfs", CTFS_ROOT);
913 913 vfs_mountfs("proc", "/proc", "/proc");
914 914 vfs_mountfs("mntfs", "/etc/mnttab", "/etc/mnttab");
915 915 vfs_mountfs("tmpfs", "/etc/svc/volatile", "/etc/svc/volatile");
916 916 vfs_mountfs("objfs", "objfs", OBJFS_ROOT);
917 917 vfs_mountfs("bootfs", "bootfs", "/system/boot");
918 918
919 919 if (getzoneid() == GLOBAL_ZONEID) {
920 920 vfs_mountfs("sharefs", "sharefs", "/etc/dfs/sharetab");
921 921 }
922 922
923 923 if (strcmp(rootfs.bo_fstype, "zfs") != 0) {
924 924 /*
925 925 * Look up the root device via devfs so that a dv_node is
926 926 * created for it. The vnode is never VN_RELE()ed.
927 927 * We allocate more than MAXPATHLEN so that the
928 928 * buffer passed to i_ddi_prompath_to_devfspath() is
929 929 * exactly MAXPATHLEN (the function expects a buffer
930 930 * of that length).
931 931 */
932 932 plen = strlen("/devices");
933 933 path = kmem_alloc(plen + MAXPATHLEN, KM_SLEEP);
934 934 (void) strcpy(path, "/devices");
935 935
936 936 if (i_ddi_prompath_to_devfspath(rootfs.bo_name, path + plen)
937 937 != DDI_SUCCESS ||
938 938 lookupname(path, UIO_SYSSPACE, FOLLOW, NULLVPP, &rvp)) {
939 939
940 940 /* NUL terminate in case "path" has garbage */
941 941 path[plen + MAXPATHLEN - 1] = '\0';
942 942 #ifdef DEBUG
943 943 cmn_err(CE_WARN, "!Cannot lookup root device: %s",
944 944 path);
945 945 #endif
946 946 }
947 947 kmem_free(path, plen + MAXPATHLEN);
948 948 }
949 949
950 950 vfs_mnttabvp_setup();
951 951 }
952 952
953 953 /*
954 954 * Check to see if our "block device" is actually a file. If so,
955 955 * automatically add a lofi device, and keep track of this fact.
956 956 */
957 957 static int
958 958 lofi_add(const char *fsname, struct vfs *vfsp,
959 959 mntopts_t *mntopts, struct mounta *uap)
960 960 {
961 961 int fromspace = (uap->flags & MS_SYSSPACE) ?
962 962 UIO_SYSSPACE : UIO_USERSPACE;
963 963 struct lofi_ioctl *li = NULL;
964 964 struct vnode *vp = NULL;
965 965 struct pathname pn = { NULL };
966 966 ldi_ident_t ldi_id;
967 967 ldi_handle_t ldi_hdl;
968 968 vfssw_t *vfssw;
969 969 int id;
970 970 int err = 0;
971 971
972 972 if ((vfssw = vfs_getvfssw(fsname)) == NULL)
973 973 return (0);
974 974
975 975 if (!(vfssw->vsw_flag & VSW_CANLOFI)) {
976 976 vfs_unrefvfssw(vfssw);
977 977 return (0);
978 978 }
979 979
980 980 vfs_unrefvfssw(vfssw);
981 981 vfssw = NULL;
982 982
983 983 if (pn_get(uap->spec, fromspace, &pn) != 0)
984 984 return (0);
985 985
986 986 if (lookupname(uap->spec, fromspace, FOLLOW, NULL, &vp) != 0)
987 987 goto out;
988 988
989 989 if (vp->v_type != VREG)
990 990 goto out;
991 991
992 992 /* OK, this is a lofi mount. */
993 993
994 994 if ((uap->flags & (MS_REMOUNT|MS_GLOBAL)) ||
995 995 vfs_optionisset_nolock(mntopts, MNTOPT_SUID, NULL) ||
996 996 vfs_optionisset_nolock(mntopts, MNTOPT_SETUID, NULL) ||
997 997 vfs_optionisset_nolock(mntopts, MNTOPT_DEVICES, NULL)) {
998 998 err = EINVAL;
999 999 goto out;
1000 1000 }
1001 1001
1002 1002 ldi_id = ldi_ident_from_anon();
1003 1003 li = kmem_zalloc(sizeof (*li), KM_SLEEP);
1004 1004 (void) strlcpy(li->li_filename, pn.pn_path, MAXPATHLEN);
1005 1005
1006 1006 err = ldi_open_by_name("/dev/lofictl", FREAD | FWRITE, kcred,
1007 1007 &ldi_hdl, ldi_id);
1008 1008
1009 1009 if (err)
1010 1010 goto out2;
1011 1011
1012 1012 err = ldi_ioctl(ldi_hdl, LOFI_MAP_FILE, (intptr_t)li,
1013 1013 FREAD | FWRITE | FKIOCTL, kcred, &id);
1014 1014
1015 1015 (void) ldi_close(ldi_hdl, FREAD | FWRITE, kcred);
1016 1016
1017 1017 if (!err)
1018 1018 vfsp->vfs_lofi_id = id;
1019 1019
1020 1020 out2:
1021 1021 ldi_ident_release(ldi_id);
1022 1022 out:
1023 1023 if (li != NULL)
1024 1024 kmem_free(li, sizeof (*li));
1025 1025 if (vp != NULL)
1026 1026 VN_RELE(vp);
1027 1027 pn_free(&pn);
1028 1028 return (err);
1029 1029 }
1030 1030
1031 1031 static void
1032 1032 lofi_remove(struct vfs *vfsp)
1033 1033 {
1034 1034 struct lofi_ioctl *li = NULL;
1035 1035 ldi_ident_t ldi_id;
1036 1036 ldi_handle_t ldi_hdl;
1037 1037 int err;
1038 1038
1039 1039 if (vfsp->vfs_lofi_id == 0)
1040 1040 return;
1041 1041
1042 1042 ldi_id = ldi_ident_from_anon();
1043 1043
1044 1044 li = kmem_zalloc(sizeof (*li), KM_SLEEP);
1045 1045 li->li_id = vfsp->vfs_lofi_id;
1046 1046 li->li_cleanup = B_TRUE;
1047 1047
1048 1048 err = ldi_open_by_name("/dev/lofictl", FREAD | FWRITE, kcred,
1049 1049 &ldi_hdl, ldi_id);
1050 1050
1051 1051 if (err)
1052 1052 goto out;
1053 1053
↓ open down ↓ |
1019 lines elided |
↑ open up ↑ |
1054 1054 err = ldi_ioctl(ldi_hdl, LOFI_UNMAP_FILE_MINOR, (intptr_t)li,
1055 1055 FREAD | FWRITE | FKIOCTL, kcred, NULL);
1056 1056
1057 1057 (void) ldi_close(ldi_hdl, FREAD | FWRITE, kcred);
1058 1058
1059 1059 if (!err)
1060 1060 vfsp->vfs_lofi_id = 0;
1061 1061
1062 1062 out:
1063 1063 ldi_ident_release(ldi_id);
1064 - if (li != NULL)
1065 - kmem_free(li, sizeof (*li));
1064 + kmem_free(li, sizeof (*li));
1066 1065 }
1067 1066
1068 1067 /*
1069 1068 * Common mount code. Called from the system call entry point, from autofs,
1070 1069 * nfsv4 trigger mounts, and from pxfs.
1071 1070 *
1072 1071 * Takes the effective file system type, mount arguments, the mount point
1073 1072 * vnode, flags specifying whether the mount is a remount and whether it
1074 1073 * should be entered into the vfs list, and credentials. Fills in its vfspp
1075 1074 * parameter with the mounted file system instance's vfs.
1076 1075 *
1077 1076 * Note that the effective file system type is specified as a string. It may
1078 1077 * be null, in which case it's determined from the mount arguments, and may
1079 1078 * differ from the type specified in the mount arguments; this is a hook to
1080 1079 * allow interposition when instantiating file system instances.
1081 1080 *
1082 1081 * The caller is responsible for releasing its own hold on the mount point
1083 1082 * vp (this routine does its own hold when necessary).
1084 1083 * Also note that for remounts, the mount point vp should be the vnode for
1085 1084 * the root of the file system rather than the vnode that the file system
1086 1085 * is mounted on top of.
1087 1086 */
1088 1087 int
1089 1088 domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp,
1090 1089 struct vfs **vfspp)
1091 1090 {
1092 1091 struct vfssw *vswp;
1093 1092 vfsops_t *vfsops;
1094 1093 struct vfs *vfsp;
1095 1094 struct vnode *bvp;
1096 1095 dev_t bdev = 0;
1097 1096 mntopts_t mnt_mntopts;
1098 1097 int error = 0;
1099 1098 int copyout_error = 0;
1100 1099 int ovflags;
1101 1100 char *opts = uap->optptr;
1102 1101 char *inargs = opts;
1103 1102 int optlen = uap->optlen;
1104 1103 int remount;
1105 1104 int rdonly;
1106 1105 int nbmand = 0;
1107 1106 int delmip = 0;
1108 1107 int addmip = 0;
1109 1108 int splice = ((uap->flags & MS_NOSPLICE) == 0);
1110 1109 int fromspace = (uap->flags & MS_SYSSPACE) ?
1111 1110 UIO_SYSSPACE : UIO_USERSPACE;
1112 1111 char *resource = NULL, *mountpt = NULL;
1113 1112 refstr_t *oldresource, *oldmntpt;
1114 1113 struct pathname pn, rpn;
1115 1114 vsk_anchor_t *vskap;
1116 1115 char fstname[FSTYPSZ];
1117 1116 zone_t *zone;
1118 1117
1119 1118 /*
1120 1119 * The v_flag value for the mount point vp is permanently set
1121 1120 * to VVFSLOCK so that no one bypasses the vn_vfs*locks routine
1122 1121 * for mount point locking.
1123 1122 */
1124 1123 mutex_enter(&vp->v_lock);
1125 1124 vp->v_flag |= VVFSLOCK;
1126 1125 mutex_exit(&vp->v_lock);
1127 1126
1128 1127 mnt_mntopts.mo_count = 0;
1129 1128 /*
1130 1129 * Find the ops vector to use to invoke the file system-specific mount
1131 1130 * method. If the fsname argument is non-NULL, use it directly.
1132 1131 * Otherwise, dig the file system type information out of the mount
1133 1132 * arguments.
1134 1133 *
1135 1134 * A side effect is to hold the vfssw entry.
1136 1135 *
1137 1136 * Mount arguments can be specified in several ways, which are
1138 1137 * distinguished by flag bit settings. The preferred way is to set
1139 1138 * MS_OPTIONSTR, indicating an 8 argument mount with the file system
1140 1139 * type supplied as a character string and the last two arguments
1141 1140 * being a pointer to a character buffer and the size of the buffer.
1142 1141 * On entry, the buffer holds a null terminated list of options; on
1143 1142 * return, the string is the list of options the file system
1144 1143 * recognized. If MS_DATA is set arguments five and six point to a
1145 1144 * block of binary data which the file system interprets.
1146 1145 * A further wrinkle is that some callers don't set MS_FSS and MS_DATA
1147 1146 * consistently with these conventions. To handle them, we check to
1148 1147 * see whether the pointer to the file system name has a numeric value
1149 1148 * less than 256. If so, we treat it as an index.
1150 1149 */
1151 1150 if (fsname != NULL) {
1152 1151 if ((vswp = vfs_getvfssw(fsname)) == NULL) {
1153 1152 return (EINVAL);
1154 1153 }
1155 1154 } else if (uap->flags & (MS_OPTIONSTR | MS_DATA | MS_FSS)) {
1156 1155 size_t n;
1157 1156 uint_t fstype;
1158 1157
1159 1158 fsname = fstname;
1160 1159
1161 1160 if ((fstype = (uintptr_t)uap->fstype) < 256) {
1162 1161 RLOCK_VFSSW();
1163 1162 if (fstype == 0 || fstype >= nfstype ||
1164 1163 !ALLOCATED_VFSSW(&vfssw[fstype])) {
1165 1164 RUNLOCK_VFSSW();
1166 1165 return (EINVAL);
1167 1166 }
1168 1167 (void) strcpy(fsname, vfssw[fstype].vsw_name);
1169 1168 RUNLOCK_VFSSW();
1170 1169 if ((vswp = vfs_getvfssw(fsname)) == NULL)
1171 1170 return (EINVAL);
1172 1171 } else {
1173 1172 /*
1174 1173 * Handle either kernel or user address space.
1175 1174 */
1176 1175 if (uap->flags & MS_SYSSPACE) {
1177 1176 error = copystr(uap->fstype, fsname,
1178 1177 FSTYPSZ, &n);
1179 1178 } else {
1180 1179 error = copyinstr(uap->fstype, fsname,
1181 1180 FSTYPSZ, &n);
1182 1181 }
1183 1182 if (error) {
1184 1183 if (error == ENAMETOOLONG)
1185 1184 return (EINVAL);
1186 1185 return (error);
1187 1186 }
1188 1187 if ((vswp = vfs_getvfssw(fsname)) == NULL)
1189 1188 return (EINVAL);
1190 1189 }
1191 1190 } else {
1192 1191 if ((vswp = vfs_getvfsswbyvfsops(vfs_getops(rootvfs))) == NULL)
1193 1192 return (EINVAL);
1194 1193 fsname = vswp->vsw_name;
1195 1194 }
1196 1195 if (!VFS_INSTALLED(vswp))
1197 1196 return (EINVAL);
1198 1197
1199 1198 if ((error = secpolicy_fs_allowed_mount(fsname)) != 0) {
1200 1199 vfs_unrefvfssw(vswp);
1201 1200 return (error);
1202 1201 }
1203 1202
1204 1203 vfsops = &vswp->vsw_vfsops;
1205 1204
1206 1205 vfs_copyopttbl(&vswp->vsw_optproto, &mnt_mntopts);
1207 1206 /*
1208 1207 * Fetch mount options and parse them for generic vfs options
1209 1208 */
1210 1209 if (uap->flags & MS_OPTIONSTR) {
1211 1210 /*
1212 1211 * Limit the buffer size
1213 1212 */
1214 1213 if (optlen < 0 || optlen > MAX_MNTOPT_STR) {
1215 1214 error = EINVAL;
1216 1215 goto errout;
1217 1216 }
1218 1217 if ((uap->flags & MS_SYSSPACE) == 0) {
1219 1218 inargs = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP);
1220 1219 inargs[0] = '\0';
1221 1220 if (optlen) {
1222 1221 error = copyinstr(opts, inargs, (size_t)optlen,
1223 1222 NULL);
1224 1223 if (error) {
1225 1224 goto errout;
1226 1225 }
1227 1226 }
1228 1227 }
1229 1228 vfs_parsemntopts(&mnt_mntopts, inargs, 0);
1230 1229 }
1231 1230 /*
1232 1231 * Flag bits override the options string.
1233 1232 */
1234 1233 if (uap->flags & MS_REMOUNT)
1235 1234 vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_REMOUNT, NULL, 0, 0);
1236 1235 if (uap->flags & MS_RDONLY)
1237 1236 vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_RO, NULL, 0, 0);
1238 1237 if (uap->flags & MS_NOSUID)
1239 1238 vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
1240 1239
1241 1240 /*
1242 1241 * Check if this is a remount; must be set in the option string and
1243 1242 * the file system must support a remount option.
1244 1243 */
1245 1244 if (remount = vfs_optionisset_nolock(&mnt_mntopts,
1246 1245 MNTOPT_REMOUNT, NULL)) {
1247 1246 if (!(vswp->vsw_flag & VSW_CANREMOUNT)) {
1248 1247 error = ENOTSUP;
1249 1248 goto errout;
1250 1249 }
1251 1250 uap->flags |= MS_REMOUNT;
1252 1251 }
1253 1252
1254 1253 /*
1255 1254 * uap->flags and vfs_optionisset() should agree.
1256 1255 */
1257 1256 if (rdonly = vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_RO, NULL)) {
1258 1257 uap->flags |= MS_RDONLY;
1259 1258 }
1260 1259 if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL)) {
1261 1260 uap->flags |= MS_NOSUID;
1262 1261 }
1263 1262 nbmand = vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_NBMAND, NULL);
1264 1263 ASSERT(splice || !remount);
1265 1264 /*
1266 1265 * If we are splicing the fs into the namespace,
1267 1266 * perform mount point checks.
1268 1267 *
1269 1268 * We want to resolve the path for the mount point to eliminate
1270 1269 * '.' and ".." and symlinks in mount points; we can't do the
1271 1270 * same for the resource string, since it would turn
1272 1271 * "/dev/dsk/c0t0d0s0" into "/devices/pci@...". We need to do
1273 1272 * this before grabbing vn_vfswlock(), because otherwise we
1274 1273 * would deadlock with lookuppn().
1275 1274 */
1276 1275 if (splice) {
1277 1276 ASSERT(vp->v_count > 0);
1278 1277
1279 1278 /*
1280 1279 * Pick up mount point and device from appropriate space.
1281 1280 */
1282 1281 if (pn_get(uap->spec, fromspace, &pn) == 0) {
1283 1282 resource = kmem_alloc(pn.pn_pathlen + 1,
1284 1283 KM_SLEEP);
1285 1284 (void) strcpy(resource, pn.pn_path);
1286 1285 pn_free(&pn);
1287 1286 }
1288 1287 /*
1289 1288 * Do a lookupname prior to taking the
1290 1289 * writelock. Mark this as completed if
1291 1290 * successful for later cleanup and addition to
1292 1291 * the mount in progress table.
1293 1292 */
1294 1293 if ((vswp->vsw_flag & VSW_MOUNTDEV) &&
1295 1294 (uap->flags & MS_GLOBAL) == 0 &&
1296 1295 lookupname(uap->spec, fromspace,
1297 1296 FOLLOW, NULL, &bvp) == 0) {
1298 1297 addmip = 1;
1299 1298 }
1300 1299
1301 1300 if ((error = pn_get(uap->dir, fromspace, &pn)) == 0) {
1302 1301 pathname_t *pnp;
1303 1302
1304 1303 if (*pn.pn_path != '/') {
1305 1304 error = EINVAL;
1306 1305 pn_free(&pn);
1307 1306 goto errout;
1308 1307 }
1309 1308 pn_alloc(&rpn);
1310 1309 /*
1311 1310 * Kludge to prevent autofs from deadlocking with
1312 1311 * itself when it calls domount().
1313 1312 *
1314 1313 * If autofs is calling, it is because it is doing
1315 1314 * (autofs) mounts in the process of an NFS mount. A
1316 1315 * lookuppn() here would cause us to block waiting for
1317 1316 * said NFS mount to complete, which can't since this
1318 1317 * is the thread that was supposed to doing it.
1319 1318 */
1320 1319 if (fromspace == UIO_USERSPACE) {
1321 1320 if ((error = lookuppn(&pn, &rpn, FOLLOW, NULL,
1322 1321 NULL)) == 0) {
1323 1322 pnp = &rpn;
1324 1323 } else {
1325 1324 /*
1326 1325 * The file disappeared or otherwise
1327 1326 * became inaccessible since we opened
1328 1327 * it; might as well fail the mount
1329 1328 * since the mount point is no longer
1330 1329 * accessible.
1331 1330 */
1332 1331 pn_free(&rpn);
1333 1332 pn_free(&pn);
1334 1333 goto errout;
1335 1334 }
1336 1335 } else {
1337 1336 pnp = &pn;
1338 1337 }
1339 1338 mountpt = kmem_alloc(pnp->pn_pathlen + 1, KM_SLEEP);
1340 1339 (void) strcpy(mountpt, pnp->pn_path);
1341 1340
1342 1341 /*
1343 1342 * If the addition of the zone's rootpath
1344 1343 * would push us over a total path length
1345 1344 * of MAXPATHLEN, we fail the mount with
1346 1345 * ENAMETOOLONG, which is what we would have
1347 1346 * gotten if we were trying to perform the same
1348 1347 * mount in the global zone.
1349 1348 *
1350 1349 * strlen() doesn't count the trailing
1351 1350 * '\0', but zone_rootpathlen counts both a
1352 1351 * trailing '/' and the terminating '\0'.
1353 1352 */
1354 1353 if ((curproc->p_zone->zone_rootpathlen - 1 +
1355 1354 strlen(mountpt)) > MAXPATHLEN ||
1356 1355 (resource != NULL &&
1357 1356 (curproc->p_zone->zone_rootpathlen - 1 +
1358 1357 strlen(resource)) > MAXPATHLEN)) {
1359 1358 error = ENAMETOOLONG;
1360 1359 }
1361 1360
1362 1361 pn_free(&rpn);
1363 1362 pn_free(&pn);
1364 1363 }
1365 1364
1366 1365 if (error)
1367 1366 goto errout;
1368 1367
1369 1368 /*
1370 1369 * Prevent path name resolution from proceeding past
1371 1370 * the mount point.
1372 1371 */
1373 1372 if (vn_vfswlock(vp) != 0) {
1374 1373 error = EBUSY;
1375 1374 goto errout;
1376 1375 }
1377 1376
1378 1377 /*
1379 1378 * Verify that it's legitimate to establish a mount on
1380 1379 * the prospective mount point.
1381 1380 */
1382 1381 if (vn_mountedvfs(vp) != NULL) {
1383 1382 /*
1384 1383 * The mount point lock was obtained after some
1385 1384 * other thread raced through and established a mount.
1386 1385 */
1387 1386 vn_vfsunlock(vp);
1388 1387 error = EBUSY;
1389 1388 goto errout;
1390 1389 }
1391 1390 if (vp->v_flag & VNOMOUNT) {
1392 1391 vn_vfsunlock(vp);
1393 1392 error = EINVAL;
1394 1393 goto errout;
1395 1394 }
1396 1395 }
1397 1396 if ((uap->flags & (MS_DATA | MS_OPTIONSTR)) == 0) {
1398 1397 uap->dataptr = NULL;
1399 1398 uap->datalen = 0;
1400 1399 }
1401 1400
1402 1401 /*
1403 1402 * If this is a remount, we don't want to create a new VFS.
1404 1403 * Instead, we pass the existing one with a remount flag.
1405 1404 */
1406 1405 if (remount) {
1407 1406 /*
1408 1407 * Confirm that the mount point is the root vnode of the
1409 1408 * file system that is being remounted.
1410 1409 * This can happen if the user specifies a different
1411 1410 * mount point directory pathname in the (re)mount command.
1412 1411 *
1413 1412 * Code below can only be reached if splice is true, so it's
1414 1413 * safe to do vn_vfsunlock() here.
1415 1414 */
1416 1415 if ((vp->v_flag & VROOT) == 0) {
1417 1416 vn_vfsunlock(vp);
1418 1417 error = ENOENT;
1419 1418 goto errout;
1420 1419 }
1421 1420 /*
1422 1421 * Disallow making file systems read-only unless file system
1423 1422 * explicitly allows it in its vfssw. Ignore other flags.
1424 1423 */
1425 1424 if (rdonly && vn_is_readonly(vp) == 0 &&
1426 1425 (vswp->vsw_flag & VSW_CANRWRO) == 0) {
1427 1426 vn_vfsunlock(vp);
1428 1427 error = EINVAL;
1429 1428 goto errout;
1430 1429 }
1431 1430 /*
1432 1431 * Disallow changing the NBMAND disposition of the file
1433 1432 * system on remounts.
1434 1433 */
1435 1434 if ((nbmand && ((vp->v_vfsp->vfs_flag & VFS_NBMAND) == 0)) ||
1436 1435 (!nbmand && (vp->v_vfsp->vfs_flag & VFS_NBMAND))) {
1437 1436 vn_vfsunlock(vp);
1438 1437 error = EINVAL;
1439 1438 goto errout;
1440 1439 }
1441 1440 vfsp = vp->v_vfsp;
1442 1441 ovflags = vfsp->vfs_flag;
1443 1442 vfsp->vfs_flag |= VFS_REMOUNT;
1444 1443 vfsp->vfs_flag &= ~VFS_RDONLY;
1445 1444 } else {
1446 1445 vfsp = vfs_alloc(KM_SLEEP);
1447 1446 VFS_INIT(vfsp, vfsops, NULL);
1448 1447 }
1449 1448
1450 1449 VFS_HOLD(vfsp);
1451 1450
1452 1451 if ((error = lofi_add(fsname, vfsp, &mnt_mntopts, uap)) != 0) {
1453 1452 if (!remount) {
1454 1453 if (splice)
1455 1454 vn_vfsunlock(vp);
1456 1455 vfs_free(vfsp);
1457 1456 } else {
1458 1457 vn_vfsunlock(vp);
1459 1458 VFS_RELE(vfsp);
1460 1459 }
1461 1460 goto errout;
1462 1461 }
1463 1462
1464 1463 /*
1465 1464 * PRIV_SYS_MOUNT doesn't mean you can become root.
1466 1465 */
1467 1466 if (vfsp->vfs_lofi_id != 0) {
1468 1467 uap->flags |= MS_NOSUID;
1469 1468 vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
1470 1469 }
1471 1470
1472 1471 /*
1473 1472 * The vfs_reflock is not used anymore the code below explicitly
1474 1473 * holds it preventing others accesing it directly.
1475 1474 */
1476 1475 if ((sema_tryp(&vfsp->vfs_reflock) == 0) &&
1477 1476 !(vfsp->vfs_flag & VFS_REMOUNT))
1478 1477 cmn_err(CE_WARN,
1479 1478 "mount type %s couldn't get vfs_reflock", vswp->vsw_name);
1480 1479
1481 1480 /*
1482 1481 * Lock the vfs. If this is a remount we want to avoid spurious umount
1483 1482 * failures that happen as a side-effect of fsflush() and other mount
1484 1483 * and unmount operations that might be going on simultaneously and
1485 1484 * may have locked the vfs currently. To not return EBUSY immediately
1486 1485 * here we use vfs_lock_wait() instead vfs_lock() for the remount case.
1487 1486 */
1488 1487 if (!remount) {
1489 1488 if (error = vfs_lock(vfsp)) {
1490 1489 vfsp->vfs_flag = ovflags;
1491 1490
1492 1491 lofi_remove(vfsp);
1493 1492
1494 1493 if (splice)
1495 1494 vn_vfsunlock(vp);
1496 1495 vfs_free(vfsp);
1497 1496 goto errout;
1498 1497 }
1499 1498 } else {
1500 1499 vfs_lock_wait(vfsp);
1501 1500 }
1502 1501
1503 1502 /*
1504 1503 * Add device to mount in progress table, global mounts require special
1505 1504 * handling. It is possible that we have already done the lookupname
1506 1505 * on a spliced, non-global fs. If so, we don't want to do it again
1507 1506 * since we cannot do a lookupname after taking the
1508 1507 * wlock above. This case is for a non-spliced, non-global filesystem.
1509 1508 */
1510 1509 if (!addmip) {
1511 1510 if ((vswp->vsw_flag & VSW_MOUNTDEV) &&
1512 1511 (uap->flags & MS_GLOBAL) == 0 &&
1513 1512 lookupname(uap->spec, fromspace, FOLLOW, NULL, &bvp) == 0) {
1514 1513 addmip = 1;
1515 1514 }
1516 1515 }
1517 1516
1518 1517 if (addmip) {
1519 1518 vnode_t *lvp = NULL;
1520 1519
1521 1520 error = vfs_get_lofi(vfsp, &lvp);
1522 1521 if (error > 0) {
1523 1522 lofi_remove(vfsp);
1524 1523
1525 1524 if (splice)
1526 1525 vn_vfsunlock(vp);
1527 1526 vfs_unlock(vfsp);
1528 1527
1529 1528 if (remount) {
1530 1529 VFS_RELE(vfsp);
1531 1530 } else {
1532 1531 vfs_free(vfsp);
1533 1532 }
1534 1533
1535 1534 goto errout;
1536 1535 } else if (error == -1) {
1537 1536 bdev = bvp->v_rdev;
1538 1537 VN_RELE(bvp);
1539 1538 } else {
1540 1539 bdev = lvp->v_rdev;
1541 1540 VN_RELE(lvp);
1542 1541 VN_RELE(bvp);
1543 1542 }
1544 1543
1545 1544 vfs_addmip(bdev, vfsp);
1546 1545 addmip = 0;
1547 1546 delmip = 1;
1548 1547 }
1549 1548 /*
1550 1549 * Invalidate cached entry for the mount point.
1551 1550 */
1552 1551 if (splice)
1553 1552 dnlc_purge_vp(vp);
1554 1553
1555 1554 /*
1556 1555 * If have an option string but the filesystem doesn't supply a
1557 1556 * prototype options table, create a table with the global
1558 1557 * options and sufficient room to accept all the options in the
1559 1558 * string. Then parse the passed in option string
1560 1559 * accepting all the options in the string. This gives us an
1561 1560 * option table with all the proper cancel properties for the
1562 1561 * global options.
1563 1562 *
1564 1563 * Filesystems that supply a prototype options table are handled
1565 1564 * earlier in this function.
1566 1565 */
1567 1566 if (uap->flags & MS_OPTIONSTR) {
1568 1567 if (!(vswp->vsw_flag & VSW_HASPROTO)) {
1569 1568 mntopts_t tmp_mntopts;
1570 1569
1571 1570 tmp_mntopts.mo_count = 0;
1572 1571 vfs_createopttbl_extend(&tmp_mntopts, inargs,
1573 1572 &mnt_mntopts);
1574 1573 vfs_parsemntopts(&tmp_mntopts, inargs, 1);
1575 1574 vfs_swapopttbl_nolock(&mnt_mntopts, &tmp_mntopts);
1576 1575 vfs_freeopttbl(&tmp_mntopts);
1577 1576 }
1578 1577 }
1579 1578
1580 1579 /*
1581 1580 * Serialize with zone state transitions.
1582 1581 * See vfs_list_add; zone mounted into is:
1583 1582 * zone_find_by_path(refstr_value(vfsp->vfs_mntpt))
1584 1583 * not the zone doing the mount (curproc->p_zone), but if we're already
1585 1584 * inside a NGZ, then we know what zone we are.
1586 1585 */
1587 1586 if (INGLOBALZONE(curproc)) {
1588 1587 zone = zone_find_by_path(mountpt);
1589 1588 ASSERT(zone != NULL);
1590 1589 } else {
1591 1590 zone = curproc->p_zone;
1592 1591 /*
1593 1592 * zone_find_by_path does a hold, so do one here too so that
1594 1593 * we can do a zone_rele after mount_completed.
1595 1594 */
1596 1595 zone_hold(zone);
1597 1596 }
1598 1597 mount_in_progress(zone);
1599 1598 /*
1600 1599 * Instantiate (or reinstantiate) the file system. If appropriate,
1601 1600 * splice it into the file system name space.
1602 1601 *
1603 1602 * We want VFS_MOUNT() to be able to override the vfs_resource
1604 1603 * string if necessary (ie, mntfs), and also for a remount to
1605 1604 * change the same (necessary when remounting '/' during boot).
1606 1605 * So we set up vfs_mntpt and vfs_resource to what we think they
1607 1606 * should be, then hand off control to VFS_MOUNT() which can
1608 1607 * override this.
1609 1608 *
1610 1609 * For safety's sake, when changing vfs_resource or vfs_mntpt of
1611 1610 * a vfs which is on the vfs list (i.e. during a remount), we must
1612 1611 * never set those fields to NULL. Several bits of code make
1613 1612 * assumptions that the fields are always valid.
1614 1613 */
1615 1614 vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts);
1616 1615 if (remount) {
1617 1616 if ((oldresource = vfsp->vfs_resource) != NULL)
1618 1617 refstr_hold(oldresource);
1619 1618 if ((oldmntpt = vfsp->vfs_mntpt) != NULL)
1620 1619 refstr_hold(oldmntpt);
1621 1620 }
1622 1621 vfs_setresource(vfsp, resource, 0);
1623 1622 vfs_setmntpoint(vfsp, mountpt, 0);
1624 1623
1625 1624 /*
1626 1625 * going to mount on this vnode, so notify.
1627 1626 */
1628 1627 vnevent_mountedover(vp, NULL);
1629 1628 error = VFS_MOUNT(vfsp, vp, uap, credp);
1630 1629
1631 1630 if (uap->flags & MS_RDONLY)
1632 1631 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
1633 1632 if (uap->flags & MS_NOSUID)
1634 1633 vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0);
1635 1634 if (uap->flags & MS_GLOBAL)
1636 1635 vfs_setmntopt(vfsp, MNTOPT_GLOBAL, NULL, 0);
1637 1636
1638 1637 if (error) {
1639 1638 lofi_remove(vfsp);
1640 1639
1641 1640 if (remount) {
1642 1641 /* put back pre-remount options */
1643 1642 vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts);
1644 1643 vfs_setmntpoint(vfsp, refstr_value(oldmntpt),
1645 1644 VFSSP_VERBATIM);
1646 1645 if (oldmntpt)
1647 1646 refstr_rele(oldmntpt);
1648 1647 vfs_setresource(vfsp, refstr_value(oldresource),
1649 1648 VFSSP_VERBATIM);
1650 1649 if (oldresource)
1651 1650 refstr_rele(oldresource);
1652 1651 vfsp->vfs_flag = ovflags;
1653 1652 vfs_unlock(vfsp);
1654 1653 VFS_RELE(vfsp);
1655 1654 } else {
1656 1655 vfs_unlock(vfsp);
1657 1656 vfs_freemnttab(vfsp);
1658 1657 vfs_free(vfsp);
1659 1658 }
1660 1659 } else {
1661 1660 /*
1662 1661 * Set the mount time to now
1663 1662 */
1664 1663 vfsp->vfs_mtime = ddi_get_time();
1665 1664 if (remount) {
1666 1665 vfsp->vfs_flag &= ~VFS_REMOUNT;
1667 1666 if (oldresource)
1668 1667 refstr_rele(oldresource);
1669 1668 if (oldmntpt)
1670 1669 refstr_rele(oldmntpt);
1671 1670 } else if (splice) {
1672 1671 /*
1673 1672 * Link vfsp into the name space at the mount
1674 1673 * point. Vfs_add() is responsible for
1675 1674 * holding the mount point which will be
1676 1675 * released when vfs_remove() is called.
1677 1676 */
1678 1677 vfs_add(vp, vfsp, uap->flags);
1679 1678 } else {
1680 1679 /*
1681 1680 * Hold the reference to file system which is
1682 1681 * not linked into the name space.
1683 1682 */
1684 1683 vfsp->vfs_zone = NULL;
1685 1684 VFS_HOLD(vfsp);
1686 1685 vfsp->vfs_vnodecovered = NULL;
1687 1686 }
1688 1687 /*
1689 1688 * Set flags for global options encountered
1690 1689 */
1691 1690 if (vfs_optionisset(vfsp, MNTOPT_RO, NULL))
1692 1691 vfsp->vfs_flag |= VFS_RDONLY;
1693 1692 else
1694 1693 vfsp->vfs_flag &= ~VFS_RDONLY;
1695 1694 if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) {
1696 1695 vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES);
1697 1696 } else {
1698 1697 if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL))
1699 1698 vfsp->vfs_flag |= VFS_NODEVICES;
1700 1699 else
1701 1700 vfsp->vfs_flag &= ~VFS_NODEVICES;
1702 1701 if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL))
1703 1702 vfsp->vfs_flag |= VFS_NOSETUID;
1704 1703 else
1705 1704 vfsp->vfs_flag &= ~VFS_NOSETUID;
1706 1705 }
1707 1706 if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL))
1708 1707 vfsp->vfs_flag |= VFS_NBMAND;
1709 1708 else
1710 1709 vfsp->vfs_flag &= ~VFS_NBMAND;
1711 1710
1712 1711 if (vfs_optionisset(vfsp, MNTOPT_XATTR, NULL))
1713 1712 vfsp->vfs_flag |= VFS_XATTR;
1714 1713 else
1715 1714 vfsp->vfs_flag &= ~VFS_XATTR;
1716 1715
1717 1716 if (vfs_optionisset(vfsp, MNTOPT_NOEXEC, NULL))
1718 1717 vfsp->vfs_flag |= VFS_NOEXEC;
1719 1718 else
1720 1719 vfsp->vfs_flag &= ~VFS_NOEXEC;
1721 1720
1722 1721 /*
1723 1722 * Now construct the output option string of options
1724 1723 * we recognized.
1725 1724 */
1726 1725 if (uap->flags & MS_OPTIONSTR) {
1727 1726 vfs_list_read_lock();
1728 1727 copyout_error = vfs_buildoptionstr(
1729 1728 &vfsp->vfs_mntopts, inargs, optlen);
1730 1729 vfs_list_unlock();
1731 1730 if (copyout_error == 0 &&
1732 1731 (uap->flags & MS_SYSSPACE) == 0) {
1733 1732 copyout_error = copyoutstr(inargs, opts,
1734 1733 optlen, NULL);
1735 1734 }
1736 1735 }
1737 1736
1738 1737 /*
1739 1738 * If this isn't a remount, set up the vopstats before
1740 1739 * anyone can touch this. We only allow spliced file
1741 1740 * systems (file systems which are in the namespace) to
1742 1741 * have the VFS_STATS flag set.
1743 1742 * NOTE: PxFS mounts the underlying file system with
1744 1743 * MS_NOSPLICE set and copies those vfs_flags to its private
1745 1744 * vfs structure. As a result, PxFS should never have
1746 1745 * the VFS_STATS flag or else we might access the vfs
1747 1746 * statistics-related fields prior to them being
1748 1747 * properly initialized.
1749 1748 */
1750 1749 if (!remount && (vswp->vsw_flag & VSW_STATS) && splice) {
1751 1750 initialize_vopstats(&vfsp->vfs_vopstats);
1752 1751 /*
1753 1752 * We need to set vfs_vskap to NULL because there's
1754 1753 * a chance it won't be set below. This is checked
1755 1754 * in teardown_vopstats() so we can't have garbage.
1756 1755 */
1757 1756 vfsp->vfs_vskap = NULL;
1758 1757 vfsp->vfs_flag |= VFS_STATS;
1759 1758 vfsp->vfs_fstypevsp = get_fstype_vopstats(vfsp, vswp);
1760 1759 }
1761 1760
1762 1761 if (vswp->vsw_flag & VSW_XID)
1763 1762 vfsp->vfs_flag |= VFS_XID;
1764 1763
1765 1764 vfs_unlock(vfsp);
1766 1765 }
1767 1766 mount_completed(zone);
1768 1767 zone_rele(zone);
1769 1768 if (splice)
1770 1769 vn_vfsunlock(vp);
1771 1770
1772 1771 if ((error == 0) && (copyout_error == 0)) {
1773 1772 if (!remount) {
1774 1773 /*
1775 1774 * Don't call get_vskstat_anchor() while holding
1776 1775 * locks since it allocates memory and calls
1777 1776 * VFS_STATVFS(). For NFS, the latter can generate
1778 1777 * an over-the-wire call.
1779 1778 */
1780 1779 vskap = get_vskstat_anchor(vfsp);
1781 1780 /* Only take the lock if we have something to do */
1782 1781 if (vskap != NULL) {
1783 1782 vfs_lock_wait(vfsp);
1784 1783 if (vfsp->vfs_flag & VFS_STATS) {
1785 1784 vfsp->vfs_vskap = vskap;
1786 1785 }
1787 1786 vfs_unlock(vfsp);
1788 1787 }
1789 1788 }
1790 1789 /* Return vfsp to caller. */
1791 1790 *vfspp = vfsp;
1792 1791 }
1793 1792 errout:
1794 1793 vfs_freeopttbl(&mnt_mntopts);
1795 1794 if (resource != NULL)
1796 1795 kmem_free(resource, strlen(resource) + 1);
1797 1796 if (mountpt != NULL)
1798 1797 kmem_free(mountpt, strlen(mountpt) + 1);
1799 1798 /*
1800 1799 * It is possible we errored prior to adding to mount in progress
1801 1800 * table. Must free vnode we acquired with successful lookupname.
1802 1801 */
1803 1802 if (addmip)
1804 1803 VN_RELE(bvp);
1805 1804 if (delmip)
1806 1805 vfs_delmip(vfsp);
1807 1806 ASSERT(vswp != NULL);
1808 1807 vfs_unrefvfssw(vswp);
1809 1808 if (inargs != opts)
1810 1809 kmem_free(inargs, MAX_MNTOPT_STR);
1811 1810 if (copyout_error) {
1812 1811 lofi_remove(vfsp);
1813 1812 VFS_RELE(vfsp);
1814 1813 error = copyout_error;
1815 1814 }
1816 1815 return (error);
1817 1816 }
1818 1817
1819 1818 static void
1820 1819 vfs_setpath(
1821 1820 struct vfs *vfsp, /* vfs being updated */
1822 1821 refstr_t **refp, /* Ref-count string to contain the new path */
1823 1822 const char *newpath, /* Path to add to refp (above) */
1824 1823 uint32_t flag) /* flag */
1825 1824 {
1826 1825 size_t len;
1827 1826 refstr_t *ref;
1828 1827 zone_t *zone = curproc->p_zone;
1829 1828 char *sp;
1830 1829 int have_list_lock = 0;
1831 1830
1832 1831 ASSERT(!VFS_ON_LIST(vfsp) || vfs_lock_held(vfsp));
1833 1832
1834 1833 /*
1835 1834 * New path must be less than MAXPATHLEN because mntfs
1836 1835 * will only display up to MAXPATHLEN bytes. This is currently
1837 1836 * safe, because domount() uses pn_get(), and other callers
1838 1837 * similarly cap the size to fewer than MAXPATHLEN bytes.
1839 1838 */
1840 1839
1841 1840 ASSERT(strlen(newpath) < MAXPATHLEN);
1842 1841
1843 1842 /* mntfs requires consistency while vfs list lock is held */
1844 1843
1845 1844 if (VFS_ON_LIST(vfsp)) {
1846 1845 have_list_lock = 1;
1847 1846 vfs_list_lock();
1848 1847 }
1849 1848
1850 1849 if (*refp != NULL)
1851 1850 refstr_rele(*refp);
1852 1851
1853 1852 /*
1854 1853 * If we are in a non-global zone then we prefix the supplied path,
1855 1854 * newpath, with the zone's root path, with two exceptions. The first
1856 1855 * is where we have been explicitly directed to avoid doing so; this
1857 1856 * will be the case following a failed remount, where the path supplied
1858 1857 * will be a saved version which must now be restored. The second
1859 1858 * exception is where newpath is not a pathname but a descriptive name,
1860 1859 * e.g. "procfs".
1861 1860 */
1862 1861 if (zone == global_zone || (flag & VFSSP_VERBATIM) || *newpath != '/') {
1863 1862 ref = refstr_alloc(newpath);
1864 1863 goto out;
1865 1864 }
1866 1865
1867 1866 /*
1868 1867 * Truncate the trailing '/' in the zoneroot, and merge
1869 1868 * in the zone's rootpath with the "newpath" (resource
1870 1869 * or mountpoint) passed in.
1871 1870 *
1872 1871 * The size of the required buffer is thus the size of
1873 1872 * the buffer required for the passed-in newpath
1874 1873 * (strlen(newpath) + 1), plus the size of the buffer
1875 1874 * required to hold zone_rootpath (zone_rootpathlen)
1876 1875 * minus one for one of the now-superfluous NUL
1877 1876 * terminations, minus one for the trailing '/'.
1878 1877 *
1879 1878 * That gives us:
1880 1879 *
1881 1880 * (strlen(newpath) + 1) + zone_rootpathlen - 1 - 1
1882 1881 *
1883 1882 * Which is what we have below.
1884 1883 */
1885 1884
1886 1885 len = strlen(newpath) + zone->zone_rootpathlen - 1;
1887 1886 sp = kmem_alloc(len, KM_SLEEP);
1888 1887
1889 1888 /*
1890 1889 * Copy everything including the trailing slash, which
1891 1890 * we then overwrite with the NUL character.
1892 1891 */
1893 1892
1894 1893 (void) strcpy(sp, zone->zone_rootpath);
1895 1894 sp[zone->zone_rootpathlen - 2] = '\0';
1896 1895 (void) strcat(sp, newpath);
1897 1896
1898 1897 ref = refstr_alloc(sp);
1899 1898 kmem_free(sp, len);
1900 1899 out:
1901 1900 *refp = ref;
1902 1901
1903 1902 if (have_list_lock) {
1904 1903 vfs_mnttab_modtimeupd();
1905 1904 vfs_list_unlock();
1906 1905 }
1907 1906 }
1908 1907
1909 1908 /*
1910 1909 * Record a mounted resource name in a vfs structure.
1911 1910 * If vfsp is already mounted, caller must hold the vfs lock.
1912 1911 */
1913 1912 void
1914 1913 vfs_setresource(struct vfs *vfsp, const char *resource, uint32_t flag)
1915 1914 {
1916 1915 if (resource == NULL || resource[0] == '\0')
1917 1916 resource = VFS_NORESOURCE;
1918 1917 vfs_setpath(vfsp, &vfsp->vfs_resource, resource, flag);
1919 1918 }
1920 1919
1921 1920 /*
1922 1921 * Record a mount point name in a vfs structure.
1923 1922 * If vfsp is already mounted, caller must hold the vfs lock.
1924 1923 */
1925 1924 void
1926 1925 vfs_setmntpoint(struct vfs *vfsp, const char *mntpt, uint32_t flag)
1927 1926 {
1928 1927 if (mntpt == NULL || mntpt[0] == '\0')
1929 1928 mntpt = VFS_NOMNTPT;
1930 1929 vfs_setpath(vfsp, &vfsp->vfs_mntpt, mntpt, flag);
1931 1930 }
1932 1931
1933 1932 /* Returns the vfs_resource. Caller must call refstr_rele() when finished. */
1934 1933
1935 1934 refstr_t *
1936 1935 vfs_getresource(const struct vfs *vfsp)
1937 1936 {
1938 1937 refstr_t *resource;
1939 1938
1940 1939 vfs_list_read_lock();
1941 1940 resource = vfsp->vfs_resource;
1942 1941 refstr_hold(resource);
1943 1942 vfs_list_unlock();
1944 1943
1945 1944 return (resource);
1946 1945 }
1947 1946
1948 1947 /* Returns the vfs_mntpt. Caller must call refstr_rele() when finished. */
1949 1948
1950 1949 refstr_t *
1951 1950 vfs_getmntpoint(const struct vfs *vfsp)
1952 1951 {
1953 1952 refstr_t *mntpt;
1954 1953
1955 1954 vfs_list_read_lock();
1956 1955 mntpt = vfsp->vfs_mntpt;
1957 1956 refstr_hold(mntpt);
1958 1957 vfs_list_unlock();
1959 1958
1960 1959 return (mntpt);
1961 1960 }
1962 1961
1963 1962 /*
1964 1963 * Create an empty options table with enough empty slots to hold all
1965 1964 * The options in the options string passed as an argument.
1966 1965 * Potentially prepend another options table.
1967 1966 *
1968 1967 * Note: caller is responsible for locking the vfs list, if needed,
1969 1968 * to protect mops.
1970 1969 */
1971 1970 static void
1972 1971 vfs_createopttbl_extend(mntopts_t *mops, const char *opts,
1973 1972 const mntopts_t *mtmpl)
1974 1973 {
1975 1974 const char *s = opts;
1976 1975 uint_t count;
1977 1976
1978 1977 if (opts == NULL || *opts == '\0') {
1979 1978 count = 0;
1980 1979 } else {
1981 1980 count = 1;
1982 1981
1983 1982 /*
1984 1983 * Count number of options in the string
1985 1984 */
1986 1985 for (s = strchr(s, ','); s != NULL; s = strchr(s, ',')) {
1987 1986 count++;
1988 1987 s++;
1989 1988 }
1990 1989 }
1991 1990 vfs_copyopttbl_extend(mtmpl, mops, count);
1992 1991 }
1993 1992
1994 1993 /*
1995 1994 * Create an empty options table with enough empty slots to hold all
1996 1995 * The options in the options string passed as an argument.
1997 1996 *
1998 1997 * This function is *not* for general use by filesystems.
1999 1998 *
2000 1999 * Note: caller is responsible for locking the vfs list, if needed,
2001 2000 * to protect mops.
2002 2001 */
2003 2002 void
2004 2003 vfs_createopttbl(mntopts_t *mops, const char *opts)
2005 2004 {
2006 2005 vfs_createopttbl_extend(mops, opts, NULL);
2007 2006 }
2008 2007
2009 2008
2010 2009 /*
2011 2010 * Swap two mount options tables
2012 2011 */
2013 2012 static void
2014 2013 vfs_swapopttbl_nolock(mntopts_t *optbl1, mntopts_t *optbl2)
2015 2014 {
2016 2015 uint_t tmpcnt;
2017 2016 mntopt_t *tmplist;
2018 2017
2019 2018 tmpcnt = optbl2->mo_count;
2020 2019 tmplist = optbl2->mo_list;
2021 2020 optbl2->mo_count = optbl1->mo_count;
2022 2021 optbl2->mo_list = optbl1->mo_list;
2023 2022 optbl1->mo_count = tmpcnt;
2024 2023 optbl1->mo_list = tmplist;
2025 2024 }
2026 2025
2027 2026 static void
2028 2027 vfs_swapopttbl(mntopts_t *optbl1, mntopts_t *optbl2)
2029 2028 {
2030 2029 vfs_list_lock();
2031 2030 vfs_swapopttbl_nolock(optbl1, optbl2);
2032 2031 vfs_mnttab_modtimeupd();
2033 2032 vfs_list_unlock();
2034 2033 }
2035 2034
2036 2035 static char **
2037 2036 vfs_copycancelopt_extend(char **const moc, int extend)
2038 2037 {
2039 2038 int i = 0;
2040 2039 int j;
2041 2040 char **result;
2042 2041
2043 2042 if (moc != NULL) {
2044 2043 for (; moc[i] != NULL; i++)
2045 2044 /* count number of options to cancel */;
2046 2045 }
2047 2046
2048 2047 if (i + extend == 0)
2049 2048 return (NULL);
2050 2049
2051 2050 result = kmem_alloc((i + extend + 1) * sizeof (char *), KM_SLEEP);
2052 2051
2053 2052 for (j = 0; j < i; j++) {
2054 2053 result[j] = kmem_alloc(strlen(moc[j]) + 1, KM_SLEEP);
2055 2054 (void) strcpy(result[j], moc[j]);
2056 2055 }
2057 2056 for (; j <= i + extend; j++)
2058 2057 result[j] = NULL;
2059 2058
2060 2059 return (result);
2061 2060 }
2062 2061
2063 2062 static void
2064 2063 vfs_copyopt(const mntopt_t *s, mntopt_t *d)
2065 2064 {
2066 2065 char *sp, *dp;
2067 2066
2068 2067 d->mo_flags = s->mo_flags;
2069 2068 d->mo_data = s->mo_data;
2070 2069 sp = s->mo_name;
2071 2070 if (sp != NULL) {
2072 2071 dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
2073 2072 (void) strcpy(dp, sp);
2074 2073 d->mo_name = dp;
2075 2074 } else {
2076 2075 d->mo_name = NULL; /* should never happen */
2077 2076 }
2078 2077
2079 2078 d->mo_cancel = vfs_copycancelopt_extend(s->mo_cancel, 0);
2080 2079
2081 2080 sp = s->mo_arg;
2082 2081 if (sp != NULL) {
2083 2082 dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP);
2084 2083 (void) strcpy(dp, sp);
2085 2084 d->mo_arg = dp;
2086 2085 } else {
2087 2086 d->mo_arg = NULL;
2088 2087 }
2089 2088 }
2090 2089
2091 2090 /*
2092 2091 * Copy a mount options table, possibly allocating some spare
2093 2092 * slots at the end. It is permissible to copy_extend the NULL table.
2094 2093 */
2095 2094 static void
2096 2095 vfs_copyopttbl_extend(const mntopts_t *smo, mntopts_t *dmo, int extra)
2097 2096 {
2098 2097 uint_t i, count;
2099 2098 mntopt_t *motbl;
2100 2099
2101 2100 /*
2102 2101 * Clear out any existing stuff in the options table being initialized
2103 2102 */
2104 2103 vfs_freeopttbl(dmo);
2105 2104 count = (smo == NULL) ? 0 : smo->mo_count;
2106 2105 if ((count + extra) == 0) /* nothing to do */
2107 2106 return;
2108 2107 dmo->mo_count = count + extra;
2109 2108 motbl = kmem_zalloc((count + extra) * sizeof (mntopt_t), KM_SLEEP);
2110 2109 dmo->mo_list = motbl;
2111 2110 for (i = 0; i < count; i++) {
2112 2111 vfs_copyopt(&smo->mo_list[i], &motbl[i]);
2113 2112 }
2114 2113 for (i = count; i < count + extra; i++) {
2115 2114 motbl[i].mo_flags = MO_EMPTY;
2116 2115 }
2117 2116 }
2118 2117
2119 2118 /*
2120 2119 * Copy a mount options table.
2121 2120 *
2122 2121 * This function is *not* for general use by filesystems.
2123 2122 *
2124 2123 * Note: caller is responsible for locking the vfs list, if needed,
2125 2124 * to protect smo and dmo.
2126 2125 */
2127 2126 void
2128 2127 vfs_copyopttbl(const mntopts_t *smo, mntopts_t *dmo)
2129 2128 {
2130 2129 vfs_copyopttbl_extend(smo, dmo, 0);
2131 2130 }
2132 2131
2133 2132 static char **
2134 2133 vfs_mergecancelopts(const mntopt_t *mop1, const mntopt_t *mop2)
2135 2134 {
2136 2135 int c1 = 0;
2137 2136 int c2 = 0;
2138 2137 char **result;
2139 2138 char **sp1, **sp2, **dp;
2140 2139
2141 2140 /*
2142 2141 * First we count both lists of cancel options.
2143 2142 * If either is NULL or has no elements, we return a copy of
2144 2143 * the other.
2145 2144 */
2146 2145 if (mop1->mo_cancel != NULL) {
2147 2146 for (; mop1->mo_cancel[c1] != NULL; c1++)
2148 2147 /* count cancel options in mop1 */;
2149 2148 }
2150 2149
2151 2150 if (c1 == 0)
2152 2151 return (vfs_copycancelopt_extend(mop2->mo_cancel, 0));
2153 2152
2154 2153 if (mop2->mo_cancel != NULL) {
2155 2154 for (; mop2->mo_cancel[c2] != NULL; c2++)
2156 2155 /* count cancel options in mop2 */;
2157 2156 }
2158 2157
2159 2158 result = vfs_copycancelopt_extend(mop1->mo_cancel, c2);
2160 2159
2161 2160 if (c2 == 0)
2162 2161 return (result);
2163 2162
2164 2163 /*
2165 2164 * When we get here, we've got two sets of cancel options;
2166 2165 * we need to merge the two sets. We know that the result
2167 2166 * array has "c1+c2+1" entries and in the end we might shrink
2168 2167 * it.
2169 2168 * Result now has a copy of the c1 entries from mop1; we'll
2170 2169 * now lookup all the entries of mop2 in mop1 and copy it if
2171 2170 * it is unique.
2172 2171 * This operation is O(n^2) but it's only called once per
2173 2172 * filesystem per duplicate option. This is a situation
2174 2173 * which doesn't arise with the filesystems in ON and
2175 2174 * n is generally 1.
2176 2175 */
2177 2176
2178 2177 dp = &result[c1];
2179 2178 for (sp2 = mop2->mo_cancel; *sp2 != NULL; sp2++) {
2180 2179 for (sp1 = mop1->mo_cancel; *sp1 != NULL; sp1++) {
2181 2180 if (strcmp(*sp1, *sp2) == 0)
2182 2181 break;
2183 2182 }
2184 2183 if (*sp1 == NULL) {
2185 2184 /*
2186 2185 * Option *sp2 not found in mop1, so copy it.
2187 2186 * The calls to vfs_copycancelopt_extend()
2188 2187 * guarantee that there's enough room.
2189 2188 */
2190 2189 *dp = kmem_alloc(strlen(*sp2) + 1, KM_SLEEP);
2191 2190 (void) strcpy(*dp++, *sp2);
2192 2191 }
2193 2192 }
2194 2193 if (dp != &result[c1+c2]) {
2195 2194 size_t bytes = (dp - result + 1) * sizeof (char *);
2196 2195 char **nres = kmem_alloc(bytes, KM_SLEEP);
2197 2196
2198 2197 bcopy(result, nres, bytes);
2199 2198 kmem_free(result, (c1 + c2 + 1) * sizeof (char *));
2200 2199 result = nres;
2201 2200 }
2202 2201 return (result);
2203 2202 }
2204 2203
2205 2204 /*
2206 2205 * Merge two mount option tables (outer and inner) into one. This is very
2207 2206 * similar to "merging" global variables and automatic variables in C.
2208 2207 *
2209 2208 * This isn't (and doesn't have to be) fast.
2210 2209 *
2211 2210 * This function is *not* for general use by filesystems.
2212 2211 *
2213 2212 * Note: caller is responsible for locking the vfs list, if needed,
2214 2213 * to protect omo, imo & dmo.
2215 2214 */
2216 2215 void
2217 2216 vfs_mergeopttbl(const mntopts_t *omo, const mntopts_t *imo, mntopts_t *dmo)
2218 2217 {
2219 2218 uint_t i, count;
2220 2219 mntopt_t *mop, *motbl;
2221 2220 uint_t freeidx;
2222 2221
2223 2222 /*
2224 2223 * First determine how much space we need to allocate.
2225 2224 */
2226 2225 count = omo->mo_count;
2227 2226 for (i = 0; i < imo->mo_count; i++) {
2228 2227 if (imo->mo_list[i].mo_flags & MO_EMPTY)
2229 2228 continue;
2230 2229 if (vfs_hasopt(omo, imo->mo_list[i].mo_name) == NULL)
2231 2230 count++;
2232 2231 }
2233 2232 ASSERT(count >= omo->mo_count &&
2234 2233 count <= omo->mo_count + imo->mo_count);
2235 2234 motbl = kmem_alloc(count * sizeof (mntopt_t), KM_SLEEP);
2236 2235 for (i = 0; i < omo->mo_count; i++)
2237 2236 vfs_copyopt(&omo->mo_list[i], &motbl[i]);
2238 2237 freeidx = omo->mo_count;
2239 2238 for (i = 0; i < imo->mo_count; i++) {
2240 2239 if (imo->mo_list[i].mo_flags & MO_EMPTY)
2241 2240 continue;
2242 2241 if ((mop = vfs_hasopt(omo, imo->mo_list[i].mo_name)) != NULL) {
2243 2242 char **newcanp;
2244 2243 uint_t index = mop - omo->mo_list;
2245 2244
2246 2245 newcanp = vfs_mergecancelopts(mop, &motbl[index]);
2247 2246
2248 2247 vfs_freeopt(&motbl[index]);
2249 2248 vfs_copyopt(&imo->mo_list[i], &motbl[index]);
2250 2249
2251 2250 vfs_freecancelopt(motbl[index].mo_cancel);
2252 2251 motbl[index].mo_cancel = newcanp;
2253 2252 } else {
2254 2253 /*
2255 2254 * If it's a new option, just copy it over to the first
2256 2255 * free location.
2257 2256 */
2258 2257 vfs_copyopt(&imo->mo_list[i], &motbl[freeidx++]);
2259 2258 }
2260 2259 }
2261 2260 dmo->mo_count = count;
2262 2261 dmo->mo_list = motbl;
2263 2262 }
2264 2263
2265 2264 /*
2266 2265 * Functions to set and clear mount options in a mount options table.
2267 2266 */
2268 2267
2269 2268 /*
2270 2269 * Clear a mount option, if it exists.
2271 2270 *
2272 2271 * The update_mnttab arg indicates whether mops is part of a vfs that is on
2273 2272 * the vfs list.
2274 2273 */
2275 2274 static void
2276 2275 vfs_clearmntopt_nolock(mntopts_t *mops, const char *opt, int update_mnttab)
2277 2276 {
2278 2277 struct mntopt *mop;
2279 2278 uint_t i, count;
2280 2279
2281 2280 ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist));
2282 2281
2283 2282 count = mops->mo_count;
2284 2283 for (i = 0; i < count; i++) {
2285 2284 mop = &mops->mo_list[i];
2286 2285
2287 2286 if (mop->mo_flags & MO_EMPTY)
2288 2287 continue;
2289 2288 if (strcmp(opt, mop->mo_name))
2290 2289 continue;
2291 2290 mop->mo_flags &= ~MO_SET;
2292 2291 if (mop->mo_arg != NULL) {
2293 2292 kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
2294 2293 }
2295 2294 mop->mo_arg = NULL;
2296 2295 if (update_mnttab)
2297 2296 vfs_mnttab_modtimeupd();
2298 2297 break;
2299 2298 }
2300 2299 }
2301 2300
2302 2301 void
2303 2302 vfs_clearmntopt(struct vfs *vfsp, const char *opt)
2304 2303 {
2305 2304 int gotlock = 0;
2306 2305
2307 2306 if (VFS_ON_LIST(vfsp)) {
2308 2307 gotlock = 1;
2309 2308 vfs_list_lock();
2310 2309 }
2311 2310 vfs_clearmntopt_nolock(&vfsp->vfs_mntopts, opt, gotlock);
2312 2311 if (gotlock)
2313 2312 vfs_list_unlock();
2314 2313 }
2315 2314
2316 2315
2317 2316 /*
2318 2317 * Set a mount option on. If it's not found in the table, it's silently
2319 2318 * ignored. If the option has MO_IGNORE set, it is still set unless the
2320 2319 * VFS_NOFORCEOPT bit is set in the flags. Also, VFS_DISPLAY/VFS_NODISPLAY flag
2321 2320 * bits can be used to toggle the MO_NODISPLAY bit for the option.
2322 2321 * If the VFS_CREATEOPT flag bit is set then the first option slot with
2323 2322 * MO_EMPTY set is created as the option passed in.
2324 2323 *
2325 2324 * The update_mnttab arg indicates whether mops is part of a vfs that is on
2326 2325 * the vfs list.
2327 2326 */
2328 2327 static void
2329 2328 vfs_setmntopt_nolock(mntopts_t *mops, const char *opt,
2330 2329 const char *arg, int flags, int update_mnttab)
2331 2330 {
2332 2331 mntopt_t *mop;
2333 2332 uint_t i, count;
2334 2333 char *sp;
2335 2334
2336 2335 ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist));
2337 2336
2338 2337 if (flags & VFS_CREATEOPT) {
2339 2338 if (vfs_hasopt(mops, opt) != NULL) {
2340 2339 flags &= ~VFS_CREATEOPT;
2341 2340 }
2342 2341 }
2343 2342 count = mops->mo_count;
2344 2343 for (i = 0; i < count; i++) {
2345 2344 mop = &mops->mo_list[i];
2346 2345
2347 2346 if (mop->mo_flags & MO_EMPTY) {
2348 2347 if ((flags & VFS_CREATEOPT) == 0)
2349 2348 continue;
2350 2349 sp = kmem_alloc(strlen(opt) + 1, KM_SLEEP);
2351 2350 (void) strcpy(sp, opt);
2352 2351 mop->mo_name = sp;
2353 2352 if (arg != NULL)
2354 2353 mop->mo_flags = MO_HASVALUE;
2355 2354 else
2356 2355 mop->mo_flags = 0;
2357 2356 } else if (strcmp(opt, mop->mo_name)) {
2358 2357 continue;
2359 2358 }
2360 2359 if ((mop->mo_flags & MO_IGNORE) && (flags & VFS_NOFORCEOPT))
2361 2360 break;
2362 2361 if (arg != NULL && (mop->mo_flags & MO_HASVALUE) != 0) {
2363 2362 sp = kmem_alloc(strlen(arg) + 1, KM_SLEEP);
2364 2363 (void) strcpy(sp, arg);
2365 2364 } else {
2366 2365 sp = NULL;
2367 2366 }
2368 2367 if (mop->mo_arg != NULL)
2369 2368 kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
2370 2369 mop->mo_arg = sp;
2371 2370 if (flags & VFS_DISPLAY)
2372 2371 mop->mo_flags &= ~MO_NODISPLAY;
2373 2372 if (flags & VFS_NODISPLAY)
2374 2373 mop->mo_flags |= MO_NODISPLAY;
2375 2374 mop->mo_flags |= MO_SET;
2376 2375 if (mop->mo_cancel != NULL) {
2377 2376 char **cp;
2378 2377
2379 2378 for (cp = mop->mo_cancel; *cp != NULL; cp++)
2380 2379 vfs_clearmntopt_nolock(mops, *cp, 0);
2381 2380 }
2382 2381 if (update_mnttab)
2383 2382 vfs_mnttab_modtimeupd();
2384 2383 break;
2385 2384 }
2386 2385 }
2387 2386
2388 2387 void
2389 2388 vfs_setmntopt(struct vfs *vfsp, const char *opt, const char *arg, int flags)
2390 2389 {
2391 2390 int gotlock = 0;
2392 2391
2393 2392 if (VFS_ON_LIST(vfsp)) {
2394 2393 gotlock = 1;
2395 2394 vfs_list_lock();
2396 2395 }
2397 2396 vfs_setmntopt_nolock(&vfsp->vfs_mntopts, opt, arg, flags, gotlock);
2398 2397 if (gotlock)
2399 2398 vfs_list_unlock();
2400 2399 }
2401 2400
2402 2401
2403 2402 /*
2404 2403 * Add a "tag" option to a mounted file system's options list.
2405 2404 *
2406 2405 * Note: caller is responsible for locking the vfs list, if needed,
2407 2406 * to protect mops.
2408 2407 */
2409 2408 static mntopt_t *
2410 2409 vfs_addtag(mntopts_t *mops, const char *tag)
2411 2410 {
2412 2411 uint_t count;
2413 2412 mntopt_t *mop, *motbl;
2414 2413
2415 2414 count = mops->mo_count + 1;
2416 2415 motbl = kmem_zalloc(count * sizeof (mntopt_t), KM_SLEEP);
2417 2416 if (mops->mo_count) {
2418 2417 size_t len = (count - 1) * sizeof (mntopt_t);
2419 2418
2420 2419 bcopy(mops->mo_list, motbl, len);
2421 2420 kmem_free(mops->mo_list, len);
2422 2421 }
2423 2422 mops->mo_count = count;
2424 2423 mops->mo_list = motbl;
2425 2424 mop = &motbl[count - 1];
2426 2425 mop->mo_flags = MO_TAG;
2427 2426 mop->mo_name = kmem_alloc(strlen(tag) + 1, KM_SLEEP);
2428 2427 (void) strcpy(mop->mo_name, tag);
2429 2428 return (mop);
2430 2429 }
2431 2430
2432 2431 /*
2433 2432 * Allow users to set arbitrary "tags" in a vfs's mount options.
2434 2433 * Broader use within the kernel is discouraged.
2435 2434 */
2436 2435 int
2437 2436 vfs_settag(uint_t major, uint_t minor, const char *mntpt, const char *tag,
2438 2437 cred_t *cr)
2439 2438 {
2440 2439 vfs_t *vfsp;
2441 2440 mntopts_t *mops;
2442 2441 mntopt_t *mop;
2443 2442 int found = 0;
2444 2443 dev_t dev = makedevice(major, minor);
2445 2444 int err = 0;
2446 2445 char *buf = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP);
2447 2446
2448 2447 /*
2449 2448 * Find the desired mounted file system
2450 2449 */
2451 2450 vfs_list_lock();
2452 2451 vfsp = rootvfs;
2453 2452 do {
2454 2453 if (vfsp->vfs_dev == dev &&
2455 2454 strcmp(mntpt, refstr_value(vfsp->vfs_mntpt)) == 0) {
2456 2455 found = 1;
2457 2456 break;
2458 2457 }
2459 2458 vfsp = vfsp->vfs_next;
2460 2459 } while (vfsp != rootvfs);
2461 2460
2462 2461 if (!found) {
2463 2462 err = EINVAL;
2464 2463 goto out;
2465 2464 }
2466 2465 err = secpolicy_fs_config(cr, vfsp);
2467 2466 if (err != 0)
2468 2467 goto out;
2469 2468
2470 2469 mops = &vfsp->vfs_mntopts;
2471 2470 /*
2472 2471 * Add tag if it doesn't already exist
2473 2472 */
2474 2473 if ((mop = vfs_hasopt(mops, tag)) == NULL) {
2475 2474 int len;
2476 2475
2477 2476 (void) vfs_buildoptionstr(mops, buf, MAX_MNTOPT_STR);
2478 2477 len = strlen(buf);
2479 2478 if (len + strlen(tag) + 2 > MAX_MNTOPT_STR) {
2480 2479 err = ENAMETOOLONG;
2481 2480 goto out;
2482 2481 }
2483 2482 mop = vfs_addtag(mops, tag);
2484 2483 }
2485 2484 if ((mop->mo_flags & MO_TAG) == 0) {
2486 2485 err = EINVAL;
2487 2486 goto out;
2488 2487 }
2489 2488 vfs_setmntopt_nolock(mops, tag, NULL, 0, 1);
2490 2489 out:
2491 2490 vfs_list_unlock();
2492 2491 kmem_free(buf, MAX_MNTOPT_STR);
2493 2492 return (err);
2494 2493 }
2495 2494
2496 2495 /*
2497 2496 * Allow users to remove arbitrary "tags" in a vfs's mount options.
2498 2497 * Broader use within the kernel is discouraged.
2499 2498 */
2500 2499 int
2501 2500 vfs_clrtag(uint_t major, uint_t minor, const char *mntpt, const char *tag,
2502 2501 cred_t *cr)
2503 2502 {
2504 2503 vfs_t *vfsp;
2505 2504 mntopt_t *mop;
2506 2505 int found = 0;
2507 2506 dev_t dev = makedevice(major, minor);
2508 2507 int err = 0;
2509 2508
2510 2509 /*
2511 2510 * Find the desired mounted file system
2512 2511 */
2513 2512 vfs_list_lock();
2514 2513 vfsp = rootvfs;
2515 2514 do {
2516 2515 if (vfsp->vfs_dev == dev &&
2517 2516 strcmp(mntpt, refstr_value(vfsp->vfs_mntpt)) == 0) {
2518 2517 found = 1;
2519 2518 break;
2520 2519 }
2521 2520 vfsp = vfsp->vfs_next;
2522 2521 } while (vfsp != rootvfs);
2523 2522
2524 2523 if (!found) {
2525 2524 err = EINVAL;
2526 2525 goto out;
2527 2526 }
2528 2527 err = secpolicy_fs_config(cr, vfsp);
2529 2528 if (err != 0)
2530 2529 goto out;
2531 2530
2532 2531 if ((mop = vfs_hasopt(&vfsp->vfs_mntopts, tag)) == NULL) {
2533 2532 err = EINVAL;
2534 2533 goto out;
2535 2534 }
2536 2535 if ((mop->mo_flags & MO_TAG) == 0) {
2537 2536 err = EINVAL;
2538 2537 goto out;
2539 2538 }
2540 2539 vfs_clearmntopt_nolock(&vfsp->vfs_mntopts, tag, 1);
2541 2540 out:
2542 2541 vfs_list_unlock();
2543 2542 return (err);
2544 2543 }
2545 2544
2546 2545 /*
2547 2546 * Function to parse an option string and fill in a mount options table.
2548 2547 * Unknown options are silently ignored. The input option string is modified
2549 2548 * by replacing separators with nulls. If the create flag is set, options
2550 2549 * not found in the table are just added on the fly. The table must have
2551 2550 * an option slot marked MO_EMPTY to add an option on the fly.
2552 2551 *
2553 2552 * This function is *not* for general use by filesystems.
2554 2553 *
2555 2554 * Note: caller is responsible for locking the vfs list, if needed,
2556 2555 * to protect mops..
2557 2556 */
2558 2557 void
2559 2558 vfs_parsemntopts(mntopts_t *mops, char *osp, int create)
2560 2559 {
2561 2560 char *s = osp, *p, *nextop, *valp, *cp, *ep;
2562 2561 int setflg = VFS_NOFORCEOPT;
2563 2562
2564 2563 if (osp == NULL)
2565 2564 return;
2566 2565 while (*s != '\0') {
2567 2566 p = strchr(s, ','); /* find next option */
2568 2567 if (p == NULL) {
2569 2568 cp = NULL;
2570 2569 p = s + strlen(s);
2571 2570 } else {
2572 2571 cp = p; /* save location of comma */
2573 2572 *p++ = '\0'; /* mark end and point to next option */
2574 2573 }
2575 2574 nextop = p;
2576 2575 p = strchr(s, '='); /* look for value */
2577 2576 if (p == NULL) {
2578 2577 valp = NULL; /* no value supplied */
2579 2578 } else {
2580 2579 ep = p; /* save location of equals */
2581 2580 *p++ = '\0'; /* end option and point to value */
2582 2581 valp = p;
2583 2582 }
2584 2583 /*
2585 2584 * set option into options table
2586 2585 */
2587 2586 if (create)
2588 2587 setflg |= VFS_CREATEOPT;
2589 2588 vfs_setmntopt_nolock(mops, s, valp, setflg, 0);
2590 2589 if (cp != NULL)
2591 2590 *cp = ','; /* restore the comma */
2592 2591 if (valp != NULL)
2593 2592 *ep = '='; /* restore the equals */
2594 2593 s = nextop;
2595 2594 }
2596 2595 }
2597 2596
2598 2597 /*
2599 2598 * Function to inquire if an option exists in a mount options table.
2600 2599 * Returns a pointer to the option if it exists, else NULL.
2601 2600 *
2602 2601 * This function is *not* for general use by filesystems.
2603 2602 *
2604 2603 * Note: caller is responsible for locking the vfs list, if needed,
2605 2604 * to protect mops.
2606 2605 */
2607 2606 struct mntopt *
2608 2607 vfs_hasopt(const mntopts_t *mops, const char *opt)
2609 2608 {
2610 2609 struct mntopt *mop;
2611 2610 uint_t i, count;
2612 2611
2613 2612 count = mops->mo_count;
2614 2613 for (i = 0; i < count; i++) {
2615 2614 mop = &mops->mo_list[i];
2616 2615
2617 2616 if (mop->mo_flags & MO_EMPTY)
2618 2617 continue;
2619 2618 if (strcmp(opt, mop->mo_name) == 0)
2620 2619 return (mop);
2621 2620 }
2622 2621 return (NULL);
2623 2622 }
2624 2623
2625 2624 /*
2626 2625 * Function to inquire if an option is set in a mount options table.
2627 2626 * Returns non-zero if set and fills in the arg pointer with a pointer to
2628 2627 * the argument string or NULL if there is no argument string.
2629 2628 */
2630 2629 static int
2631 2630 vfs_optionisset_nolock(const mntopts_t *mops, const char *opt, char **argp)
2632 2631 {
2633 2632 struct mntopt *mop;
2634 2633 uint_t i, count;
2635 2634
2636 2635 count = mops->mo_count;
2637 2636 for (i = 0; i < count; i++) {
2638 2637 mop = &mops->mo_list[i];
2639 2638
2640 2639 if (mop->mo_flags & MO_EMPTY)
2641 2640 continue;
2642 2641 if (strcmp(opt, mop->mo_name))
2643 2642 continue;
2644 2643 if ((mop->mo_flags & MO_SET) == 0)
2645 2644 return (0);
2646 2645 if (argp != NULL && (mop->mo_flags & MO_HASVALUE) != 0)
2647 2646 *argp = mop->mo_arg;
2648 2647 return (1);
2649 2648 }
2650 2649 return (0);
2651 2650 }
2652 2651
2653 2652
2654 2653 int
2655 2654 vfs_optionisset(const struct vfs *vfsp, const char *opt, char **argp)
2656 2655 {
2657 2656 int ret;
2658 2657
2659 2658 vfs_list_read_lock();
2660 2659 ret = vfs_optionisset_nolock(&vfsp->vfs_mntopts, opt, argp);
2661 2660 vfs_list_unlock();
2662 2661 return (ret);
2663 2662 }
2664 2663
2665 2664
2666 2665 /*
2667 2666 * Construct a comma separated string of the options set in the given
2668 2667 * mount table, return the string in the given buffer. Return non-zero if
2669 2668 * the buffer would overflow.
2670 2669 *
2671 2670 * This function is *not* for general use by filesystems.
2672 2671 *
2673 2672 * Note: caller is responsible for locking the vfs list, if needed,
2674 2673 * to protect mp.
2675 2674 */
2676 2675 int
2677 2676 vfs_buildoptionstr(const mntopts_t *mp, char *buf, int len)
2678 2677 {
2679 2678 char *cp;
2680 2679 uint_t i;
2681 2680
2682 2681 buf[0] = '\0';
2683 2682 cp = buf;
2684 2683 for (i = 0; i < mp->mo_count; i++) {
2685 2684 struct mntopt *mop;
2686 2685
2687 2686 mop = &mp->mo_list[i];
2688 2687 if (mop->mo_flags & MO_SET) {
2689 2688 int optlen, comma = 0;
2690 2689
2691 2690 if (buf[0] != '\0')
2692 2691 comma = 1;
2693 2692 optlen = strlen(mop->mo_name);
2694 2693 if (strlen(buf) + comma + optlen + 1 > len)
2695 2694 goto err;
2696 2695 if (comma)
2697 2696 *cp++ = ',';
2698 2697 (void) strcpy(cp, mop->mo_name);
2699 2698 cp += optlen;
2700 2699 /*
2701 2700 * Append option value if there is one
2702 2701 */
2703 2702 if (mop->mo_arg != NULL) {
2704 2703 int arglen;
2705 2704
2706 2705 arglen = strlen(mop->mo_arg);
2707 2706 if (strlen(buf) + arglen + 2 > len)
2708 2707 goto err;
2709 2708 *cp++ = '=';
2710 2709 (void) strcpy(cp, mop->mo_arg);
2711 2710 cp += arglen;
2712 2711 }
2713 2712 }
2714 2713 }
2715 2714 return (0);
2716 2715 err:
2717 2716 return (EOVERFLOW);
2718 2717 }
2719 2718
2720 2719 static void
2721 2720 vfs_freecancelopt(char **moc)
2722 2721 {
2723 2722 if (moc != NULL) {
2724 2723 int ccnt = 0;
2725 2724 char **cp;
2726 2725
2727 2726 for (cp = moc; *cp != NULL; cp++) {
2728 2727 kmem_free(*cp, strlen(*cp) + 1);
2729 2728 ccnt++;
2730 2729 }
2731 2730 kmem_free(moc, (ccnt + 1) * sizeof (char *));
2732 2731 }
2733 2732 }
2734 2733
2735 2734 static void
2736 2735 vfs_freeopt(mntopt_t *mop)
2737 2736 {
2738 2737 if (mop->mo_name != NULL)
2739 2738 kmem_free(mop->mo_name, strlen(mop->mo_name) + 1);
2740 2739
2741 2740 vfs_freecancelopt(mop->mo_cancel);
2742 2741
2743 2742 if (mop->mo_arg != NULL)
2744 2743 kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1);
2745 2744 }
2746 2745
2747 2746 /*
2748 2747 * Free a mount options table
2749 2748 *
2750 2749 * This function is *not* for general use by filesystems.
2751 2750 *
2752 2751 * Note: caller is responsible for locking the vfs list, if needed,
2753 2752 * to protect mp.
2754 2753 */
2755 2754 void
2756 2755 vfs_freeopttbl(mntopts_t *mp)
2757 2756 {
2758 2757 uint_t i, count;
2759 2758
2760 2759 count = mp->mo_count;
2761 2760 for (i = 0; i < count; i++) {
2762 2761 vfs_freeopt(&mp->mo_list[i]);
2763 2762 }
2764 2763 if (count) {
2765 2764 kmem_free(mp->mo_list, sizeof (mntopt_t) * count);
2766 2765 mp->mo_count = 0;
2767 2766 mp->mo_list = NULL;
2768 2767 }
2769 2768 }
2770 2769
2771 2770
2772 2771 /* ARGSUSED */
2773 2772 static int
2774 2773 vfs_mntdummyread(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cred,
2775 2774 caller_context_t *ct)
2776 2775 {
2777 2776 return (0);
2778 2777 }
2779 2778
2780 2779 /* ARGSUSED */
2781 2780 static int
2782 2781 vfs_mntdummywrite(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cred,
2783 2782 caller_context_t *ct)
2784 2783 {
2785 2784 return (0);
2786 2785 }
2787 2786
2788 2787 /*
2789 2788 * The dummy vnode is currently used only by file events notification
2790 2789 * module which is just interested in the timestamps.
2791 2790 */
2792 2791 /* ARGSUSED */
2793 2792 static int
2794 2793 vfs_mntdummygetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
2795 2794 caller_context_t *ct)
2796 2795 {
2797 2796 bzero(vap, sizeof (vattr_t));
2798 2797 vap->va_type = VREG;
2799 2798 vap->va_nlink = 1;
2800 2799 vap->va_ctime = vfs_mnttab_ctime;
2801 2800 /*
2802 2801 * it is ok to just copy mtime as the time will be monotonically
2803 2802 * increasing.
2804 2803 */
2805 2804 vap->va_mtime = vfs_mnttab_mtime;
2806 2805 vap->va_atime = vap->va_mtime;
2807 2806 return (0);
2808 2807 }
2809 2808
2810 2809 static void
2811 2810 vfs_mnttabvp_setup(void)
2812 2811 {
2813 2812 vnode_t *tvp;
2814 2813 vnodeops_t *vfs_mntdummyvnops;
2815 2814 const fs_operation_def_t mnt_dummyvnodeops_template[] = {
2816 2815 VOPNAME_READ, { .vop_read = vfs_mntdummyread },
2817 2816 VOPNAME_WRITE, { .vop_write = vfs_mntdummywrite },
2818 2817 VOPNAME_GETATTR, { .vop_getattr = vfs_mntdummygetattr },
2819 2818 VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support },
2820 2819 NULL, NULL
2821 2820 };
2822 2821
2823 2822 if (vn_make_ops("mnttab", mnt_dummyvnodeops_template,
2824 2823 &vfs_mntdummyvnops) != 0) {
2825 2824 cmn_err(CE_WARN, "vfs_mnttabvp_setup: vn_make_ops failed");
2826 2825 /* Shouldn't happen, but not bad enough to panic */
2827 2826 return;
2828 2827 }
2829 2828
2830 2829 /*
2831 2830 * A global dummy vnode is allocated to represent mntfs files.
2832 2831 * The mntfs file (/etc/mnttab) can be monitored for file events
2833 2832 * and receive an event when mnttab changes. Dummy VOP calls
2834 2833 * will be made on this vnode. The file events notification module
2835 2834 * intercepts this vnode and delivers relevant events.
2836 2835 */
2837 2836 tvp = vn_alloc(KM_SLEEP);
2838 2837 tvp->v_flag = VNOMOUNT|VNOMAP|VNOSWAP|VNOCACHE;
2839 2838 vn_setops(tvp, vfs_mntdummyvnops);
2840 2839 tvp->v_type = VREG;
2841 2840 /*
2842 2841 * The mnt dummy ops do not reference v_data.
2843 2842 * No other module intercepting this vnode should either.
2844 2843 * Just set it to point to itself.
2845 2844 */
2846 2845 tvp->v_data = (caddr_t)tvp;
2847 2846 tvp->v_vfsp = rootvfs;
2848 2847 vfs_mntdummyvp = tvp;
2849 2848 }
2850 2849
2851 2850 /*
2852 2851 * performs fake read/write ops
2853 2852 */
2854 2853 static void
2855 2854 vfs_mnttab_rwop(int rw)
2856 2855 {
2857 2856 struct uio uio;
2858 2857 struct iovec iov;
2859 2858 char buf[1];
2860 2859
2861 2860 if (vfs_mntdummyvp == NULL)
2862 2861 return;
2863 2862
2864 2863 bzero(&uio, sizeof (uio));
2865 2864 bzero(&iov, sizeof (iov));
2866 2865 iov.iov_base = buf;
2867 2866 iov.iov_len = 0;
2868 2867 uio.uio_iov = &iov;
2869 2868 uio.uio_iovcnt = 1;
2870 2869 uio.uio_loffset = 0;
2871 2870 uio.uio_segflg = UIO_SYSSPACE;
2872 2871 uio.uio_resid = 0;
2873 2872 if (rw) {
2874 2873 (void) VOP_WRITE(vfs_mntdummyvp, &uio, 0, kcred, NULL);
2875 2874 } else {
2876 2875 (void) VOP_READ(vfs_mntdummyvp, &uio, 0, kcred, NULL);
2877 2876 }
2878 2877 }
2879 2878
2880 2879 /*
2881 2880 * Generate a write operation.
2882 2881 */
2883 2882 void
2884 2883 vfs_mnttab_writeop(void)
2885 2884 {
2886 2885 vfs_mnttab_rwop(1);
2887 2886 }
2888 2887
2889 2888 /*
2890 2889 * Generate a read operation.
2891 2890 */
2892 2891 void
2893 2892 vfs_mnttab_readop(void)
2894 2893 {
2895 2894 vfs_mnttab_rwop(0);
2896 2895 }
2897 2896
2898 2897 /*
2899 2898 * Free any mnttab information recorded in the vfs struct.
2900 2899 * The vfs must not be on the vfs list.
2901 2900 */
2902 2901 static void
2903 2902 vfs_freemnttab(struct vfs *vfsp)
2904 2903 {
2905 2904 ASSERT(!VFS_ON_LIST(vfsp));
2906 2905
2907 2906 /*
2908 2907 * Free device and mount point information
2909 2908 */
2910 2909 if (vfsp->vfs_mntpt != NULL) {
2911 2910 refstr_rele(vfsp->vfs_mntpt);
2912 2911 vfsp->vfs_mntpt = NULL;
2913 2912 }
2914 2913 if (vfsp->vfs_resource != NULL) {
2915 2914 refstr_rele(vfsp->vfs_resource);
2916 2915 vfsp->vfs_resource = NULL;
2917 2916 }
2918 2917 /*
2919 2918 * Now free mount options information
2920 2919 */
2921 2920 vfs_freeopttbl(&vfsp->vfs_mntopts);
2922 2921 }
2923 2922
2924 2923 /*
2925 2924 * Return the last mnttab modification time
2926 2925 */
2927 2926 void
2928 2927 vfs_mnttab_modtime(timespec_t *ts)
2929 2928 {
2930 2929 ASSERT(RW_LOCK_HELD(&vfslist));
2931 2930 *ts = vfs_mnttab_mtime;
2932 2931 }
2933 2932
2934 2933 /*
2935 2934 * See if mnttab is changed
2936 2935 */
2937 2936 void
2938 2937 vfs_mnttab_poll(timespec_t *old, struct pollhead **phpp)
2939 2938 {
2940 2939 int changed;
2941 2940
2942 2941 *phpp = (struct pollhead *)NULL;
2943 2942
2944 2943 /*
2945 2944 * Note: don't grab vfs list lock before accessing vfs_mnttab_mtime.
2946 2945 * Can lead to deadlock against vfs_mnttab_modtimeupd(). It is safe
2947 2946 * to not grab the vfs list lock because tv_sec is monotonically
2948 2947 * increasing.
2949 2948 */
2950 2949
2951 2950 changed = (old->tv_nsec != vfs_mnttab_mtime.tv_nsec) ||
2952 2951 (old->tv_sec != vfs_mnttab_mtime.tv_sec);
2953 2952 if (!changed) {
2954 2953 *phpp = &vfs_pollhd;
2955 2954 }
2956 2955 }
2957 2956
2958 2957 /* Provide a unique and monotonically-increasing timestamp. */
2959 2958 void
2960 2959 vfs_mono_time(timespec_t *ts)
2961 2960 {
2962 2961 static volatile hrtime_t hrt; /* The saved time. */
2963 2962 hrtime_t newhrt, oldhrt; /* For effecting the CAS. */
2964 2963 timespec_t newts;
2965 2964
2966 2965 /*
2967 2966 * Try gethrestime() first, but be prepared to fabricate a sensible
2968 2967 * answer at the first sign of any trouble.
2969 2968 */
2970 2969 gethrestime(&newts);
2971 2970 newhrt = ts2hrt(&newts);
2972 2971 for (;;) {
2973 2972 oldhrt = hrt;
2974 2973 if (newhrt <= hrt)
2975 2974 newhrt = hrt + 1;
2976 2975 if (atomic_cas_64((uint64_t *)&hrt, oldhrt, newhrt) == oldhrt)
2977 2976 break;
2978 2977 }
2979 2978 hrt2ts(newhrt, ts);
2980 2979 }
2981 2980
2982 2981 /*
2983 2982 * Update the mnttab modification time and wake up any waiters for
2984 2983 * mnttab changes
2985 2984 */
2986 2985 void
2987 2986 vfs_mnttab_modtimeupd()
2988 2987 {
2989 2988 hrtime_t oldhrt, newhrt;
2990 2989
2991 2990 ASSERT(RW_WRITE_HELD(&vfslist));
2992 2991 oldhrt = ts2hrt(&vfs_mnttab_mtime);
2993 2992 gethrestime(&vfs_mnttab_mtime);
2994 2993 newhrt = ts2hrt(&vfs_mnttab_mtime);
2995 2994 if (oldhrt == (hrtime_t)0)
2996 2995 vfs_mnttab_ctime = vfs_mnttab_mtime;
2997 2996 /*
2998 2997 * Attempt to provide unique mtime (like uniqtime but not).
2999 2998 */
3000 2999 if (newhrt == oldhrt) {
3001 3000 newhrt++;
3002 3001 hrt2ts(newhrt, &vfs_mnttab_mtime);
3003 3002 }
3004 3003 pollwakeup(&vfs_pollhd, (short)POLLRDBAND);
3005 3004 vfs_mnttab_writeop();
3006 3005 }
3007 3006
3008 3007 int
3009 3008 dounmount(struct vfs *vfsp, int flag, cred_t *cr)
3010 3009 {
3011 3010 vnode_t *coveredvp;
3012 3011 int error;
3013 3012 extern void teardown_vopstats(vfs_t *);
3014 3013
3015 3014 /*
3016 3015 * Get covered vnode. This will be NULL if the vfs is not linked
3017 3016 * into the file system name space (i.e., domount() with MNT_NOSPICE).
3018 3017 */
3019 3018 coveredvp = vfsp->vfs_vnodecovered;
3020 3019 ASSERT(coveredvp == NULL || vn_vfswlock_held(coveredvp));
3021 3020
3022 3021 /*
3023 3022 * Purge all dnlc entries for this vfs.
3024 3023 */
3025 3024 (void) dnlc_purge_vfsp(vfsp, 0);
3026 3025
3027 3026 /* For forcible umount, skip VFS_SYNC() since it may hang */
3028 3027 if ((flag & MS_FORCE) == 0)
3029 3028 (void) VFS_SYNC(vfsp, 0, cr);
3030 3029
3031 3030 /*
3032 3031 * Lock the vfs to maintain fs status quo during unmount. This
3033 3032 * has to be done after the sync because ufs_update tries to acquire
3034 3033 * the vfs_reflock.
3035 3034 */
3036 3035 vfs_lock_wait(vfsp);
3037 3036
3038 3037 if (error = VFS_UNMOUNT(vfsp, flag, cr)) {
3039 3038 vfs_unlock(vfsp);
3040 3039 if (coveredvp != NULL)
3041 3040 vn_vfsunlock(coveredvp);
3042 3041 } else if (coveredvp != NULL) {
3043 3042 teardown_vopstats(vfsp);
3044 3043 /*
3045 3044 * vfs_remove() will do a VN_RELE(vfsp->vfs_vnodecovered)
3046 3045 * when it frees vfsp so we do a VN_HOLD() so we can
3047 3046 * continue to use coveredvp afterwards.
3048 3047 */
3049 3048 VN_HOLD(coveredvp);
3050 3049 vfs_remove(vfsp);
3051 3050 vn_vfsunlock(coveredvp);
3052 3051 VN_RELE(coveredvp);
3053 3052 } else {
3054 3053 teardown_vopstats(vfsp);
3055 3054 /*
3056 3055 * Release the reference to vfs that is not linked
3057 3056 * into the name space.
3058 3057 */
3059 3058 vfs_unlock(vfsp);
3060 3059 VFS_RELE(vfsp);
3061 3060 }
3062 3061 return (error);
3063 3062 }
3064 3063
3065 3064
3066 3065 /*
3067 3066 * Vfs_unmountall() is called by uadmin() to unmount all
3068 3067 * mounted file systems (except the root file system) during shutdown.
3069 3068 * It follows the existing locking protocol when traversing the vfs list
3070 3069 * to sync and unmount vfses. Even though there should be no
3071 3070 * other thread running while the system is shutting down, it is prudent
3072 3071 * to still follow the locking protocol.
3073 3072 */
3074 3073 void
3075 3074 vfs_unmountall(void)
3076 3075 {
3077 3076 struct vfs *vfsp;
3078 3077 struct vfs *prev_vfsp = NULL;
3079 3078 int error;
3080 3079
3081 3080 /*
3082 3081 * Toss all dnlc entries now so that the per-vfs sync
3083 3082 * and unmount operations don't have to slog through
3084 3083 * a bunch of uninteresting vnodes over and over again.
3085 3084 */
3086 3085 dnlc_purge();
3087 3086
3088 3087 vfs_list_lock();
3089 3088 for (vfsp = rootvfs->vfs_prev; vfsp != rootvfs; vfsp = prev_vfsp) {
3090 3089 prev_vfsp = vfsp->vfs_prev;
3091 3090
3092 3091 if (vfs_lock(vfsp) != 0)
3093 3092 continue;
3094 3093 error = vn_vfswlock(vfsp->vfs_vnodecovered);
3095 3094 vfs_unlock(vfsp);
3096 3095 if (error)
3097 3096 continue;
3098 3097
3099 3098 vfs_list_unlock();
3100 3099
3101 3100 (void) VFS_SYNC(vfsp, SYNC_CLOSE, CRED());
3102 3101 (void) dounmount(vfsp, 0, CRED());
3103 3102
3104 3103 /*
3105 3104 * Since we dropped the vfslist lock above we must
3106 3105 * verify that next_vfsp still exists, else start over.
3107 3106 */
3108 3107 vfs_list_lock();
3109 3108 for (vfsp = rootvfs->vfs_prev;
3110 3109 vfsp != rootvfs; vfsp = vfsp->vfs_prev)
3111 3110 if (vfsp == prev_vfsp)
3112 3111 break;
3113 3112 if (vfsp == rootvfs && prev_vfsp != rootvfs)
3114 3113 prev_vfsp = rootvfs->vfs_prev;
3115 3114 }
3116 3115 vfs_list_unlock();
3117 3116 }
3118 3117
3119 3118 /*
3120 3119 * Called to add an entry to the end of the vfs mount in progress list
3121 3120 */
3122 3121 void
3123 3122 vfs_addmip(dev_t dev, struct vfs *vfsp)
3124 3123 {
3125 3124 struct ipmnt *mipp;
3126 3125
3127 3126 mipp = (struct ipmnt *)kmem_alloc(sizeof (struct ipmnt), KM_SLEEP);
3128 3127 mipp->mip_next = NULL;
3129 3128 mipp->mip_dev = dev;
3130 3129 mipp->mip_vfsp = vfsp;
3131 3130 mutex_enter(&vfs_miplist_mutex);
3132 3131 if (vfs_miplist_end != NULL)
3133 3132 vfs_miplist_end->mip_next = mipp;
3134 3133 else
3135 3134 vfs_miplist = mipp;
3136 3135 vfs_miplist_end = mipp;
3137 3136 mutex_exit(&vfs_miplist_mutex);
3138 3137 }
3139 3138
3140 3139 /*
3141 3140 * Called to remove an entry from the mount in progress list
3142 3141 * Either because the mount completed or it failed.
3143 3142 */
3144 3143 void
3145 3144 vfs_delmip(struct vfs *vfsp)
3146 3145 {
3147 3146 struct ipmnt *mipp, *mipprev;
3148 3147
3149 3148 mutex_enter(&vfs_miplist_mutex);
3150 3149 mipprev = NULL;
3151 3150 for (mipp = vfs_miplist;
3152 3151 mipp && mipp->mip_vfsp != vfsp; mipp = mipp->mip_next) {
3153 3152 mipprev = mipp;
3154 3153 }
3155 3154 if (mipp == NULL)
3156 3155 return; /* shouldn't happen */
3157 3156 if (mipp == vfs_miplist_end)
3158 3157 vfs_miplist_end = mipprev;
3159 3158 if (mipprev == NULL)
3160 3159 vfs_miplist = mipp->mip_next;
3161 3160 else
3162 3161 mipprev->mip_next = mipp->mip_next;
3163 3162 mutex_exit(&vfs_miplist_mutex);
3164 3163 kmem_free(mipp, sizeof (struct ipmnt));
3165 3164 }
3166 3165
3167 3166 /*
3168 3167 * vfs_add is called by a specific filesystem's mount routine to add
3169 3168 * the new vfs into the vfs list/hash and to cover the mounted-on vnode.
3170 3169 * The vfs should already have been locked by the caller.
3171 3170 *
3172 3171 * coveredvp is NULL if this is the root.
3173 3172 */
3174 3173 void
3175 3174 vfs_add(vnode_t *coveredvp, struct vfs *vfsp, int mflag)
3176 3175 {
3177 3176 int newflag;
3178 3177
3179 3178 ASSERT(vfs_lock_held(vfsp));
3180 3179 VFS_HOLD(vfsp);
3181 3180 newflag = vfsp->vfs_flag;
3182 3181 if (mflag & MS_RDONLY)
3183 3182 newflag |= VFS_RDONLY;
3184 3183 else
3185 3184 newflag &= ~VFS_RDONLY;
3186 3185 if (mflag & MS_NOSUID)
3187 3186 newflag |= (VFS_NOSETUID|VFS_NODEVICES);
3188 3187 else
3189 3188 newflag &= ~(VFS_NOSETUID|VFS_NODEVICES);
3190 3189 if (mflag & MS_NOMNTTAB)
3191 3190 newflag |= VFS_NOMNTTAB;
3192 3191 else
3193 3192 newflag &= ~VFS_NOMNTTAB;
3194 3193
3195 3194 if (coveredvp != NULL) {
3196 3195 ASSERT(vn_vfswlock_held(coveredvp));
3197 3196 coveredvp->v_vfsmountedhere = vfsp;
3198 3197 VN_HOLD(coveredvp);
3199 3198 }
3200 3199 vfsp->vfs_vnodecovered = coveredvp;
3201 3200 vfsp->vfs_flag = newflag;
3202 3201
3203 3202 vfs_list_add(vfsp);
3204 3203 }
3205 3204
3206 3205 /*
3207 3206 * Remove a vfs from the vfs list, null out the pointer from the
3208 3207 * covered vnode to the vfs (v_vfsmountedhere), and null out the pointer
3209 3208 * from the vfs to the covered vnode (vfs_vnodecovered). Release the
3210 3209 * reference to the vfs and to the covered vnode.
3211 3210 *
3212 3211 * Called from dounmount after it's confirmed with the file system
3213 3212 * that the unmount is legal.
3214 3213 */
3215 3214 void
3216 3215 vfs_remove(struct vfs *vfsp)
3217 3216 {
3218 3217 vnode_t *vp;
3219 3218
3220 3219 ASSERT(vfs_lock_held(vfsp));
3221 3220
3222 3221 /*
3223 3222 * Can't unmount root. Should never happen because fs will
3224 3223 * be busy.
3225 3224 */
3226 3225 if (vfsp == rootvfs)
3227 3226 panic("vfs_remove: unmounting root");
3228 3227
3229 3228 vfs_list_remove(vfsp);
3230 3229
3231 3230 /*
3232 3231 * Unhook from the file system name space.
3233 3232 */
3234 3233 vp = vfsp->vfs_vnodecovered;
3235 3234 ASSERT(vn_vfswlock_held(vp));
3236 3235 vp->v_vfsmountedhere = NULL;
3237 3236 vfsp->vfs_vnodecovered = NULL;
3238 3237 VN_RELE(vp);
3239 3238
3240 3239 /*
3241 3240 * Release lock and wakeup anybody waiting.
3242 3241 */
3243 3242 vfs_unlock(vfsp);
3244 3243 VFS_RELE(vfsp);
3245 3244 }
3246 3245
3247 3246 /*
3248 3247 * Lock a filesystem to prevent access to it while mounting,
3249 3248 * unmounting and syncing. Return EBUSY immediately if lock
3250 3249 * can't be acquired.
3251 3250 */
3252 3251 int
3253 3252 vfs_lock(vfs_t *vfsp)
3254 3253 {
3255 3254 vn_vfslocks_entry_t *vpvfsentry;
3256 3255
3257 3256 vpvfsentry = vn_vfslocks_getlock(vfsp);
3258 3257 if (rwst_tryenter(&vpvfsentry->ve_lock, RW_WRITER))
3259 3258 return (0);
3260 3259
3261 3260 vn_vfslocks_rele(vpvfsentry);
3262 3261 return (EBUSY);
3263 3262 }
3264 3263
3265 3264 int
3266 3265 vfs_rlock(vfs_t *vfsp)
3267 3266 {
3268 3267 vn_vfslocks_entry_t *vpvfsentry;
3269 3268
3270 3269 vpvfsentry = vn_vfslocks_getlock(vfsp);
3271 3270
3272 3271 if (rwst_tryenter(&vpvfsentry->ve_lock, RW_READER))
3273 3272 return (0);
3274 3273
3275 3274 vn_vfslocks_rele(vpvfsentry);
3276 3275 return (EBUSY);
3277 3276 }
3278 3277
3279 3278 void
3280 3279 vfs_lock_wait(vfs_t *vfsp)
3281 3280 {
3282 3281 vn_vfslocks_entry_t *vpvfsentry;
3283 3282
3284 3283 vpvfsentry = vn_vfslocks_getlock(vfsp);
3285 3284 rwst_enter(&vpvfsentry->ve_lock, RW_WRITER);
3286 3285 }
3287 3286
3288 3287 void
3289 3288 vfs_rlock_wait(vfs_t *vfsp)
3290 3289 {
3291 3290 vn_vfslocks_entry_t *vpvfsentry;
3292 3291
3293 3292 vpvfsentry = vn_vfslocks_getlock(vfsp);
3294 3293 rwst_enter(&vpvfsentry->ve_lock, RW_READER);
3295 3294 }
3296 3295
3297 3296 /*
3298 3297 * Unlock a locked filesystem.
3299 3298 */
3300 3299 void
3301 3300 vfs_unlock(vfs_t *vfsp)
3302 3301 {
3303 3302 vn_vfslocks_entry_t *vpvfsentry;
3304 3303
3305 3304 /*
3306 3305 * vfs_unlock will mimic sema_v behaviour to fix 4748018.
3307 3306 * And these changes should remain for the patch changes as it is.
3308 3307 */
3309 3308 if (panicstr)
3310 3309 return;
3311 3310
3312 3311 /*
3313 3312 * ve_refcount needs to be dropped twice here.
3314 3313 * 1. To release refernce after a call to vfs_locks_getlock()
3315 3314 * 2. To release the reference from the locking routines like
3316 3315 * vfs_rlock_wait/vfs_wlock_wait/vfs_wlock etc,.
3317 3316 */
3318 3317
3319 3318 vpvfsentry = vn_vfslocks_getlock(vfsp);
3320 3319 vn_vfslocks_rele(vpvfsentry);
3321 3320
3322 3321 rwst_exit(&vpvfsentry->ve_lock);
3323 3322 vn_vfslocks_rele(vpvfsentry);
3324 3323 }
3325 3324
3326 3325 /*
3327 3326 * Utility routine that allows a filesystem to construct its
3328 3327 * fsid in "the usual way" - by munging some underlying dev_t and
3329 3328 * the filesystem type number into the 64-bit fsid. Note that
3330 3329 * this implicitly relies on dev_t persistence to make filesystem
3331 3330 * id's persistent.
3332 3331 *
3333 3332 * There's nothing to prevent an individual fs from constructing its
3334 3333 * fsid in a different way, and indeed they should.
3335 3334 *
3336 3335 * Since we want fsids to be 32-bit quantities (so that they can be
3337 3336 * exported identically by either 32-bit or 64-bit APIs, as well as
3338 3337 * the fact that fsid's are "known" to NFS), we compress the device
3339 3338 * number given down to 32-bits, and panic if that isn't possible.
3340 3339 */
3341 3340 void
3342 3341 vfs_make_fsid(fsid_t *fsi, dev_t dev, int val)
3343 3342 {
3344 3343 if (!cmpldev((dev32_t *)&fsi->val[0], dev))
3345 3344 panic("device number too big for fsid!");
3346 3345 fsi->val[1] = val;
3347 3346 }
3348 3347
3349 3348 int
3350 3349 vfs_lock_held(vfs_t *vfsp)
3351 3350 {
3352 3351 int held;
3353 3352 vn_vfslocks_entry_t *vpvfsentry;
3354 3353
3355 3354 /*
3356 3355 * vfs_lock_held will mimic sema_held behaviour
3357 3356 * if panicstr is set. And these changes should remain
3358 3357 * for the patch changes as it is.
3359 3358 */
3360 3359 if (panicstr)
3361 3360 return (1);
3362 3361
3363 3362 vpvfsentry = vn_vfslocks_getlock(vfsp);
3364 3363 held = rwst_lock_held(&vpvfsentry->ve_lock, RW_WRITER);
3365 3364
3366 3365 vn_vfslocks_rele(vpvfsentry);
3367 3366 return (held);
3368 3367 }
3369 3368
3370 3369 struct _kthread *
3371 3370 vfs_lock_owner(vfs_t *vfsp)
3372 3371 {
3373 3372 struct _kthread *owner;
3374 3373 vn_vfslocks_entry_t *vpvfsentry;
3375 3374
3376 3375 /*
3377 3376 * vfs_wlock_held will mimic sema_held behaviour
3378 3377 * if panicstr is set. And these changes should remain
3379 3378 * for the patch changes as it is.
3380 3379 */
3381 3380 if (panicstr)
3382 3381 return (NULL);
3383 3382
3384 3383 vpvfsentry = vn_vfslocks_getlock(vfsp);
3385 3384 owner = rwst_owner(&vpvfsentry->ve_lock);
3386 3385
3387 3386 vn_vfslocks_rele(vpvfsentry);
3388 3387 return (owner);
3389 3388 }
3390 3389
3391 3390 /*
3392 3391 * vfs list locking.
3393 3392 *
3394 3393 * Rather than manipulate the vfslist lock directly, we abstract into lock
3395 3394 * and unlock routines to allow the locking implementation to be changed for
3396 3395 * clustering.
3397 3396 *
3398 3397 * Whenever the vfs list is modified through its hash links, the overall list
3399 3398 * lock must be obtained before locking the relevant hash bucket. But to see
3400 3399 * whether a given vfs is on the list, it suffices to obtain the lock for the
3401 3400 * hash bucket without getting the overall list lock. (See getvfs() below.)
3402 3401 */
3403 3402
3404 3403 void
3405 3404 vfs_list_lock()
3406 3405 {
3407 3406 rw_enter(&vfslist, RW_WRITER);
3408 3407 }
3409 3408
3410 3409 void
3411 3410 vfs_list_read_lock()
3412 3411 {
3413 3412 rw_enter(&vfslist, RW_READER);
3414 3413 }
3415 3414
3416 3415 void
3417 3416 vfs_list_unlock()
3418 3417 {
3419 3418 rw_exit(&vfslist);
3420 3419 }
3421 3420
3422 3421 /*
3423 3422 * Low level worker routines for adding entries to and removing entries from
3424 3423 * the vfs list.
3425 3424 */
3426 3425
3427 3426 static void
3428 3427 vfs_hash_add(struct vfs *vfsp, int insert_at_head)
3429 3428 {
3430 3429 int vhno;
3431 3430 struct vfs **hp;
3432 3431 dev_t dev;
3433 3432
3434 3433 ASSERT(RW_WRITE_HELD(&vfslist));
3435 3434
3436 3435 dev = expldev(vfsp->vfs_fsid.val[0]);
3437 3436 vhno = VFSHASH(getmajor(dev), getminor(dev));
3438 3437
3439 3438 mutex_enter(&rvfs_list[vhno].rvfs_lock);
3440 3439
3441 3440 /*
3442 3441 * Link into the hash table, inserting it at the end, so that LOFS
3443 3442 * with the same fsid as UFS (or other) file systems will not hide the
3444 3443 * UFS.
3445 3444 */
3446 3445 if (insert_at_head) {
3447 3446 vfsp->vfs_hash = rvfs_list[vhno].rvfs_head;
3448 3447 rvfs_list[vhno].rvfs_head = vfsp;
3449 3448 } else {
3450 3449 for (hp = &rvfs_list[vhno].rvfs_head; *hp != NULL;
3451 3450 hp = &(*hp)->vfs_hash)
3452 3451 continue;
3453 3452 /*
3454 3453 * hp now contains the address of the pointer to update
3455 3454 * to effect the insertion.
3456 3455 */
3457 3456 vfsp->vfs_hash = NULL;
3458 3457 *hp = vfsp;
3459 3458 }
3460 3459
3461 3460 rvfs_list[vhno].rvfs_len++;
3462 3461 mutex_exit(&rvfs_list[vhno].rvfs_lock);
3463 3462 }
3464 3463
3465 3464
3466 3465 static void
3467 3466 vfs_hash_remove(struct vfs *vfsp)
3468 3467 {
3469 3468 int vhno;
3470 3469 struct vfs *tvfsp;
3471 3470 dev_t dev;
3472 3471
3473 3472 ASSERT(RW_WRITE_HELD(&vfslist));
3474 3473
3475 3474 dev = expldev(vfsp->vfs_fsid.val[0]);
3476 3475 vhno = VFSHASH(getmajor(dev), getminor(dev));
3477 3476
3478 3477 mutex_enter(&rvfs_list[vhno].rvfs_lock);
3479 3478
3480 3479 /*
3481 3480 * Remove from hash.
3482 3481 */
3483 3482 if (rvfs_list[vhno].rvfs_head == vfsp) {
3484 3483 rvfs_list[vhno].rvfs_head = vfsp->vfs_hash;
3485 3484 rvfs_list[vhno].rvfs_len--;
3486 3485 goto foundit;
3487 3486 }
3488 3487 for (tvfsp = rvfs_list[vhno].rvfs_head; tvfsp != NULL;
3489 3488 tvfsp = tvfsp->vfs_hash) {
3490 3489 if (tvfsp->vfs_hash == vfsp) {
3491 3490 tvfsp->vfs_hash = vfsp->vfs_hash;
3492 3491 rvfs_list[vhno].rvfs_len--;
3493 3492 goto foundit;
3494 3493 }
3495 3494 }
3496 3495 cmn_err(CE_WARN, "vfs_list_remove: vfs not found in hash");
3497 3496
3498 3497 foundit:
3499 3498
3500 3499 mutex_exit(&rvfs_list[vhno].rvfs_lock);
3501 3500 }
3502 3501
3503 3502
3504 3503 void
3505 3504 vfs_list_add(struct vfs *vfsp)
3506 3505 {
3507 3506 zone_t *zone;
3508 3507
3509 3508 /*
3510 3509 * Typically, the vfs_t will have been created on behalf of the file
3511 3510 * system in vfs_init, where it will have been provided with a
3512 3511 * vfs_impl_t. This, however, might be lacking if the vfs_t was created
3513 3512 * by an unbundled file system. We therefore check for such an example
3514 3513 * before stamping the vfs_t with its creation time for the benefit of
3515 3514 * mntfs.
3516 3515 */
3517 3516 if (vfsp->vfs_implp == NULL)
3518 3517 vfsimpl_setup(vfsp);
3519 3518 vfs_mono_time(&vfsp->vfs_hrctime);
3520 3519
3521 3520 /*
3522 3521 * The zone that owns the mount is the one that performed the mount.
3523 3522 * Note that this isn't necessarily the same as the zone mounted into.
3524 3523 * The corresponding zone_rele_ref() will be done when the vfs_t
3525 3524 * is being free'd.
3526 3525 */
3527 3526 vfsp->vfs_zone = curproc->p_zone;
3528 3527 zone_init_ref(&vfsp->vfs_implp->vi_zone_ref);
3529 3528 zone_hold_ref(vfsp->vfs_zone, &vfsp->vfs_implp->vi_zone_ref,
3530 3529 ZONE_REF_VFS);
3531 3530
3532 3531 /*
3533 3532 * Find the zone mounted into, and put this mount on its vfs list.
3534 3533 */
3535 3534 zone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
3536 3535 ASSERT(zone != NULL);
3537 3536 /*
3538 3537 * Special casing for the root vfs. This structure is allocated
3539 3538 * statically and hooked onto rootvfs at link time. During the
3540 3539 * vfs_mountroot call at system startup time, the root file system's
3541 3540 * VFS_MOUNTROOT routine will call vfs_add with this root vfs struct
3542 3541 * as argument. The code below must detect and handle this special
3543 3542 * case. The only apparent justification for this special casing is
3544 3543 * to ensure that the root file system appears at the head of the
3545 3544 * list.
3546 3545 *
3547 3546 * XXX: I'm assuming that it's ok to do normal list locking when
3548 3547 * adding the entry for the root file system (this used to be
3549 3548 * done with no locks held).
3550 3549 */
3551 3550 vfs_list_lock();
3552 3551 /*
3553 3552 * Link into the vfs list proper.
3554 3553 */
3555 3554 if (vfsp == &root) {
3556 3555 /*
3557 3556 * Assert: This vfs is already on the list as its first entry.
3558 3557 * Thus, there's nothing to do.
3559 3558 */
3560 3559 ASSERT(rootvfs == vfsp);
3561 3560 /*
3562 3561 * Add it to the head of the global zone's vfslist.
3563 3562 */
3564 3563 ASSERT(zone == global_zone);
3565 3564 ASSERT(zone->zone_vfslist == NULL);
3566 3565 zone->zone_vfslist = vfsp;
3567 3566 } else {
3568 3567 /*
3569 3568 * Link to end of list using vfs_prev (as rootvfs is now a
3570 3569 * doubly linked circular list) so list is in mount order for
3571 3570 * mnttab use.
3572 3571 */
3573 3572 rootvfs->vfs_prev->vfs_next = vfsp;
3574 3573 vfsp->vfs_prev = rootvfs->vfs_prev;
3575 3574 rootvfs->vfs_prev = vfsp;
3576 3575 vfsp->vfs_next = rootvfs;
3577 3576
3578 3577 /*
3579 3578 * Do it again for the zone-private list (which may be NULL).
3580 3579 */
3581 3580 if (zone->zone_vfslist == NULL) {
3582 3581 ASSERT(zone != global_zone);
3583 3582 zone->zone_vfslist = vfsp;
3584 3583 } else {
3585 3584 zone->zone_vfslist->vfs_zone_prev->vfs_zone_next = vfsp;
3586 3585 vfsp->vfs_zone_prev = zone->zone_vfslist->vfs_zone_prev;
3587 3586 zone->zone_vfslist->vfs_zone_prev = vfsp;
3588 3587 vfsp->vfs_zone_next = zone->zone_vfslist;
3589 3588 }
3590 3589 }
3591 3590
3592 3591 /*
3593 3592 * Link into the hash table, inserting it at the end, so that LOFS
3594 3593 * with the same fsid as UFS (or other) file systems will not hide
3595 3594 * the UFS.
3596 3595 */
3597 3596 vfs_hash_add(vfsp, 0);
3598 3597
3599 3598 /*
3600 3599 * update the mnttab modification time
3601 3600 */
3602 3601 vfs_mnttab_modtimeupd();
3603 3602 vfs_list_unlock();
3604 3603 zone_rele(zone);
3605 3604 }
3606 3605
3607 3606 void
3608 3607 vfs_list_remove(struct vfs *vfsp)
3609 3608 {
3610 3609 zone_t *zone;
3611 3610
3612 3611 zone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
3613 3612 ASSERT(zone != NULL);
3614 3613 /*
3615 3614 * Callers are responsible for preventing attempts to unmount the
3616 3615 * root.
3617 3616 */
3618 3617 ASSERT(vfsp != rootvfs);
3619 3618
3620 3619 vfs_list_lock();
3621 3620
3622 3621 /*
3623 3622 * Remove from hash.
3624 3623 */
3625 3624 vfs_hash_remove(vfsp);
3626 3625
3627 3626 /*
3628 3627 * Remove from vfs list.
3629 3628 */
3630 3629 vfsp->vfs_prev->vfs_next = vfsp->vfs_next;
3631 3630 vfsp->vfs_next->vfs_prev = vfsp->vfs_prev;
3632 3631 vfsp->vfs_next = vfsp->vfs_prev = NULL;
3633 3632
3634 3633 /*
3635 3634 * Remove from zone-specific vfs list.
3636 3635 */
3637 3636 if (zone->zone_vfslist == vfsp)
3638 3637 zone->zone_vfslist = vfsp->vfs_zone_next;
3639 3638
3640 3639 if (vfsp->vfs_zone_next == vfsp) {
3641 3640 ASSERT(vfsp->vfs_zone_prev == vfsp);
3642 3641 ASSERT(zone->zone_vfslist == vfsp);
3643 3642 zone->zone_vfslist = NULL;
3644 3643 }
3645 3644
3646 3645 vfsp->vfs_zone_prev->vfs_zone_next = vfsp->vfs_zone_next;
3647 3646 vfsp->vfs_zone_next->vfs_zone_prev = vfsp->vfs_zone_prev;
3648 3647 vfsp->vfs_zone_next = vfsp->vfs_zone_prev = NULL;
3649 3648
3650 3649 /*
3651 3650 * update the mnttab modification time
3652 3651 */
3653 3652 vfs_mnttab_modtimeupd();
3654 3653 vfs_list_unlock();
3655 3654 zone_rele(zone);
3656 3655 }
3657 3656
3658 3657 struct vfs *
3659 3658 getvfs(fsid_t *fsid)
3660 3659 {
3661 3660 struct vfs *vfsp;
3662 3661 int val0 = fsid->val[0];
3663 3662 int val1 = fsid->val[1];
3664 3663 dev_t dev = expldev(val0);
3665 3664 int vhno = VFSHASH(getmajor(dev), getminor(dev));
3666 3665 kmutex_t *hmp = &rvfs_list[vhno].rvfs_lock;
3667 3666
3668 3667 mutex_enter(hmp);
3669 3668 for (vfsp = rvfs_list[vhno].rvfs_head; vfsp; vfsp = vfsp->vfs_hash) {
3670 3669 if (vfsp->vfs_fsid.val[0] == val0 &&
3671 3670 vfsp->vfs_fsid.val[1] == val1) {
3672 3671 VFS_HOLD(vfsp);
3673 3672 mutex_exit(hmp);
3674 3673 return (vfsp);
3675 3674 }
3676 3675 }
3677 3676 mutex_exit(hmp);
3678 3677 return (NULL);
3679 3678 }
3680 3679
3681 3680 /*
3682 3681 * Search the vfs mount in progress list for a specified device/vfs entry.
3683 3682 * Returns 0 if the first entry in the list that the device matches has the
3684 3683 * given vfs pointer as well. If the device matches but a different vfs
3685 3684 * pointer is encountered in the list before the given vfs pointer then
3686 3685 * a 1 is returned.
3687 3686 */
3688 3687
3689 3688 int
3690 3689 vfs_devmounting(dev_t dev, struct vfs *vfsp)
3691 3690 {
3692 3691 int retval = 0;
3693 3692 struct ipmnt *mipp;
3694 3693
3695 3694 mutex_enter(&vfs_miplist_mutex);
3696 3695 for (mipp = vfs_miplist; mipp != NULL; mipp = mipp->mip_next) {
3697 3696 if (mipp->mip_dev == dev) {
3698 3697 if (mipp->mip_vfsp != vfsp)
3699 3698 retval = 1;
3700 3699 break;
3701 3700 }
3702 3701 }
3703 3702 mutex_exit(&vfs_miplist_mutex);
3704 3703 return (retval);
3705 3704 }
3706 3705
3707 3706 /*
3708 3707 * Search the vfs list for a specified device. Returns 1, if entry is found
3709 3708 * or 0 if no suitable entry is found.
3710 3709 */
3711 3710
3712 3711 int
3713 3712 vfs_devismounted(dev_t dev)
3714 3713 {
3715 3714 struct vfs *vfsp;
3716 3715 int found;
3717 3716
3718 3717 vfs_list_read_lock();
3719 3718 vfsp = rootvfs;
3720 3719 found = 0;
3721 3720 do {
3722 3721 if (vfsp->vfs_dev == dev) {
3723 3722 found = 1;
3724 3723 break;
3725 3724 }
3726 3725 vfsp = vfsp->vfs_next;
3727 3726 } while (vfsp != rootvfs);
3728 3727
3729 3728 vfs_list_unlock();
3730 3729 return (found);
3731 3730 }
3732 3731
3733 3732 /*
3734 3733 * Search the vfs list for a specified device. Returns a pointer to it
3735 3734 * or NULL if no suitable entry is found. The caller of this routine
3736 3735 * is responsible for releasing the returned vfs pointer.
3737 3736 */
3738 3737 struct vfs *
3739 3738 vfs_dev2vfsp(dev_t dev)
3740 3739 {
3741 3740 struct vfs *vfsp;
3742 3741 int found;
3743 3742
3744 3743 vfs_list_read_lock();
3745 3744 vfsp = rootvfs;
3746 3745 found = 0;
3747 3746 do {
3748 3747 /*
3749 3748 * The following could be made more efficient by making
3750 3749 * the entire loop use vfs_zone_next if the call is from
3751 3750 * a zone. The only callers, however, ustat(2) and
3752 3751 * umount2(2), don't seem to justify the added
3753 3752 * complexity at present.
3754 3753 */
3755 3754 if (vfsp->vfs_dev == dev &&
3756 3755 ZONE_PATH_VISIBLE(refstr_value(vfsp->vfs_mntpt),
3757 3756 curproc->p_zone)) {
3758 3757 VFS_HOLD(vfsp);
3759 3758 found = 1;
3760 3759 break;
3761 3760 }
3762 3761 vfsp = vfsp->vfs_next;
3763 3762 } while (vfsp != rootvfs);
3764 3763 vfs_list_unlock();
3765 3764 return (found ? vfsp: NULL);
3766 3765 }
3767 3766
3768 3767 /*
3769 3768 * Search the vfs list for a specified mntpoint. Returns a pointer to it
3770 3769 * or NULL if no suitable entry is found. The caller of this routine
3771 3770 * is responsible for releasing the returned vfs pointer.
3772 3771 *
3773 3772 * Note that if multiple mntpoints match, the last one matching is
3774 3773 * returned in an attempt to return the "top" mount when overlay
3775 3774 * mounts are covering the same mount point. This is accomplished by starting
3776 3775 * at the end of the list and working our way backwards, stopping at the first
3777 3776 * matching mount.
3778 3777 */
3779 3778 struct vfs *
3780 3779 vfs_mntpoint2vfsp(const char *mp)
3781 3780 {
3782 3781 struct vfs *vfsp;
3783 3782 struct vfs *retvfsp = NULL;
3784 3783 zone_t *zone = curproc->p_zone;
3785 3784 struct vfs *list;
3786 3785
3787 3786 vfs_list_read_lock();
3788 3787 if (getzoneid() == GLOBAL_ZONEID) {
3789 3788 /*
3790 3789 * The global zone may see filesystems in any zone.
3791 3790 */
3792 3791 vfsp = rootvfs->vfs_prev;
3793 3792 do {
3794 3793 if (strcmp(refstr_value(vfsp->vfs_mntpt), mp) == 0) {
3795 3794 retvfsp = vfsp;
3796 3795 break;
3797 3796 }
3798 3797 vfsp = vfsp->vfs_prev;
3799 3798 } while (vfsp != rootvfs->vfs_prev);
3800 3799 } else if ((list = zone->zone_vfslist) != NULL) {
3801 3800 const char *mntpt;
3802 3801
3803 3802 vfsp = list->vfs_zone_prev;
3804 3803 do {
3805 3804 mntpt = refstr_value(vfsp->vfs_mntpt);
3806 3805 mntpt = ZONE_PATH_TRANSLATE(mntpt, zone);
3807 3806 if (strcmp(mntpt, mp) == 0) {
3808 3807 retvfsp = vfsp;
3809 3808 break;
3810 3809 }
3811 3810 vfsp = vfsp->vfs_zone_prev;
3812 3811 } while (vfsp != list->vfs_zone_prev);
3813 3812 }
3814 3813 if (retvfsp)
3815 3814 VFS_HOLD(retvfsp);
3816 3815 vfs_list_unlock();
3817 3816 return (retvfsp);
3818 3817 }
3819 3818
3820 3819 /*
3821 3820 * Search the vfs list for a specified vfsops.
3822 3821 * if vfs entry is found then return 1, else 0.
3823 3822 */
3824 3823 int
3825 3824 vfs_opsinuse(vfsops_t *ops)
3826 3825 {
3827 3826 struct vfs *vfsp;
3828 3827 int found;
3829 3828
3830 3829 vfs_list_read_lock();
3831 3830 vfsp = rootvfs;
3832 3831 found = 0;
3833 3832 do {
3834 3833 if (vfs_getops(vfsp) == ops) {
3835 3834 found = 1;
3836 3835 break;
3837 3836 }
3838 3837 vfsp = vfsp->vfs_next;
3839 3838 } while (vfsp != rootvfs);
3840 3839 vfs_list_unlock();
3841 3840 return (found);
3842 3841 }
3843 3842
3844 3843 /*
3845 3844 * Allocate an entry in vfssw for a file system type
3846 3845 */
3847 3846 struct vfssw *
3848 3847 allocate_vfssw(const char *type)
3849 3848 {
3850 3849 struct vfssw *vswp;
3851 3850
3852 3851 if (type[0] == '\0' || strlen(type) + 1 > _ST_FSTYPSZ) {
3853 3852 /*
3854 3853 * The vfssw table uses the empty string to identify an
3855 3854 * available entry; we cannot add any type which has
3856 3855 * a leading NUL. The string length is limited to
3857 3856 * the size of the st_fstype array in struct stat.
3858 3857 */
3859 3858 return (NULL);
3860 3859 }
3861 3860
3862 3861 ASSERT(VFSSW_WRITE_LOCKED());
3863 3862 for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++)
3864 3863 if (!ALLOCATED_VFSSW(vswp)) {
3865 3864 vswp->vsw_name = kmem_alloc(strlen(type) + 1, KM_SLEEP);
3866 3865 (void) strcpy(vswp->vsw_name, type);
3867 3866 ASSERT(vswp->vsw_count == 0);
3868 3867 vswp->vsw_count = 1;
3869 3868 mutex_init(&vswp->vsw_lock, NULL, MUTEX_DEFAULT, NULL);
3870 3869 return (vswp);
3871 3870 }
3872 3871 return (NULL);
3873 3872 }
3874 3873
3875 3874 /*
3876 3875 * Impose additional layer of translation between vfstype names
3877 3876 * and module names in the filesystem.
3878 3877 */
3879 3878 static const char *
3880 3879 vfs_to_modname(const char *vfstype)
3881 3880 {
3882 3881 if (strcmp(vfstype, "proc") == 0) {
3883 3882 vfstype = "procfs";
3884 3883 } else if (strcmp(vfstype, "fd") == 0) {
3885 3884 vfstype = "fdfs";
3886 3885 } else if (strncmp(vfstype, "nfs", 3) == 0) {
3887 3886 vfstype = "nfs";
3888 3887 }
3889 3888
3890 3889 return (vfstype);
3891 3890 }
3892 3891
3893 3892 /*
3894 3893 * Find a vfssw entry given a file system type name.
3895 3894 * Try to autoload the filesystem if it's not found.
3896 3895 * If it's installed, return the vfssw locked to prevent unloading.
3897 3896 */
3898 3897 struct vfssw *
3899 3898 vfs_getvfssw(const char *type)
3900 3899 {
3901 3900 struct vfssw *vswp;
3902 3901 const char *modname;
3903 3902
3904 3903 RLOCK_VFSSW();
3905 3904 vswp = vfs_getvfsswbyname(type);
3906 3905 modname = vfs_to_modname(type);
3907 3906
3908 3907 if (rootdir == NULL) {
3909 3908 /*
3910 3909 * If we haven't yet loaded the root file system, then our
3911 3910 * _init won't be called until later. Allocate vfssw entry,
3912 3911 * because mod_installfs won't be called.
3913 3912 */
3914 3913 if (vswp == NULL) {
3915 3914 RUNLOCK_VFSSW();
3916 3915 WLOCK_VFSSW();
3917 3916 if ((vswp = vfs_getvfsswbyname(type)) == NULL) {
3918 3917 if ((vswp = allocate_vfssw(type)) == NULL) {
3919 3918 WUNLOCK_VFSSW();
3920 3919 return (NULL);
3921 3920 }
3922 3921 }
3923 3922 WUNLOCK_VFSSW();
3924 3923 RLOCK_VFSSW();
3925 3924 }
3926 3925 if (!VFS_INSTALLED(vswp)) {
3927 3926 RUNLOCK_VFSSW();
3928 3927 (void) modloadonly("fs", modname);
3929 3928 } else
3930 3929 RUNLOCK_VFSSW();
3931 3930 return (vswp);
3932 3931 }
3933 3932
3934 3933 /*
3935 3934 * Try to load the filesystem. Before calling modload(), we drop
3936 3935 * our lock on the VFS switch table, and pick it up after the
3937 3936 * module is loaded. However, there is a potential race: the
3938 3937 * module could be unloaded after the call to modload() completes
3939 3938 * but before we pick up the lock and drive on. Therefore,
3940 3939 * we keep reloading the module until we've loaded the module
3941 3940 * _and_ we have the lock on the VFS switch table.
3942 3941 */
3943 3942 while (vswp == NULL || !VFS_INSTALLED(vswp)) {
3944 3943 RUNLOCK_VFSSW();
3945 3944 if (modload("fs", modname) == -1)
3946 3945 return (NULL);
3947 3946 RLOCK_VFSSW();
3948 3947 if (vswp == NULL)
3949 3948 if ((vswp = vfs_getvfsswbyname(type)) == NULL)
3950 3949 break;
3951 3950 }
3952 3951 RUNLOCK_VFSSW();
3953 3952
3954 3953 return (vswp);
3955 3954 }
3956 3955
3957 3956 /*
3958 3957 * Find a vfssw entry given a file system type name.
3959 3958 */
3960 3959 struct vfssw *
3961 3960 vfs_getvfsswbyname(const char *type)
3962 3961 {
3963 3962 struct vfssw *vswp;
3964 3963
3965 3964 ASSERT(VFSSW_LOCKED());
3966 3965 if (type == NULL || *type == '\0')
3967 3966 return (NULL);
3968 3967
3969 3968 for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
3970 3969 if (strcmp(type, vswp->vsw_name) == 0) {
3971 3970 vfs_refvfssw(vswp);
3972 3971 return (vswp);
3973 3972 }
3974 3973 }
3975 3974
3976 3975 return (NULL);
3977 3976 }
3978 3977
3979 3978 /*
3980 3979 * Find a vfssw entry given a set of vfsops.
3981 3980 */
3982 3981 struct vfssw *
3983 3982 vfs_getvfsswbyvfsops(vfsops_t *vfsops)
3984 3983 {
3985 3984 struct vfssw *vswp;
3986 3985
3987 3986 RLOCK_VFSSW();
3988 3987 for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
3989 3988 if (ALLOCATED_VFSSW(vswp) && &vswp->vsw_vfsops == vfsops) {
3990 3989 vfs_refvfssw(vswp);
3991 3990 RUNLOCK_VFSSW();
3992 3991 return (vswp);
3993 3992 }
3994 3993 }
3995 3994 RUNLOCK_VFSSW();
3996 3995
3997 3996 return (NULL);
3998 3997 }
3999 3998
4000 3999 /*
4001 4000 * Reference a vfssw entry.
4002 4001 */
4003 4002 void
4004 4003 vfs_refvfssw(struct vfssw *vswp)
4005 4004 {
4006 4005
4007 4006 mutex_enter(&vswp->vsw_lock);
4008 4007 vswp->vsw_count++;
4009 4008 mutex_exit(&vswp->vsw_lock);
4010 4009 }
4011 4010
4012 4011 /*
4013 4012 * Unreference a vfssw entry.
4014 4013 */
4015 4014 void
4016 4015 vfs_unrefvfssw(struct vfssw *vswp)
4017 4016 {
4018 4017
4019 4018 mutex_enter(&vswp->vsw_lock);
4020 4019 vswp->vsw_count--;
4021 4020 mutex_exit(&vswp->vsw_lock);
4022 4021 }
4023 4022
4024 4023 static int sync_retries = 20; /* number of retries when not making progress */
4025 4024 static int sync_triesleft; /* portion of sync_retries remaining */
4026 4025
4027 4026 static pgcnt_t old_pgcnt, new_pgcnt;
4028 4027 static int new_bufcnt, old_bufcnt;
4029 4028
4030 4029 /*
4031 4030 * Sync all of the mounted filesystems, and then wait for the actual i/o to
4032 4031 * complete. We wait by counting the number of dirty pages and buffers,
4033 4032 * pushing them out using bio_busy() and page_busy(), and then counting again.
4034 4033 * This routine is used during the uadmin A_SHUTDOWN code. It should only
4035 4034 * be used after some higher-level mechanism has quiesced the system so that
4036 4035 * new writes are not being initiated while we are waiting for completion.
4037 4036 *
4038 4037 * To ensure finite running time, our algorithm uses sync_triesleft (a progress
4039 4038 * counter used by the vfs_syncall() loop below). It is declared above so
4040 4039 * it can be found easily in the debugger.
4041 4040 *
4042 4041 * The sync_triesleft counter is updated by vfs_syncall() itself. If we make
4043 4042 * sync_retries consecutive calls to bio_busy() and page_busy() without
4044 4043 * decreasing either the number of dirty buffers or dirty pages below the
4045 4044 * lowest count we have seen so far, we give up and return from vfs_syncall().
4046 4045 *
4047 4046 * Each loop iteration ends with a call to delay() one second to allow time for
4048 4047 * i/o completion and to permit the user time to read our progress messages.
4049 4048 */
4050 4049 void
4051 4050 vfs_syncall(void)
4052 4051 {
4053 4052 if (rootdir == NULL && !modrootloaded)
4054 4053 return; /* no filesystems have been loaded yet */
4055 4054
4056 4055 printf("syncing file systems...");
4057 4056 sync();
4058 4057
4059 4058 sync_triesleft = sync_retries;
4060 4059
4061 4060 old_bufcnt = new_bufcnt = INT_MAX;
4062 4061 old_pgcnt = new_pgcnt = ULONG_MAX;
4063 4062
4064 4063 while (sync_triesleft > 0) {
4065 4064 old_bufcnt = MIN(old_bufcnt, new_bufcnt);
4066 4065 old_pgcnt = MIN(old_pgcnt, new_pgcnt);
4067 4066
4068 4067 new_bufcnt = bio_busy(B_TRUE);
4069 4068 new_pgcnt = page_busy(B_TRUE);
4070 4069
4071 4070 if (new_bufcnt == 0 && new_pgcnt == 0)
4072 4071 break;
4073 4072
4074 4073 if (new_bufcnt < old_bufcnt || new_pgcnt < old_pgcnt)
4075 4074 sync_triesleft = sync_retries;
4076 4075 else
4077 4076 sync_triesleft--;
4078 4077
4079 4078 if (new_bufcnt)
4080 4079 printf(" [%d]", new_bufcnt);
4081 4080 if (new_pgcnt)
4082 4081 printf(" %lu", new_pgcnt);
4083 4082
4084 4083 delay(hz);
4085 4084 }
4086 4085
4087 4086 if (new_bufcnt != 0 || new_pgcnt != 0)
4088 4087 printf(" done (not all i/o completed)\n");
4089 4088 else
4090 4089 printf(" done\n");
4091 4090
4092 4091 delay(hz);
4093 4092 }
4094 4093
4095 4094 /*
4096 4095 * Map VFS flags to statvfs flags. These shouldn't really be separate
4097 4096 * flags at all.
4098 4097 */
4099 4098 uint_t
4100 4099 vf_to_stf(uint_t vf)
4101 4100 {
4102 4101 uint_t stf = 0;
4103 4102
4104 4103 if (vf & VFS_RDONLY)
4105 4104 stf |= ST_RDONLY;
4106 4105 if (vf & VFS_NOSETUID)
4107 4106 stf |= ST_NOSUID;
4108 4107 if (vf & VFS_NOTRUNC)
4109 4108 stf |= ST_NOTRUNC;
4110 4109
4111 4110 return (stf);
4112 4111 }
4113 4112
4114 4113 /*
4115 4114 * Entries for (illegal) fstype 0.
4116 4115 */
4117 4116 /* ARGSUSED */
4118 4117 int
4119 4118 vfsstray_sync(struct vfs *vfsp, short arg, struct cred *cr)
4120 4119 {
4121 4120 cmn_err(CE_PANIC, "stray vfs operation");
4122 4121 return (0);
4123 4122 }
4124 4123
4125 4124 /*
4126 4125 * Entries for (illegal) fstype 0.
4127 4126 */
4128 4127 int
4129 4128 vfsstray(void)
4130 4129 {
4131 4130 cmn_err(CE_PANIC, "stray vfs operation");
4132 4131 return (0);
4133 4132 }
4134 4133
4135 4134 /*
4136 4135 * Support for dealing with forced UFS unmount and its interaction with
4137 4136 * LOFS. Could be used by any filesystem.
4138 4137 * See bug 1203132.
4139 4138 */
4140 4139 int
4141 4140 vfs_EIO(void)
4142 4141 {
4143 4142 return (EIO);
4144 4143 }
4145 4144
4146 4145 /*
4147 4146 * We've gotta define the op for sync separately, since the compiler gets
4148 4147 * confused if we mix and match ANSI and normal style prototypes when
4149 4148 * a "short" argument is present and spits out a warning.
4150 4149 */
4151 4150 /*ARGSUSED*/
4152 4151 int
4153 4152 vfs_EIO_sync(struct vfs *vfsp, short arg, struct cred *cr)
4154 4153 {
4155 4154 return (EIO);
4156 4155 }
4157 4156
4158 4157 vfs_t EIO_vfs;
4159 4158 vfsops_t *EIO_vfsops;
4160 4159
4161 4160 /*
4162 4161 * Called from startup() to initialize all loaded vfs's
4163 4162 */
4164 4163 void
4165 4164 vfsinit(void)
4166 4165 {
4167 4166 struct vfssw *vswp;
4168 4167 int error;
4169 4168 extern int vopstats_enabled;
4170 4169 extern void vopstats_startup();
4171 4170
4172 4171 static const fs_operation_def_t EIO_vfsops_template[] = {
4173 4172 VFSNAME_MOUNT, { .error = vfs_EIO },
4174 4173 VFSNAME_UNMOUNT, { .error = vfs_EIO },
4175 4174 VFSNAME_ROOT, { .error = vfs_EIO },
4176 4175 VFSNAME_STATVFS, { .error = vfs_EIO },
4177 4176 VFSNAME_SYNC, { .vfs_sync = vfs_EIO_sync },
4178 4177 VFSNAME_VGET, { .error = vfs_EIO },
4179 4178 VFSNAME_MOUNTROOT, { .error = vfs_EIO },
4180 4179 VFSNAME_FREEVFS, { .error = vfs_EIO },
4181 4180 VFSNAME_VNSTATE, { .error = vfs_EIO },
4182 4181 NULL, NULL
4183 4182 };
4184 4183
4185 4184 static const fs_operation_def_t stray_vfsops_template[] = {
4186 4185 VFSNAME_MOUNT, { .error = vfsstray },
4187 4186 VFSNAME_UNMOUNT, { .error = vfsstray },
4188 4187 VFSNAME_ROOT, { .error = vfsstray },
4189 4188 VFSNAME_STATVFS, { .error = vfsstray },
4190 4189 VFSNAME_SYNC, { .vfs_sync = vfsstray_sync },
4191 4190 VFSNAME_VGET, { .error = vfsstray },
4192 4191 VFSNAME_MOUNTROOT, { .error = vfsstray },
4193 4192 VFSNAME_FREEVFS, { .error = vfsstray },
4194 4193 VFSNAME_VNSTATE, { .error = vfsstray },
4195 4194 NULL, NULL
4196 4195 };
4197 4196
4198 4197 /* Create vfs cache */
4199 4198 vfs_cache = kmem_cache_create("vfs_cache", sizeof (struct vfs),
4200 4199 sizeof (uintptr_t), NULL, NULL, NULL, NULL, NULL, 0);
4201 4200
4202 4201 /* Initialize the vnode cache (file systems may use it during init). */
4203 4202 vn_create_cache();
4204 4203
4205 4204 /* Setup event monitor framework */
4206 4205 fem_init();
4207 4206
4208 4207 /* Initialize the dummy stray file system type. */
4209 4208 error = vfs_setfsops(0, stray_vfsops_template, NULL);
4210 4209
4211 4210 /* Initialize the dummy EIO file system. */
4212 4211 error = vfs_makefsops(EIO_vfsops_template, &EIO_vfsops);
4213 4212 if (error != 0) {
4214 4213 cmn_err(CE_WARN, "vfsinit: bad EIO vfs ops template");
4215 4214 /* Shouldn't happen, but not bad enough to panic */
4216 4215 }
4217 4216
4218 4217 VFS_INIT(&EIO_vfs, EIO_vfsops, (caddr_t)NULL);
4219 4218
4220 4219 /*
4221 4220 * Default EIO_vfs.vfs_flag to VFS_UNMOUNTED so a lookup
4222 4221 * on this vfs can immediately notice it's invalid.
4223 4222 */
4224 4223 EIO_vfs.vfs_flag |= VFS_UNMOUNTED;
↓ open down ↓ |
3149 lines elided |
↑ open up ↑ |
4225 4224
4226 4225 /*
4227 4226 * Call the init routines of non-loadable filesystems only.
4228 4227 * Filesystems which are loaded as separate modules will be
4229 4228 * initialized by the module loading code instead.
4230 4229 */
4231 4230
4232 4231 for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) {
4233 4232 RLOCK_VFSSW();
4234 4233 if (vswp->vsw_init != NULL)
4235 - (*vswp->vsw_init)(vswp - vfssw, vswp->vsw_name);
4234 + (void) (*vswp->vsw_init)(vswp - vfssw, vswp->vsw_name);
4236 4235 RUNLOCK_VFSSW();
4237 4236 }
4238 4237
4239 4238 vopstats_startup();
4240 4239
4241 4240 if (vopstats_enabled) {
4242 4241 /* EIO_vfs can collect stats, but we don't retrieve them */
4243 4242 initialize_vopstats(&EIO_vfs.vfs_vopstats);
4244 4243 EIO_vfs.vfs_fstypevsp = NULL;
4245 4244 EIO_vfs.vfs_vskap = NULL;
4246 4245 EIO_vfs.vfs_flag |= VFS_STATS;
4247 4246 }
4248 4247
4249 4248 xattr_init();
4250 4249
4251 4250 reparse_point_init();
4252 4251 }
4253 4252
4254 4253 vfs_t *
4255 4254 vfs_alloc(int kmflag)
4256 4255 {
4257 4256 vfs_t *vfsp;
4258 4257
4259 4258 vfsp = kmem_cache_alloc(vfs_cache, kmflag);
4260 4259
4261 4260 /*
4262 4261 * Do the simplest initialization here.
4263 4262 * Everything else gets done in vfs_init()
4264 4263 */
4265 4264 bzero(vfsp, sizeof (vfs_t));
4266 4265 return (vfsp);
4267 4266 }
4268 4267
4269 4268 void
4270 4269 vfs_free(vfs_t *vfsp)
4271 4270 {
4272 4271 /*
4273 4272 * One would be tempted to assert that "vfsp->vfs_count == 0".
4274 4273 * The problem is that this gets called out of domount() with
4275 4274 * a partially initialized vfs and a vfs_count of 1. This is
4276 4275 * also called from vfs_rele() with a vfs_count of 0. We can't
4277 4276 * call VFS_RELE() from domount() if VFS_MOUNT() hasn't successfully
4278 4277 * returned. This is because VFS_MOUNT() fully initializes the
4279 4278 * vfs structure and its associated data. VFS_RELE() will call
4280 4279 * VFS_FREEVFS() which may panic the system if the data structures
4281 4280 * aren't fully initialized from a successful VFS_MOUNT()).
4282 4281 */
4283 4282
4284 4283 /* If FEM was in use, make sure everything gets cleaned up */
4285 4284 if (vfsp->vfs_femhead) {
4286 4285 ASSERT(vfsp->vfs_femhead->femh_list == NULL);
4287 4286 mutex_destroy(&vfsp->vfs_femhead->femh_lock);
4288 4287 kmem_free(vfsp->vfs_femhead, sizeof (*(vfsp->vfs_femhead)));
4289 4288 vfsp->vfs_femhead = NULL;
4290 4289 }
4291 4290
4292 4291 if (vfsp->vfs_implp)
4293 4292 vfsimpl_teardown(vfsp);
4294 4293 sema_destroy(&vfsp->vfs_reflock);
4295 4294 kmem_cache_free(vfs_cache, vfsp);
4296 4295 }
4297 4296
4298 4297 /*
4299 4298 * Increments the vfs reference count by one atomically.
4300 4299 */
4301 4300 void
4302 4301 vfs_hold(vfs_t *vfsp)
4303 4302 {
4304 4303 atomic_inc_32(&vfsp->vfs_count);
4305 4304 ASSERT(vfsp->vfs_count != 0);
4306 4305 }
4307 4306
4308 4307 /*
4309 4308 * Decrements the vfs reference count by one atomically. When
4310 4309 * vfs reference count becomes zero, it calls the file system
4311 4310 * specific vfs_freevfs() to free up the resources.
4312 4311 */
4313 4312 void
4314 4313 vfs_rele(vfs_t *vfsp)
4315 4314 {
4316 4315 ASSERT(vfsp->vfs_count != 0);
4317 4316 if (atomic_dec_32_nv(&vfsp->vfs_count) == 0) {
4318 4317 VFS_FREEVFS(vfsp);
4319 4318 lofi_remove(vfsp);
4320 4319 if (vfsp->vfs_zone)
4321 4320 zone_rele_ref(&vfsp->vfs_implp->vi_zone_ref,
4322 4321 ZONE_REF_VFS);
4323 4322 vfs_freemnttab(vfsp);
4324 4323 vfs_free(vfsp);
4325 4324 }
4326 4325 }
4327 4326
4328 4327 /*
4329 4328 * Generic operations vector support.
4330 4329 *
4331 4330 * This is used to build operations vectors for both the vfs and vnode.
4332 4331 * It's normally called only when a file system is loaded.
4333 4332 *
4334 4333 * There are many possible algorithms for this, including the following:
4335 4334 *
4336 4335 * (1) scan the list of known operations; for each, see if the file system
4337 4336 * includes an entry for it, and fill it in as appropriate.
4338 4337 *
4339 4338 * (2) set up defaults for all known operations. scan the list of ops
4340 4339 * supplied by the file system; for each which is both supplied and
4341 4340 * known, fill it in.
4342 4341 *
4343 4342 * (3) sort the lists of known ops & supplied ops; scan the list, filling
4344 4343 * in entries as we go.
4345 4344 *
4346 4345 * we choose (1) for simplicity, and because performance isn't critical here.
4347 4346 * note that (2) could be sped up using a precomputed hash table on known ops.
4348 4347 * (3) could be faster than either, but only if the lists were very large or
4349 4348 * supplied in sorted order.
4350 4349 *
4351 4350 */
4352 4351
4353 4352 int
4354 4353 fs_build_vector(void *vector, int *unused_ops,
4355 4354 const fs_operation_trans_def_t *translation,
4356 4355 const fs_operation_def_t *operations)
4357 4356 {
4358 4357 int i, num_trans, num_ops, used;
4359 4358
4360 4359 /*
4361 4360 * Count the number of translations and the number of supplied
4362 4361 * operations.
4363 4362 */
4364 4363
4365 4364 {
4366 4365 const fs_operation_trans_def_t *p;
4367 4366
4368 4367 for (num_trans = 0, p = translation;
4369 4368 p->name != NULL;
4370 4369 num_trans++, p++)
4371 4370 ;
4372 4371 }
4373 4372
4374 4373 {
4375 4374 const fs_operation_def_t *p;
4376 4375
4377 4376 for (num_ops = 0, p = operations;
4378 4377 p->name != NULL;
4379 4378 num_ops++, p++)
4380 4379 ;
4381 4380 }
4382 4381
4383 4382 /* Walk through each operation known to our caller. There will be */
4384 4383 /* one entry in the supplied "translation table" for each. */
4385 4384
4386 4385 used = 0;
4387 4386
4388 4387 for (i = 0; i < num_trans; i++) {
4389 4388 int j, found;
4390 4389 char *curname;
4391 4390 fs_generic_func_p result;
4392 4391 fs_generic_func_p *location;
4393 4392
4394 4393 curname = translation[i].name;
4395 4394
4396 4395 /* Look for a matching operation in the list supplied by the */
4397 4396 /* file system. */
4398 4397
4399 4398 found = 0;
4400 4399
4401 4400 for (j = 0; j < num_ops; j++) {
4402 4401 if (strcmp(operations[j].name, curname) == 0) {
4403 4402 used++;
4404 4403 found = 1;
4405 4404 break;
4406 4405 }
4407 4406 }
4408 4407
4409 4408 /*
4410 4409 * If the file system is using a "placeholder" for default
4411 4410 * or error functions, grab the appropriate function out of
4412 4411 * the translation table. If the file system didn't supply
4413 4412 * this operation at all, use the default function.
4414 4413 */
4415 4414
4416 4415 if (found) {
4417 4416 result = operations[j].func.fs_generic;
4418 4417 if (result == fs_default) {
4419 4418 result = translation[i].defaultFunc;
4420 4419 } else if (result == fs_error) {
4421 4420 result = translation[i].errorFunc;
4422 4421 } else if (result == NULL) {
4423 4422 /* Null values are PROHIBITED */
4424 4423 return (EINVAL);
4425 4424 }
4426 4425 } else {
4427 4426 result = translation[i].defaultFunc;
4428 4427 }
4429 4428
4430 4429 /* Now store the function into the operations vector. */
4431 4430
4432 4431 location = (fs_generic_func_p *)
4433 4432 (((char *)vector) + translation[i].offset);
4434 4433
4435 4434 *location = result;
4436 4435 }
4437 4436
4438 4437 *unused_ops = num_ops - used;
4439 4438
4440 4439 return (0);
4441 4440 }
4442 4441
4443 4442 /* Placeholder functions, should never be called. */
4444 4443
4445 4444 int
4446 4445 fs_error(void)
4447 4446 {
4448 4447 cmn_err(CE_PANIC, "fs_error called");
4449 4448 return (0);
4450 4449 }
4451 4450
4452 4451 int
4453 4452 fs_default(void)
4454 4453 {
4455 4454 cmn_err(CE_PANIC, "fs_default called");
4456 4455 return (0);
4457 4456 }
4458 4457
4459 4458 #ifdef __sparc
4460 4459
4461 4460 /*
4462 4461 * Part of the implementation of booting off a mirrored root
4463 4462 * involves a change of dev_t for the root device. To
4464 4463 * accomplish this, first remove the existing hash table
4465 4464 * entry for the root device, convert to the new dev_t,
4466 4465 * then re-insert in the hash table at the head of the list.
4467 4466 */
4468 4467 void
4469 4468 vfs_root_redev(vfs_t *vfsp, dev_t ndev, int fstype)
4470 4469 {
4471 4470 vfs_list_lock();
4472 4471
4473 4472 vfs_hash_remove(vfsp);
4474 4473
4475 4474 vfsp->vfs_dev = ndev;
4476 4475 vfs_make_fsid(&vfsp->vfs_fsid, ndev, fstype);
4477 4476
4478 4477 vfs_hash_add(vfsp, 1);
4479 4478
4480 4479 vfs_list_unlock();
4481 4480 }
4482 4481
4483 4482 #else /* x86 NEWBOOT */
4484 4483
4485 4484 #if defined(__x86)
4486 4485 extern int hvmboot_rootconf();
4487 4486 #endif /* __x86 */
4488 4487
4489 4488 extern ib_boot_prop_t *iscsiboot_prop;
4490 4489
4491 4490 int
4492 4491 rootconf()
4493 4492 {
4494 4493 int error;
4495 4494 struct vfssw *vsw;
4496 4495 extern void pm_init();
4497 4496 char *fstyp, *fsmod;
4498 4497 int ret = -1;
4499 4498
4500 4499 getrootfs(&fstyp, &fsmod);
4501 4500
4502 4501 #if defined(__x86)
4503 4502 /*
4504 4503 * hvmboot_rootconf() is defined in the hvm_bootstrap misc module,
4505 4504 * which lives in /platform/i86hvm, and hence is only available when
4506 4505 * booted in an x86 hvm environment. If the hvm_bootstrap misc module
4507 4506 * is not available then the modstub for this function will return 0.
4508 4507 * If the hvm_bootstrap misc module is available it will be loaded
4509 4508 * and hvmboot_rootconf() will be invoked.
4510 4509 */
4511 4510 if (error = hvmboot_rootconf())
4512 4511 return (error);
4513 4512 #endif /* __x86 */
4514 4513
4515 4514 if (error = clboot_rootconf())
4516 4515 return (error);
4517 4516
4518 4517 if (modload("fs", fsmod) == -1)
4519 4518 panic("Cannot _init %s module", fsmod);
4520 4519
4521 4520 RLOCK_VFSSW();
4522 4521 vsw = vfs_getvfsswbyname(fstyp);
4523 4522 RUNLOCK_VFSSW();
4524 4523 if (vsw == NULL) {
4525 4524 cmn_err(CE_CONT, "Cannot find %s filesystem\n", fstyp);
4526 4525 return (ENXIO);
4527 4526 }
4528 4527 VFS_INIT(rootvfs, &vsw->vsw_vfsops, 0);
4529 4528 VFS_HOLD(rootvfs);
4530 4529
4531 4530 /* always mount readonly first */
4532 4531 rootvfs->vfs_flag |= VFS_RDONLY;
4533 4532
4534 4533 pm_init();
4535 4534
4536 4535 if (netboot && iscsiboot_prop) {
4537 4536 cmn_err(CE_WARN, "NFS boot and iSCSI boot"
4538 4537 " shouldn't happen in the same time");
4539 4538 return (EINVAL);
4540 4539 }
4541 4540
4542 4541 if (netboot || iscsiboot_prop) {
4543 4542 ret = strplumb();
4544 4543 if (ret != 0) {
4545 4544 cmn_err(CE_WARN, "Cannot plumb network device %d", ret);
4546 4545 return (EFAULT);
4547 4546 }
4548 4547 }
4549 4548
4550 4549 if ((ret == 0) && iscsiboot_prop) {
4551 4550 ret = modload("drv", "iscsi");
4552 4551 /* -1 indicates fail */
4553 4552 if (ret == -1) {
4554 4553 cmn_err(CE_WARN, "Failed to load iscsi module");
4555 4554 iscsi_boot_prop_free();
4556 4555 return (EINVAL);
4557 4556 } else {
4558 4557 if (!i_ddi_attach_pseudo_node("iscsi")) {
4559 4558 cmn_err(CE_WARN,
4560 4559 "Failed to attach iscsi driver");
4561 4560 iscsi_boot_prop_free();
4562 4561 return (ENODEV);
4563 4562 }
4564 4563 }
4565 4564 }
4566 4565
4567 4566 error = VFS_MOUNTROOT(rootvfs, ROOT_INIT);
4568 4567 vfs_unrefvfssw(vsw);
4569 4568 rootdev = rootvfs->vfs_dev;
4570 4569
4571 4570 if (error)
4572 4571 cmn_err(CE_CONT, "Cannot mount root on %s fstype %s\n",
4573 4572 rootfs.bo_name, fstyp);
4574 4573 else
4575 4574 cmn_err(CE_CONT, "?root on %s fstype %s\n",
4576 4575 rootfs.bo_name, fstyp);
4577 4576 return (error);
4578 4577 }
4579 4578
4580 4579 /*
4581 4580 * XXX this is called by nfs only and should probably be removed
4582 4581 * If booted with ASKNAME, prompt on the console for a filesystem
4583 4582 * name and return it.
4584 4583 */
4585 4584 void
4586 4585 getfsname(char *askfor, char *name, size_t namelen)
4587 4586 {
4588 4587 if (boothowto & RB_ASKNAME) {
4589 4588 printf("%s name: ", askfor);
4590 4589 console_gets(name, namelen);
4591 4590 }
4592 4591 }
4593 4592
4594 4593 /*
4595 4594 * Init the root filesystem type (rootfs.bo_fstype) from the "fstype"
4596 4595 * property.
4597 4596 *
4598 4597 * Filesystem types starting with the prefix "nfs" are diskless clients;
4599 4598 * init the root filename name (rootfs.bo_name), too.
4600 4599 *
4601 4600 * If we are booting via NFS we currently have these options:
4602 4601 * nfs - dynamically choose NFS V2, V3, or V4 (default)
4603 4602 * nfs2 - force NFS V2
4604 4603 * nfs3 - force NFS V3
4605 4604 * nfs4 - force NFS V4
4606 4605 * Because we need to maintain backward compatibility with the naming
4607 4606 * convention that the NFS V2 filesystem name is "nfs" (see vfs_conf.c)
4608 4607 * we need to map "nfs" => "nfsdyn" and "nfs2" => "nfs". The dynamic
4609 4608 * nfs module will map the type back to either "nfs", "nfs3", or "nfs4".
4610 4609 * This is only for root filesystems, all other uses will expect
4611 4610 * that "nfs" == NFS V2.
4612 4611 */
4613 4612 static void
4614 4613 getrootfs(char **fstypp, char **fsmodp)
4615 4614 {
4616 4615 char *propstr = NULL;
4617 4616
4618 4617 /*
4619 4618 * Check fstype property; for diskless it should be one of "nfs",
4620 4619 * "nfs2", "nfs3" or "nfs4".
4621 4620 */
4622 4621 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
4623 4622 DDI_PROP_DONTPASS, "fstype", &propstr)
4624 4623 == DDI_SUCCESS) {
4625 4624 (void) strncpy(rootfs.bo_fstype, propstr, BO_MAXFSNAME);
4626 4625 ddi_prop_free(propstr);
4627 4626
4628 4627 /*
4629 4628 * if the boot property 'fstype' is not set, but 'zfs-bootfs' is set,
4630 4629 * assume the type of this root filesystem is 'zfs'.
4631 4630 */
4632 4631 } else if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
4633 4632 DDI_PROP_DONTPASS, "zfs-bootfs", &propstr)
4634 4633 == DDI_SUCCESS) {
4635 4634 (void) strncpy(rootfs.bo_fstype, "zfs", BO_MAXFSNAME);
4636 4635 ddi_prop_free(propstr);
4637 4636 }
4638 4637
4639 4638 if (strncmp(rootfs.bo_fstype, "nfs", 3) != 0) {
4640 4639 *fstypp = *fsmodp = rootfs.bo_fstype;
4641 4640 return;
4642 4641 }
4643 4642
4644 4643 ++netboot;
4645 4644
4646 4645 if (strcmp(rootfs.bo_fstype, "nfs2") == 0)
4647 4646 (void) strcpy(rootfs.bo_fstype, "nfs");
4648 4647 else if (strcmp(rootfs.bo_fstype, "nfs") == 0)
4649 4648 (void) strcpy(rootfs.bo_fstype, "nfsdyn");
4650 4649
4651 4650 /*
4652 4651 * check if path to network interface is specified in bootpath
4653 4652 * or by a hypervisor domain configuration file.
4654 4653 * XXPV - enable strlumb_get_netdev_path()
4655 4654 */
4656 4655 if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS,
4657 4656 "xpv-nfsroot")) {
4658 4657 (void) strcpy(rootfs.bo_name, "/xpvd/xnf@0");
4659 4658 } else if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
4660 4659 DDI_PROP_DONTPASS, "bootpath", &propstr)
4661 4660 == DDI_SUCCESS) {
4662 4661 (void) strncpy(rootfs.bo_name, propstr, BO_MAXOBJNAME);
4663 4662 ddi_prop_free(propstr);
4664 4663 } else {
4665 4664 rootfs.bo_name[0] = '\0';
4666 4665 }
4667 4666 *fstypp = rootfs.bo_fstype;
4668 4667 *fsmodp = "nfs";
4669 4668 }
4670 4669 #endif
4671 4670
4672 4671 /*
4673 4672 * VFS feature routines
4674 4673 */
4675 4674
4676 4675 #define VFTINDEX(feature) (((feature) >> 32) & 0xFFFFFFFF)
4677 4676 #define VFTBITS(feature) ((feature) & 0xFFFFFFFFLL)
4678 4677
4679 4678 /* Register a feature in the vfs */
4680 4679 void
4681 4680 vfs_set_feature(vfs_t *vfsp, vfs_feature_t feature)
4682 4681 {
4683 4682 /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
4684 4683 if (vfsp->vfs_implp == NULL)
4685 4684 return;
4686 4685
4687 4686 vfsp->vfs_featureset[VFTINDEX(feature)] |= VFTBITS(feature);
4688 4687 }
4689 4688
4690 4689 void
4691 4690 vfs_clear_feature(vfs_t *vfsp, vfs_feature_t feature)
4692 4691 {
4693 4692 /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
4694 4693 if (vfsp->vfs_implp == NULL)
4695 4694 return;
4696 4695 vfsp->vfs_featureset[VFTINDEX(feature)] &= VFTBITS(~feature);
4697 4696 }
4698 4697
4699 4698 /*
4700 4699 * Query a vfs for a feature.
4701 4700 * Returns 1 if feature is present, 0 if not
4702 4701 */
4703 4702 int
4704 4703 vfs_has_feature(vfs_t *vfsp, vfs_feature_t feature)
4705 4704 {
4706 4705 int ret = 0;
4707 4706
4708 4707 /* Note that vfs_featureset[] is found in *vfsp->vfs_implp */
4709 4708 if (vfsp->vfs_implp == NULL)
4710 4709 return (ret);
4711 4710
4712 4711 if (vfsp->vfs_featureset[VFTINDEX(feature)] & VFTBITS(feature))
4713 4712 ret = 1;
4714 4713
4715 4714 return (ret);
4716 4715 }
4717 4716
4718 4717 /*
4719 4718 * Propagate feature set from one vfs to another
4720 4719 */
4721 4720 void
4722 4721 vfs_propagate_features(vfs_t *from, vfs_t *to)
4723 4722 {
4724 4723 int i;
4725 4724
4726 4725 if (to->vfs_implp == NULL || from->vfs_implp == NULL)
4727 4726 return;
4728 4727
4729 4728 for (i = 1; i <= to->vfs_featureset[0]; i++) {
4730 4729 to->vfs_featureset[i] = from->vfs_featureset[i];
4731 4730 }
4732 4731 }
4733 4732
4734 4733 #define LOFINODE_PATH "/dev/lofi/%d"
4735 4734
4736 4735 /*
4737 4736 * Return the vnode for the lofi node if there's a lofi mount in place.
4738 4737 * Returns -1 when there's no lofi node, 0 on success, and > 0 on
4739 4738 * failure.
4740 4739 */
4741 4740 int
4742 4741 vfs_get_lofi(vfs_t *vfsp, vnode_t **vpp)
4743 4742 {
4744 4743 char *path = NULL;
4745 4744 int strsize;
4746 4745 int err;
4747 4746
4748 4747 if (vfsp->vfs_lofi_id == 0) {
4749 4748 *vpp = NULL;
4750 4749 return (-1);
4751 4750 }
4752 4751
4753 4752 strsize = snprintf(NULL, 0, LOFINODE_PATH, vfsp->vfs_lofi_id);
4754 4753 path = kmem_alloc(strsize + 1, KM_SLEEP);
4755 4754 (void) snprintf(path, strsize + 1, LOFINODE_PATH, vfsp->vfs_lofi_id);
4756 4755
4757 4756 /*
4758 4757 * We may be inside a zone, so we need to use the /dev path, but
4759 4758 * it's created asynchronously, so we wait here.
4760 4759 */
4761 4760 for (;;) {
4762 4761 err = lookupname(path, UIO_SYSSPACE, FOLLOW, NULLVPP, vpp);
4763 4762
4764 4763 if (err != ENOENT)
4765 4764 break;
4766 4765
4767 4766 if ((err = delay_sig(hz / 8)) == EINTR)
4768 4767 break;
4769 4768 }
4770 4769
4771 4770 if (err)
4772 4771 *vpp = NULL;
4773 4772
4774 4773 kmem_free(path, strsize + 1);
4775 4774 return (err);
4776 4775 }
↓ open down ↓ |
531 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX