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