17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55a59a8b3Srsb * Common Development and Distribution License (the "License"). 65a59a8b3Srsb * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21*e373b6e4SYuri Pankov 227c478bd9Sstevel@tonic-gate /* 23e07b36b5Sbatschul * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*e373b6e4SYuri Pankov * Copyright 2016 Nexenta Systems, Inc. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 297c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate /* 327c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 337c478bd9Sstevel@tonic-gate * The Regents of the University of California 347c478bd9Sstevel@tonic-gate * All Rights Reserved 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 377c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 387c478bd9Sstevel@tonic-gate * contributors. 397c478bd9Sstevel@tonic-gate */ 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #include <sys/types.h> 427c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 437c478bd9Sstevel@tonic-gate #include <sys/param.h> 447c478bd9Sstevel@tonic-gate #include <sys/systm.h> 457c478bd9Sstevel@tonic-gate #include <sys/bitmap.h> 467c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 477c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 487c478bd9Sstevel@tonic-gate #include <sys/signal.h> 497c478bd9Sstevel@tonic-gate #include <sys/user.h> 507c478bd9Sstevel@tonic-gate #include <sys/proc.h> 517c478bd9Sstevel@tonic-gate #include <sys/disp.h> 527c478bd9Sstevel@tonic-gate #include <sys/buf.h> 537c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 547c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 55aa59c4cbSrsb #include <sys/vfs_opreg.h> 567c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 577c478bd9Sstevel@tonic-gate #include <sys/file.h> 58bc69f433Saguzovsk #include <sys/atomic.h> 597c478bd9Sstevel@tonic-gate #include <sys/uio.h> 607c478bd9Sstevel@tonic-gate #include <sys/dkio.h> 617c478bd9Sstevel@tonic-gate #include <sys/cred.h> 627c478bd9Sstevel@tonic-gate #include <sys/conf.h> 637c478bd9Sstevel@tonic-gate #include <sys/dnlc.h> 647c478bd9Sstevel@tonic-gate #include <sys/kstat.h> 657c478bd9Sstevel@tonic-gate #include <sys/acl.h> 667c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h> 677c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_fs.h> 687c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h> 697c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_mount.h> 707c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_acl.h> 717c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_panic.h> 727c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_bio.h> 737c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_quota.h> 747c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_log.h> 757c478bd9Sstevel@tonic-gate #undef NFS 767c478bd9Sstevel@tonic-gate #include <sys/statvfs.h> 777c478bd9Sstevel@tonic-gate #include <sys/mount.h> 787c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 797c478bd9Sstevel@tonic-gate #include <sys/swap.h> 807c478bd9Sstevel@tonic-gate #include <sys/errno.h> 817c478bd9Sstevel@tonic-gate #include <sys/debug.h> 827c478bd9Sstevel@tonic-gate #include "fs/fs_subr.h" 837c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 847c478bd9Sstevel@tonic-gate #include <sys/dnlc.h> 857c478bd9Sstevel@tonic-gate #include <sys/fssnap_if.h> 867c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 877c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 887c478bd9Sstevel@tonic-gate #include <sys/policy.h> 897c478bd9Sstevel@tonic-gate #include <sys/zone.h> 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate /* 927c478bd9Sstevel@tonic-gate * This is the loadable module wrapper. 937c478bd9Sstevel@tonic-gate */ 947c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate int ufsfstype; 977c478bd9Sstevel@tonic-gate vfsops_t *ufs_vfsops; 987c478bd9Sstevel@tonic-gate static int ufsinit(int, char *); 997c478bd9Sstevel@tonic-gate static int mountfs(); 1007c478bd9Sstevel@tonic-gate extern int highbit(); 1017c478bd9Sstevel@tonic-gate extern struct instats ins; 1027c478bd9Sstevel@tonic-gate extern struct vnode *common_specvp(struct vnode *vp); 1037c478bd9Sstevel@tonic-gate extern vfs_t EIO_vfs; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate struct dquot *dquot, *dquotNDQUOT; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 1087c478bd9Sstevel@tonic-gate * Cylinder group summary information handling tunable. 1097c478bd9Sstevel@tonic-gate * This defines when these deltas get logged. 1107c478bd9Sstevel@tonic-gate * If the number of cylinders in the file system is over the 1117c478bd9Sstevel@tonic-gate * tunable then we log csum updates. Otherwise the updates are only 1127c478bd9Sstevel@tonic-gate * done for performance on unmount. After a panic they can be 1137c478bd9Sstevel@tonic-gate * quickly constructed during mounting. See ufs_construct_si() 1147c478bd9Sstevel@tonic-gate * called from ufs_getsummaryinfo(). 1157c478bd9Sstevel@tonic-gate * 1167c478bd9Sstevel@tonic-gate * This performance feature can of course be disabled by setting 1177c478bd9Sstevel@tonic-gate * ufs_ncg_log to 0, and fully enabled by setting it to 0xffffffff. 1187c478bd9Sstevel@tonic-gate */ 1197c478bd9Sstevel@tonic-gate #define UFS_LOG_NCG_DEFAULT 10000 1207c478bd9Sstevel@tonic-gate uint32_t ufs_ncg_log = UFS_LOG_NCG_DEFAULT; 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate /* 1237c478bd9Sstevel@tonic-gate * ufs_clean_root indicates whether the root fs went down cleanly 1247c478bd9Sstevel@tonic-gate */ 1257c478bd9Sstevel@tonic-gate static int ufs_clean_root = 0; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * UFS Mount options table 1297c478bd9Sstevel@tonic-gate */ 1307c478bd9Sstevel@tonic-gate static char *intr_cancel[] = { MNTOPT_NOINTR, NULL }; 1317c478bd9Sstevel@tonic-gate static char *nointr_cancel[] = { MNTOPT_INTR, NULL }; 1327c478bd9Sstevel@tonic-gate static char *forcedirectio_cancel[] = { MNTOPT_NOFORCEDIRECTIO, NULL }; 1337c478bd9Sstevel@tonic-gate static char *noforcedirectio_cancel[] = { MNTOPT_FORCEDIRECTIO, NULL }; 1347c478bd9Sstevel@tonic-gate static char *largefiles_cancel[] = { MNTOPT_NOLARGEFILES, NULL }; 1357c478bd9Sstevel@tonic-gate static char *nolargefiles_cancel[] = { MNTOPT_LARGEFILES, NULL }; 1367c478bd9Sstevel@tonic-gate static char *logging_cancel[] = { MNTOPT_NOLOGGING, NULL }; 1377c478bd9Sstevel@tonic-gate static char *nologging_cancel[] = { MNTOPT_LOGGING, NULL }; 1387c478bd9Sstevel@tonic-gate static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL }; 1397c478bd9Sstevel@tonic-gate static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL }; 1407c478bd9Sstevel@tonic-gate static char *quota_cancel[] = { MNTOPT_NOQUOTA, NULL }; 1417c478bd9Sstevel@tonic-gate static char *noquota_cancel[] = { MNTOPT_QUOTA, NULL }; 1427c478bd9Sstevel@tonic-gate static char *dfratime_cancel[] = { MNTOPT_NODFRATIME, NULL }; 1437c478bd9Sstevel@tonic-gate static char *nodfratime_cancel[] = { MNTOPT_DFRATIME, NULL }; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate static mntopt_t mntopts[] = { 1467c478bd9Sstevel@tonic-gate /* 1477c478bd9Sstevel@tonic-gate * option name cancel option default arg flags 1487c478bd9Sstevel@tonic-gate * ufs arg flag 1497c478bd9Sstevel@tonic-gate */ 1507c478bd9Sstevel@tonic-gate { MNTOPT_INTR, intr_cancel, NULL, MO_DEFAULT, 1517c478bd9Sstevel@tonic-gate (void *)0 }, 1527c478bd9Sstevel@tonic-gate { MNTOPT_NOINTR, nointr_cancel, NULL, 0, 1537c478bd9Sstevel@tonic-gate (void *)UFSMNT_NOINTR }, 1547c478bd9Sstevel@tonic-gate { MNTOPT_SYNCDIR, NULL, NULL, 0, 1557c478bd9Sstevel@tonic-gate (void *)UFSMNT_SYNCDIR }, 1567c478bd9Sstevel@tonic-gate { MNTOPT_FORCEDIRECTIO, forcedirectio_cancel, NULL, 0, 1577c478bd9Sstevel@tonic-gate (void *)UFSMNT_FORCEDIRECTIO }, 1587c478bd9Sstevel@tonic-gate { MNTOPT_NOFORCEDIRECTIO, noforcedirectio_cancel, NULL, 0, 1597c478bd9Sstevel@tonic-gate (void *)UFSMNT_NOFORCEDIRECTIO }, 1607c478bd9Sstevel@tonic-gate { MNTOPT_NOSETSEC, NULL, NULL, 0, 1617c478bd9Sstevel@tonic-gate (void *)UFSMNT_NOSETSEC }, 1627c478bd9Sstevel@tonic-gate { MNTOPT_LARGEFILES, largefiles_cancel, NULL, MO_DEFAULT, 1637c478bd9Sstevel@tonic-gate (void *)UFSMNT_LARGEFILES }, 1647c478bd9Sstevel@tonic-gate { MNTOPT_NOLARGEFILES, nolargefiles_cancel, NULL, 0, 1657c478bd9Sstevel@tonic-gate (void *)0 }, 1667c478bd9Sstevel@tonic-gate { MNTOPT_LOGGING, logging_cancel, NULL, MO_TAG, 1677c478bd9Sstevel@tonic-gate (void *)UFSMNT_LOGGING }, 1687c478bd9Sstevel@tonic-gate { MNTOPT_NOLOGGING, nologging_cancel, NULL, 1697c478bd9Sstevel@tonic-gate MO_NODISPLAY|MO_DEFAULT|MO_TAG, (void *)0 }, 1707c478bd9Sstevel@tonic-gate { MNTOPT_QUOTA, quota_cancel, NULL, MO_IGNORE, 1717c478bd9Sstevel@tonic-gate (void *)0 }, 1727c478bd9Sstevel@tonic-gate { MNTOPT_NOQUOTA, noquota_cancel, NULL, 1737c478bd9Sstevel@tonic-gate MO_NODISPLAY|MO_DEFAULT, (void *)0 }, 1747c478bd9Sstevel@tonic-gate { MNTOPT_GLOBAL, NULL, NULL, 0, 1757c478bd9Sstevel@tonic-gate (void *)0 }, 1767c478bd9Sstevel@tonic-gate { MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, 1777c478bd9Sstevel@tonic-gate (void *)0 }, 1787c478bd9Sstevel@tonic-gate { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 1797c478bd9Sstevel@tonic-gate (void *)0 }, 1807c478bd9Sstevel@tonic-gate { MNTOPT_NOATIME, NULL, NULL, 0, 1817c478bd9Sstevel@tonic-gate (void *)UFSMNT_NOATIME }, 1827c478bd9Sstevel@tonic-gate { MNTOPT_DFRATIME, dfratime_cancel, NULL, 0, 1837c478bd9Sstevel@tonic-gate (void *)0 }, 1847c478bd9Sstevel@tonic-gate { MNTOPT_NODFRATIME, nodfratime_cancel, NULL, 1857c478bd9Sstevel@tonic-gate MO_NODISPLAY|MO_DEFAULT, (void *)UFSMNT_NODFRATIME }, 1867c478bd9Sstevel@tonic-gate { MNTOPT_ONERROR, NULL, UFSMNT_ONERROR_PANIC_STR, 1877c478bd9Sstevel@tonic-gate MO_DEFAULT|MO_HASVALUE, (void *)0 }, 1887c478bd9Sstevel@tonic-gate }; 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate static mntopts_t ufs_mntopts = { 1917c478bd9Sstevel@tonic-gate sizeof (mntopts) / sizeof (mntopt_t), 1927c478bd9Sstevel@tonic-gate mntopts 1937c478bd9Sstevel@tonic-gate }; 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate static vfsdef_t vfw = { 1967c478bd9Sstevel@tonic-gate VFSDEF_VERSION, 1977c478bd9Sstevel@tonic-gate "ufs", 1987c478bd9Sstevel@tonic-gate ufsinit, 19943d5cd3dSjohnlev VSW_HASPROTO|VSW_CANREMOUNT|VSW_STATS|VSW_CANLOFI, 2007c478bd9Sstevel@tonic-gate &ufs_mntopts 2017c478bd9Sstevel@tonic-gate }; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate /* 2047c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 2057c478bd9Sstevel@tonic-gate */ 2067c478bd9Sstevel@tonic-gate extern struct mod_ops mod_fsops; 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate static struct modlfs modlfs = { 2097c478bd9Sstevel@tonic-gate &mod_fsops, "filesystem for ufs", &vfw 2107c478bd9Sstevel@tonic-gate }; 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 2137c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modlfs, NULL 2147c478bd9Sstevel@tonic-gate }; 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * An attempt has been made to make this module unloadable. In order to 2187c478bd9Sstevel@tonic-gate * test it, we need a system in which the root fs is NOT ufs. THIS HAS NOT 2197c478bd9Sstevel@tonic-gate * BEEN DONE 2207c478bd9Sstevel@tonic-gate */ 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate extern kstat_t *ufs_inode_kstat; 2237c478bd9Sstevel@tonic-gate extern uint_t ufs_lockfs_key; 2247c478bd9Sstevel@tonic-gate extern void ufs_lockfs_tsd_destructor(void *); 2257c478bd9Sstevel@tonic-gate extern uint_t bypass_snapshot_throttle_key; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate int 2287c478bd9Sstevel@tonic-gate _init(void) 2297c478bd9Sstevel@tonic-gate { 2307c478bd9Sstevel@tonic-gate /* 2317c478bd9Sstevel@tonic-gate * Create an index into the per thread array so that any thread doing 2327c478bd9Sstevel@tonic-gate * VOP will have a lockfs mark on it. 2337c478bd9Sstevel@tonic-gate */ 2347c478bd9Sstevel@tonic-gate tsd_create(&ufs_lockfs_key, ufs_lockfs_tsd_destructor); 2357c478bd9Sstevel@tonic-gate tsd_create(&bypass_snapshot_throttle_key, NULL); 2367c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate int 2407c478bd9Sstevel@tonic-gate _fini(void) 2417c478bd9Sstevel@tonic-gate { 2427c478bd9Sstevel@tonic-gate return (EBUSY); 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate int 2467c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2477c478bd9Sstevel@tonic-gate { 2487c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate extern struct vnode *makespecvp(dev_t dev, vtype_t type); 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate extern kmutex_t ufs_scan_lock; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate static int mountfs(struct vfs *, enum whymountroot, struct vnode *, char *, 2567c478bd9Sstevel@tonic-gate struct cred *, int, void *, int); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate static int 2607c478bd9Sstevel@tonic-gate ufs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap, 2617c478bd9Sstevel@tonic-gate struct cred *cr) 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate { 2647c478bd9Sstevel@tonic-gate char *data = uap->dataptr; 2657c478bd9Sstevel@tonic-gate int datalen = uap->datalen; 2667c478bd9Sstevel@tonic-gate dev_t dev; 26793239addSjohnlev struct vnode *lvp = NULL; 26893239addSjohnlev struct vnode *svp = NULL; 2697c478bd9Sstevel@tonic-gate struct pathname dpn; 2707c478bd9Sstevel@tonic-gate int error; 2717c478bd9Sstevel@tonic-gate enum whymountroot why = ROOT_INIT; 2727c478bd9Sstevel@tonic-gate struct ufs_args args; 2737c478bd9Sstevel@tonic-gate int oflag, aflag; 2747c478bd9Sstevel@tonic-gate int fromspace = (uap->flags & MS_SYSSPACE) ? 2757c478bd9Sstevel@tonic-gate UIO_SYSSPACE : UIO_USERSPACE; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) 2787c478bd9Sstevel@tonic-gate return (error); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate if (mvp->v_type != VDIR) 2817c478bd9Sstevel@tonic-gate return (ENOTDIR); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate mutex_enter(&mvp->v_lock); 2847c478bd9Sstevel@tonic-gate if ((uap->flags & MS_REMOUNT) == 0 && 2857c478bd9Sstevel@tonic-gate (uap->flags & MS_OVERLAY) == 0 && 2867c478bd9Sstevel@tonic-gate (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 2877c478bd9Sstevel@tonic-gate mutex_exit(&mvp->v_lock); 2887c478bd9Sstevel@tonic-gate return (EBUSY); 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate mutex_exit(&mvp->v_lock); 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate /* 2937c478bd9Sstevel@tonic-gate * Get arguments 2947c478bd9Sstevel@tonic-gate */ 2957c478bd9Sstevel@tonic-gate bzero(&args, sizeof (args)); 2967c478bd9Sstevel@tonic-gate if ((uap->flags & MS_DATA) && data != NULL && datalen != 0) { 2977c478bd9Sstevel@tonic-gate int copy_result = 0; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate if (datalen > sizeof (args)) 3007c478bd9Sstevel@tonic-gate return (EINVAL); 3017c478bd9Sstevel@tonic-gate if (uap->flags & MS_SYSSPACE) 3027c478bd9Sstevel@tonic-gate bcopy(data, &args, datalen); 3037c478bd9Sstevel@tonic-gate else 3047c478bd9Sstevel@tonic-gate copy_result = copyin(data, &args, datalen); 3057c478bd9Sstevel@tonic-gate if (copy_result) 3067c478bd9Sstevel@tonic-gate return (EFAULT); 3077c478bd9Sstevel@tonic-gate datalen = sizeof (struct ufs_args); 3087c478bd9Sstevel@tonic-gate } else { 3097c478bd9Sstevel@tonic-gate datalen = 0; 3107c478bd9Sstevel@tonic-gate } 31193239addSjohnlev 31293239addSjohnlev if ((vfsp->vfs_flag & VFS_RDONLY) != 0 || 31393239addSjohnlev (uap->flags & MS_RDONLY) != 0) { 31493239addSjohnlev oflag = FREAD; 31593239addSjohnlev aflag = VREAD; 31693239addSjohnlev } else { 31793239addSjohnlev oflag = FREAD | FWRITE; 31893239addSjohnlev aflag = VREAD | VWRITE; 31993239addSjohnlev } 32093239addSjohnlev 3217c478bd9Sstevel@tonic-gate /* 3227c478bd9Sstevel@tonic-gate * Read in the mount point pathname 3237c478bd9Sstevel@tonic-gate * (so we can record the directory the file system was last mounted on). 3247c478bd9Sstevel@tonic-gate */ 3257c478bd9Sstevel@tonic-gate if (error = pn_get(uap->dir, fromspace, &dpn)) 3267c478bd9Sstevel@tonic-gate return (error); 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /* 3297c478bd9Sstevel@tonic-gate * Resolve path name of special file being mounted. 3307c478bd9Sstevel@tonic-gate */ 33193239addSjohnlev if (error = lookupname(uap->spec, fromspace, FOLLOW, NULL, &svp)) { 3327c478bd9Sstevel@tonic-gate pn_free(&dpn); 3337c478bd9Sstevel@tonic-gate return (error); 3347c478bd9Sstevel@tonic-gate } 33593239addSjohnlev 33693239addSjohnlev error = vfs_get_lofi(vfsp, &lvp); 33793239addSjohnlev 33893239addSjohnlev if (error > 0) { 33993239addSjohnlev VN_RELE(svp); 34093239addSjohnlev pn_free(&dpn); 34193239addSjohnlev return (error); 34293239addSjohnlev } else if (error == 0) { 34393239addSjohnlev dev = lvp->v_rdev; 34493239addSjohnlev 34593239addSjohnlev if (getmajor(dev) >= devcnt) { 34693239addSjohnlev error = ENXIO; 34793239addSjohnlev goto out; 34893239addSjohnlev } 34993239addSjohnlev } else { 35093239addSjohnlev dev = svp->v_rdev; 35193239addSjohnlev 35293239addSjohnlev if (svp->v_type != VBLK) { 35393239addSjohnlev VN_RELE(svp); 3547c478bd9Sstevel@tonic-gate pn_free(&dpn); 3557c478bd9Sstevel@tonic-gate return (ENOTBLK); 3567c478bd9Sstevel@tonic-gate } 35793239addSjohnlev 3587c478bd9Sstevel@tonic-gate if (getmajor(dev) >= devcnt) { 35993239addSjohnlev error = ENXIO; 36093239addSjohnlev goto out; 3617c478bd9Sstevel@tonic-gate } 36293239addSjohnlev 36393239addSjohnlev /* 36493239addSjohnlev * In SunCluster, requests to a global device are 36593239addSjohnlev * satisfied by a local device. We substitute the global 36693239addSjohnlev * pxfs node with a local spec node here. 36793239addSjohnlev */ 36893239addSjohnlev if (IS_PXFSVP(svp)) { 36993239addSjohnlev ASSERT(lvp == NULL); 37093239addSjohnlev VN_RELE(svp); 37193239addSjohnlev svp = makespecvp(dev, VBLK); 37293239addSjohnlev } 37393239addSjohnlev 37493239addSjohnlev if ((error = secpolicy_spec_open(cr, svp, oflag)) != 0) { 37593239addSjohnlev VN_RELE(svp); 37693239addSjohnlev pn_free(&dpn); 37793239addSjohnlev return (error); 37893239addSjohnlev } 37993239addSjohnlev } 38093239addSjohnlev 3817c478bd9Sstevel@tonic-gate if (uap->flags & MS_REMOUNT) 3827c478bd9Sstevel@tonic-gate why = ROOT_REMOUNT; 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate /* 38593239addSjohnlev * Open device/file mounted on. We need this to check whether 38693239addSjohnlev * the caller has sufficient rights to access the resource in 38793239addSjohnlev * question. When bio is fixed for vnodes this can all be vnode 3887c478bd9Sstevel@tonic-gate * operations. 3897c478bd9Sstevel@tonic-gate */ 39093239addSjohnlev if ((error = VOP_ACCESS(svp, aflag, 0, cr, NULL)) != 0) 39193239addSjohnlev goto out; 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate /* 3947c478bd9Sstevel@tonic-gate * Ensure that this device isn't already mounted or in progress on a 3957c478bd9Sstevel@tonic-gate * mount unless this is a REMOUNT request or we are told to suppress 3967c478bd9Sstevel@tonic-gate * mount checks. Global mounts require special handling. 3977c478bd9Sstevel@tonic-gate */ 3987c478bd9Sstevel@tonic-gate if ((uap->flags & MS_NOCHECK) == 0) { 3997c478bd9Sstevel@tonic-gate if ((uap->flags & MS_GLOBAL) == 0 && 4007c478bd9Sstevel@tonic-gate vfs_devmounting(dev, vfsp)) { 40193239addSjohnlev error = EBUSY; 40293239addSjohnlev goto out; 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate if (vfs_devismounted(dev)) { 4057c478bd9Sstevel@tonic-gate if ((uap->flags & MS_REMOUNT) == 0) { 40693239addSjohnlev error = EBUSY; 40793239addSjohnlev goto out; 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* 4137c478bd9Sstevel@tonic-gate * If the device is a tape, mount it read only 4147c478bd9Sstevel@tonic-gate */ 4157c478bd9Sstevel@tonic-gate if (devopsp[getmajor(dev)]->devo_cb_ops->cb_flag & D_TAPE) { 4167c478bd9Sstevel@tonic-gate vfsp->vfs_flag |= VFS_RDONLY; 4177c478bd9Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate if (uap->flags & MS_RDONLY) 4207c478bd9Sstevel@tonic-gate vfsp->vfs_flag |= VFS_RDONLY; 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /* 4237c478bd9Sstevel@tonic-gate * Mount the filesystem, free the device vnode on error. 4247c478bd9Sstevel@tonic-gate */ 42593239addSjohnlev error = mountfs(vfsp, why, lvp != NULL ? lvp : svp, 42693239addSjohnlev dpn.pn_path, cr, 0, &args, datalen); 42793239addSjohnlev 42893239addSjohnlev if (error == 0) { 4299660e5cbSJanice Chang vfs_set_feature(vfsp, VFSFT_SYSATTR_VIEWS); 43093239addSjohnlev 43193239addSjohnlev /* 43293239addSjohnlev * If lofi, drop our reference to the original file. 43393239addSjohnlev */ 43493239addSjohnlev if (lvp != NULL) 43593239addSjohnlev VN_RELE(svp); 43693239addSjohnlev } 43793239addSjohnlev 43893239addSjohnlev out: 43993239addSjohnlev pn_free(&dpn); 44093239addSjohnlev 44193239addSjohnlev if (error) { 44293239addSjohnlev if (lvp != NULL) 44393239addSjohnlev VN_RELE(lvp); 44493239addSjohnlev if (svp != NULL) 44593239addSjohnlev VN_RELE(svp); 44693239addSjohnlev } 4477c478bd9Sstevel@tonic-gate return (error); 4487c478bd9Sstevel@tonic-gate } 44993239addSjohnlev 4507c478bd9Sstevel@tonic-gate /* 4517c478bd9Sstevel@tonic-gate * Mount root file system. 4527c478bd9Sstevel@tonic-gate * "why" is ROOT_INIT on initial call ROOT_REMOUNT if called to 4537c478bd9Sstevel@tonic-gate * remount the root file system, and ROOT_UNMOUNT if called to 4547c478bd9Sstevel@tonic-gate * unmount the root (e.g., as part of a system shutdown). 4557c478bd9Sstevel@tonic-gate * 4567c478bd9Sstevel@tonic-gate * XXX - this may be partially machine-dependent; it, along with the VFS_SWAPVP 4577c478bd9Sstevel@tonic-gate * operation, goes along with auto-configuration. A mechanism should be 4587c478bd9Sstevel@tonic-gate * provided by which machine-INdependent code in the kernel can say "get me the 4597c478bd9Sstevel@tonic-gate * right root file system" and "get me the right initial swap area", and have 4607c478bd9Sstevel@tonic-gate * that done in what may well be a machine-dependent fashion. 4617c478bd9Sstevel@tonic-gate * Unfortunately, it is also file-system-type dependent (NFS gets it via 4627c478bd9Sstevel@tonic-gate * bootparams calls, UFS gets it from various and sundry machine-dependent 4637c478bd9Sstevel@tonic-gate * mechanisms, as SPECFS does for swap). 4647c478bd9Sstevel@tonic-gate */ 4657c478bd9Sstevel@tonic-gate static int 4667c478bd9Sstevel@tonic-gate ufs_mountroot(struct vfs *vfsp, enum whymountroot why) 4677c478bd9Sstevel@tonic-gate { 4687c478bd9Sstevel@tonic-gate struct fs *fsp; 4697c478bd9Sstevel@tonic-gate int error; 4707c478bd9Sstevel@tonic-gate static int ufsrootdone = 0; 4717c478bd9Sstevel@tonic-gate dev_t rootdev; 4727c478bd9Sstevel@tonic-gate struct vnode *vp; 4737c478bd9Sstevel@tonic-gate struct vnode *devvp = 0; 4747c478bd9Sstevel@tonic-gate int ovflags; 4757c478bd9Sstevel@tonic-gate int doclkset; 4767c478bd9Sstevel@tonic-gate ufsvfs_t *ufsvfsp; 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate if (why == ROOT_INIT) { 4797c478bd9Sstevel@tonic-gate if (ufsrootdone++) 4807c478bd9Sstevel@tonic-gate return (EBUSY); 4817c478bd9Sstevel@tonic-gate rootdev = getrootdev(); 4827c478bd9Sstevel@tonic-gate if (rootdev == (dev_t)NODEV) 4837c478bd9Sstevel@tonic-gate return (ENODEV); 4847c478bd9Sstevel@tonic-gate vfsp->vfs_dev = rootdev; 4857c478bd9Sstevel@tonic-gate vfsp->vfs_flag |= VFS_RDONLY; 4867c478bd9Sstevel@tonic-gate } else if (why == ROOT_REMOUNT) { 4877c478bd9Sstevel@tonic-gate vp = ((struct ufsvfs *)vfsp->vfs_data)->vfs_devvp; 4887c478bd9Sstevel@tonic-gate (void) dnlc_purge_vfsp(vfsp, 0); 4897c478bd9Sstevel@tonic-gate vp = common_specvp(vp); 490da6c28aaSamw (void) VOP_PUTPAGE(vp, (offset_t)0, (size_t)0, B_INVAL, 491da6c28aaSamw CRED(), NULL); 4927c478bd9Sstevel@tonic-gate (void) bfinval(vfsp->vfs_dev, 0); 4937c478bd9Sstevel@tonic-gate fsp = getfs(vfsp); 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate ovflags = vfsp->vfs_flag; 4967c478bd9Sstevel@tonic-gate vfsp->vfs_flag &= ~VFS_RDONLY; 4977c478bd9Sstevel@tonic-gate vfsp->vfs_flag |= VFS_REMOUNT; 4987c478bd9Sstevel@tonic-gate rootdev = vfsp->vfs_dev; 4997c478bd9Sstevel@tonic-gate } else if (why == ROOT_UNMOUNT) { 5007c478bd9Sstevel@tonic-gate if (vfs_lock(vfsp) == 0) { 5017c478bd9Sstevel@tonic-gate (void) ufs_flush(vfsp); 5027c478bd9Sstevel@tonic-gate /* 5037c478bd9Sstevel@tonic-gate * Mark the log as fully rolled 5047c478bd9Sstevel@tonic-gate */ 5057c478bd9Sstevel@tonic-gate ufsvfsp = (ufsvfs_t *)vfsp->vfs_data; 5067c478bd9Sstevel@tonic-gate fsp = ufsvfsp->vfs_fs; 5077c478bd9Sstevel@tonic-gate if (TRANS_ISTRANS(ufsvfsp) && 5087c478bd9Sstevel@tonic-gate !TRANS_ISERROR(ufsvfsp) && 5097c478bd9Sstevel@tonic-gate (fsp->fs_rolled == FS_NEED_ROLL)) { 5107c478bd9Sstevel@tonic-gate ml_unit_t *ul = ufsvfsp->vfs_log; 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate error = ufs_putsummaryinfo(ul->un_dev, 5137c478bd9Sstevel@tonic-gate ufsvfsp, fsp); 5147c478bd9Sstevel@tonic-gate if (error == 0) { 5157c478bd9Sstevel@tonic-gate fsp->fs_rolled = FS_ALL_ROLLED; 5167c478bd9Sstevel@tonic-gate UFS_BWRITE2(NULL, ufsvfsp->vfs_bufp); 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate vfs_unlock(vfsp); 5207c478bd9Sstevel@tonic-gate } else { 5217c478bd9Sstevel@tonic-gate ufs_update(0); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate vp = ((struct ufsvfs *)vfsp->vfs_data)->vfs_devvp; 5257c478bd9Sstevel@tonic-gate (void) VOP_CLOSE(vp, FREAD|FWRITE, 1, 526da6c28aaSamw (offset_t)0, CRED(), NULL); 5277c478bd9Sstevel@tonic-gate return (0); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate error = vfs_lock(vfsp); 5307c478bd9Sstevel@tonic-gate if (error) 5317c478bd9Sstevel@tonic-gate return (error); 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate devvp = makespecvp(rootdev, VBLK); 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate /* If RO media, don't call clkset() (see below) */ 5367c478bd9Sstevel@tonic-gate doclkset = 1; 5377c478bd9Sstevel@tonic-gate if (why == ROOT_INIT) { 538da6c28aaSamw error = VOP_OPEN(&devvp, FREAD|FWRITE, CRED(), NULL); 5397c478bd9Sstevel@tonic-gate if (error == 0) { 5407c478bd9Sstevel@tonic-gate (void) VOP_CLOSE(devvp, FREAD|FWRITE, 1, 541da6c28aaSamw (offset_t)0, CRED(), NULL); 5427c478bd9Sstevel@tonic-gate } else { 5437c478bd9Sstevel@tonic-gate doclkset = 0; 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate error = mountfs(vfsp, why, devvp, "/", CRED(), 1, NULL, 0); 5487c478bd9Sstevel@tonic-gate /* 5497c478bd9Sstevel@tonic-gate * XXX - assumes root device is not indirect, because we don't set 5507c478bd9Sstevel@tonic-gate * rootvp. Is rootvp used for anything? If so, make another arg 5517c478bd9Sstevel@tonic-gate * to mountfs. 5527c478bd9Sstevel@tonic-gate */ 5537c478bd9Sstevel@tonic-gate if (error) { 5547c478bd9Sstevel@tonic-gate vfs_unlock(vfsp); 5557c478bd9Sstevel@tonic-gate if (why == ROOT_REMOUNT) 5567c478bd9Sstevel@tonic-gate vfsp->vfs_flag = ovflags; 5577c478bd9Sstevel@tonic-gate if (rootvp) { 5587c478bd9Sstevel@tonic-gate VN_RELE(rootvp); 5597c478bd9Sstevel@tonic-gate rootvp = (struct vnode *)0; 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate VN_RELE(devvp); 5627c478bd9Sstevel@tonic-gate return (error); 5637c478bd9Sstevel@tonic-gate } 5647c478bd9Sstevel@tonic-gate if (why == ROOT_INIT) 5657c478bd9Sstevel@tonic-gate vfs_add((struct vnode *)0, vfsp, 5667c478bd9Sstevel@tonic-gate (vfsp->vfs_flag & VFS_RDONLY) ? MS_RDONLY : 0); 5677c478bd9Sstevel@tonic-gate vfs_unlock(vfsp); 5687c478bd9Sstevel@tonic-gate fsp = getfs(vfsp); 5697c478bd9Sstevel@tonic-gate clkset(doclkset ? fsp->fs_time : -1); 5707c478bd9Sstevel@tonic-gate ufsvfsp = (ufsvfs_t *)vfsp->vfs_data; 5717c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_log) { 5727c478bd9Sstevel@tonic-gate vfs_setmntopt(vfsp, MNTOPT_LOGGING, NULL, 0); 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate return (0); 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate static int 5787c478bd9Sstevel@tonic-gate remountfs(struct vfs *vfsp, dev_t dev, void *raw_argsp, int args_len) 5797c478bd9Sstevel@tonic-gate { 5807c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = (struct ufsvfs *)vfsp->vfs_data; 5817c478bd9Sstevel@tonic-gate struct ulockfs *ulp = &ufsvfsp->vfs_ulockfs; 5827c478bd9Sstevel@tonic-gate struct buf *bp = ufsvfsp->vfs_bufp; 5837c478bd9Sstevel@tonic-gate struct fs *fsp = (struct fs *)bp->b_un.b_addr; 5847c478bd9Sstevel@tonic-gate struct fs *fspt; 5857c478bd9Sstevel@tonic-gate struct buf *tpt = 0; 5867c478bd9Sstevel@tonic-gate int error = 0; 5877c478bd9Sstevel@tonic-gate int flags = 0; 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate if (args_len == sizeof (struct ufs_args) && raw_argsp) 5907c478bd9Sstevel@tonic-gate flags = ((struct ufs_args *)raw_argsp)->flags; 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate /* cannot remount to RDONLY */ 5937c478bd9Sstevel@tonic-gate if (vfsp->vfs_flag & VFS_RDONLY) 59482d71480Ssjelinek return (ENOTSUP); 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate /* whoops, wrong dev */ 5977c478bd9Sstevel@tonic-gate if (vfsp->vfs_dev != dev) 5987c478bd9Sstevel@tonic-gate return (EINVAL); 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate /* 6017c478bd9Sstevel@tonic-gate * synchronize w/ufs ioctls 6027c478bd9Sstevel@tonic-gate */ 6037c478bd9Sstevel@tonic-gate mutex_enter(&ulp->ul_lock); 6041a5e258fSJosef 'Jeff' Sipek atomic_inc_ulong(&ufs_quiesce_pend); 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate /* 6077c478bd9Sstevel@tonic-gate * reset options 6087c478bd9Sstevel@tonic-gate */ 6097c478bd9Sstevel@tonic-gate ufsvfsp->vfs_nointr = flags & UFSMNT_NOINTR; 6107c478bd9Sstevel@tonic-gate ufsvfsp->vfs_syncdir = flags & UFSMNT_SYNCDIR; 6117c478bd9Sstevel@tonic-gate ufsvfsp->vfs_nosetsec = flags & UFSMNT_NOSETSEC; 6127c478bd9Sstevel@tonic-gate ufsvfsp->vfs_noatime = flags & UFSMNT_NOATIME; 6137c478bd9Sstevel@tonic-gate if ((flags & UFSMNT_NODFRATIME) || ufsvfsp->vfs_noatime) 6147c478bd9Sstevel@tonic-gate ufsvfsp->vfs_dfritime &= ~UFS_DFRATIME; 6157c478bd9Sstevel@tonic-gate else /* dfratime, default behavior */ 6167c478bd9Sstevel@tonic-gate ufsvfsp->vfs_dfritime |= UFS_DFRATIME; 6177c478bd9Sstevel@tonic-gate if (flags & UFSMNT_FORCEDIRECTIO) 6187c478bd9Sstevel@tonic-gate ufsvfsp->vfs_forcedirectio = 1; 6197c478bd9Sstevel@tonic-gate else /* default is no direct I/O */ 6207c478bd9Sstevel@tonic-gate ufsvfsp->vfs_forcedirectio = 0; 621d3d50737SRafael Vanoni ufsvfsp->vfs_iotstamp = ddi_get_lbolt(); 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate /* 6247c478bd9Sstevel@tonic-gate * set largefiles flag in ufsvfs equal to the 6257c478bd9Sstevel@tonic-gate * value passed in by the mount command. If 6267c478bd9Sstevel@tonic-gate * it is "nolargefiles", and the flag is set 6277c478bd9Sstevel@tonic-gate * in the superblock, the mount fails. 6287c478bd9Sstevel@tonic-gate */ 6297c478bd9Sstevel@tonic-gate if (!(flags & UFSMNT_LARGEFILES)) { /* "nolargefiles" */ 6307c478bd9Sstevel@tonic-gate if (fsp->fs_flags & FSLARGEFILES) { 6317c478bd9Sstevel@tonic-gate error = EFBIG; 6327c478bd9Sstevel@tonic-gate goto remounterr; 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate ufsvfsp->vfs_lfflags &= ~UFS_LARGEFILES; 6357c478bd9Sstevel@tonic-gate } else /* "largefiles" */ 6367c478bd9Sstevel@tonic-gate ufsvfsp->vfs_lfflags |= UFS_LARGEFILES; 6377c478bd9Sstevel@tonic-gate /* 6387c478bd9Sstevel@tonic-gate * read/write to read/write; all done 6397c478bd9Sstevel@tonic-gate */ 6407c478bd9Sstevel@tonic-gate if (fsp->fs_ronly == 0) 6417c478bd9Sstevel@tonic-gate goto remounterr; 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate /* 6447c478bd9Sstevel@tonic-gate * fix-on-panic assumes RO->RW remount implies system-critical fs 6457c478bd9Sstevel@tonic-gate * if it is shortly after boot; so, don't attempt to lock and fix 6467c478bd9Sstevel@tonic-gate * (unless the user explicitly asked for another action on error) 6477c478bd9Sstevel@tonic-gate * XXX UFSMNT_ONERROR_RDONLY rather than UFSMNT_ONERROR_PANIC 6487c478bd9Sstevel@tonic-gate */ 6497c478bd9Sstevel@tonic-gate #define BOOT_TIME_LIMIT (180*hz) 650d3d50737SRafael Vanoni if (!(flags & UFSMNT_ONERROR_FLGMASK) && 651d3d50737SRafael Vanoni ddi_get_lbolt() < BOOT_TIME_LIMIT) { 6527c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s is required to be mounted onerror=%s", 6537c478bd9Sstevel@tonic-gate ufsvfsp->vfs_fs->fs_fsmnt, UFSMNT_ONERROR_PANIC_STR); 6547c478bd9Sstevel@tonic-gate flags |= UFSMNT_ONERROR_PANIC; 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate if ((error = ufsfx_mount(ufsvfsp, flags)) != 0) 6587c478bd9Sstevel@tonic-gate goto remounterr; 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate /* 66114c932c0Sbatschul * quiesce the file system 6627c478bd9Sstevel@tonic-gate */ 6637c478bd9Sstevel@tonic-gate error = ufs_quiesce(ulp); 6647c478bd9Sstevel@tonic-gate if (error) 6657c478bd9Sstevel@tonic-gate goto remounterr; 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate tpt = UFS_BREAD(ufsvfsp, ufsvfsp->vfs_dev, SBLOCK, SBSIZE); 6687c478bd9Sstevel@tonic-gate if (tpt->b_flags & B_ERROR) { 6697c478bd9Sstevel@tonic-gate error = EIO; 6707c478bd9Sstevel@tonic-gate goto remounterr; 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate fspt = (struct fs *)tpt->b_un.b_addr; 6737c478bd9Sstevel@tonic-gate if (((fspt->fs_magic != FS_MAGIC) && 6747c478bd9Sstevel@tonic-gate (fspt->fs_magic != MTB_UFS_MAGIC)) || 6756451fdbcSvsakar (fspt->fs_magic == FS_MAGIC && 6766451fdbcSvsakar (fspt->fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 && 6776451fdbcSvsakar fspt->fs_version != UFS_VERSION_MIN)) || 6787c478bd9Sstevel@tonic-gate (fspt->fs_magic == MTB_UFS_MAGIC && 6797c478bd9Sstevel@tonic-gate (fspt->fs_version > MTB_UFS_VERSION_1 || 6807c478bd9Sstevel@tonic-gate fspt->fs_version < MTB_UFS_VERSION_MIN)) || 6817c478bd9Sstevel@tonic-gate fspt->fs_bsize > MAXBSIZE || fspt->fs_frag > MAXFRAG || 6827c478bd9Sstevel@tonic-gate fspt->fs_bsize < sizeof (struct fs) || fspt->fs_bsize < PAGESIZE) { 6837c478bd9Sstevel@tonic-gate tpt->b_flags |= B_STALE | B_AGE; 6847c478bd9Sstevel@tonic-gate error = EINVAL; 6857c478bd9Sstevel@tonic-gate goto remounterr; 6867c478bd9Sstevel@tonic-gate } 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_log && (ufsvfsp->vfs_log->un_flags & LDL_NOROLL)) { 6897c478bd9Sstevel@tonic-gate ufsvfsp->vfs_log->un_flags &= ~LDL_NOROLL; 6907c478bd9Sstevel@tonic-gate logmap_start_roll(ufsvfsp->vfs_log); 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate if (TRANS_ISERROR(ufsvfsp)) 6947c478bd9Sstevel@tonic-gate goto remounterr; 6957c478bd9Sstevel@tonic-gate TRANS_DOMATAMAP(ufsvfsp); 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate if ((fspt->fs_state + fspt->fs_time == FSOKAY) && 6987c478bd9Sstevel@tonic-gate fspt->fs_clean == FSLOG && !TRANS_ISTRANS(ufsvfsp)) { 6997c478bd9Sstevel@tonic-gate ufsvfsp->vfs_log = NULL; 7007c478bd9Sstevel@tonic-gate ufsvfsp->vfs_domatamap = 0; 7017c478bd9Sstevel@tonic-gate error = ENOSPC; 7027c478bd9Sstevel@tonic-gate goto remounterr; 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate if (fspt->fs_state + fspt->fs_time == FSOKAY && 7067c478bd9Sstevel@tonic-gate (fspt->fs_clean == FSCLEAN || 7077c478bd9Sstevel@tonic-gate fspt->fs_clean == FSSTABLE || 7087c478bd9Sstevel@tonic-gate fspt->fs_clean == FSLOG)) { 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate /* 7117c478bd9Sstevel@tonic-gate * Ensure that ufs_getsummaryinfo doesn't reconstruct 7127c478bd9Sstevel@tonic-gate * the summary info. 7137c478bd9Sstevel@tonic-gate */ 7147c478bd9Sstevel@tonic-gate error = ufs_getsummaryinfo(vfsp->vfs_dev, ufsvfsp, fspt); 7157c478bd9Sstevel@tonic-gate if (error) 7167c478bd9Sstevel@tonic-gate goto remounterr; 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate /* preserve mount name */ 7197c478bd9Sstevel@tonic-gate (void) strncpy(fspt->fs_fsmnt, fsp->fs_fsmnt, MAXMNTLEN); 7207c478bd9Sstevel@tonic-gate /* free the old cg space */ 7217c478bd9Sstevel@tonic-gate kmem_free(fsp->fs_u.fs_csp, fsp->fs_cssize); 7227c478bd9Sstevel@tonic-gate /* switch in the new superblock */ 7237c478bd9Sstevel@tonic-gate fspt->fs_rolled = FS_NEED_ROLL; 7247c478bd9Sstevel@tonic-gate bcopy(tpt->b_un.b_addr, bp->b_un.b_addr, fspt->fs_sbsize); 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate fsp->fs_clean = FSSTABLE; 7277c478bd9Sstevel@tonic-gate } /* superblock updated in memory */ 7287c478bd9Sstevel@tonic-gate tpt->b_flags |= B_STALE | B_AGE; 7297c478bd9Sstevel@tonic-gate brelse(tpt); 7307c478bd9Sstevel@tonic-gate tpt = 0; 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate if (fsp->fs_clean != FSSTABLE) { 7337c478bd9Sstevel@tonic-gate error = ENOSPC; 7347c478bd9Sstevel@tonic-gate goto remounterr; 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate if (TRANS_ISTRANS(ufsvfsp)) { 7397c478bd9Sstevel@tonic-gate fsp->fs_clean = FSLOG; 7407c478bd9Sstevel@tonic-gate ufsvfsp->vfs_dio = 0; 7417c478bd9Sstevel@tonic-gate } else 7427c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_dio) 7437c478bd9Sstevel@tonic-gate fsp->fs_clean = FSSUSPEND; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate TRANS_MATA_MOUNT(ufsvfsp); 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate fsp->fs_fmod = 0; 7487c478bd9Sstevel@tonic-gate fsp->fs_ronly = 0; 7497c478bd9Sstevel@tonic-gate 7501a5e258fSJosef 'Jeff' Sipek atomic_dec_ulong(&ufs_quiesce_pend); 7517c478bd9Sstevel@tonic-gate cv_broadcast(&ulp->ul_cv); 7527c478bd9Sstevel@tonic-gate mutex_exit(&ulp->ul_lock); 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate if (TRANS_ISTRANS(ufsvfsp)) { 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate /* 7577c478bd9Sstevel@tonic-gate * start the delete thread 7587c478bd9Sstevel@tonic-gate */ 7597c478bd9Sstevel@tonic-gate ufs_thread_start(&ufsvfsp->vfs_delete, ufs_thread_delete, vfsp); 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate /* 7627c478bd9Sstevel@tonic-gate * start the reclaim thread 7637c478bd9Sstevel@tonic-gate */ 7647c478bd9Sstevel@tonic-gate if (fsp->fs_reclaim & (FS_RECLAIM|FS_RECLAIMING)) { 7657c478bd9Sstevel@tonic-gate fsp->fs_reclaim &= ~FS_RECLAIM; 7667c478bd9Sstevel@tonic-gate fsp->fs_reclaim |= FS_RECLAIMING; 7677c478bd9Sstevel@tonic-gate ufs_thread_start(&ufsvfsp->vfs_reclaim, 7687c478bd9Sstevel@tonic-gate ufs_thread_reclaim, vfsp); 7697c478bd9Sstevel@tonic-gate } 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate TRANS_SBWRITE(ufsvfsp, TOP_MOUNT); 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate return (0); 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate remounterr: 7777c478bd9Sstevel@tonic-gate if (tpt) 7787c478bd9Sstevel@tonic-gate brelse(tpt); 7791a5e258fSJosef 'Jeff' Sipek atomic_dec_ulong(&ufs_quiesce_pend); 7807c478bd9Sstevel@tonic-gate cv_broadcast(&ulp->ul_cv); 7817c478bd9Sstevel@tonic-gate mutex_exit(&ulp->ul_lock); 7827c478bd9Sstevel@tonic-gate return (error); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate /* 7867c478bd9Sstevel@tonic-gate * If the device maxtransfer size is not available, we use ufs_maxmaxphys 7877c478bd9Sstevel@tonic-gate * along with the system value for maxphys to determine the value for 7887c478bd9Sstevel@tonic-gate * maxtransfer. 7897c478bd9Sstevel@tonic-gate */ 7907c478bd9Sstevel@tonic-gate int ufs_maxmaxphys = (1024 * 1024); 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate #include <sys/ddi.h> /* for delay(9f) */ 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate int ufs_mount_error_delay = 20; /* default to 20ms */ 79582d71480Ssjelinek int ufs_mount_timeout = 60000; /* default to 1 minute */ 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate static int 7987c478bd9Sstevel@tonic-gate mountfs(struct vfs *vfsp, enum whymountroot why, struct vnode *devvp, 7997c478bd9Sstevel@tonic-gate char *path, cred_t *cr, int isroot, void *raw_argsp, int args_len) 8007c478bd9Sstevel@tonic-gate { 8017c478bd9Sstevel@tonic-gate dev_t dev = devvp->v_rdev; 8027c478bd9Sstevel@tonic-gate struct fs *fsp; 8037c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = 0; 8047c478bd9Sstevel@tonic-gate struct buf *bp = 0; 8057c478bd9Sstevel@tonic-gate struct buf *tp = 0; 8067c478bd9Sstevel@tonic-gate struct dk_cinfo ci; 8077c478bd9Sstevel@tonic-gate int error = 0; 8087c478bd9Sstevel@tonic-gate size_t len; 8097c478bd9Sstevel@tonic-gate int needclose = 0; 8107c478bd9Sstevel@tonic-gate int needtrans = 0; 8117c478bd9Sstevel@tonic-gate struct inode *rip; 8127c478bd9Sstevel@tonic-gate struct vnode *rvp = NULL; 8137c478bd9Sstevel@tonic-gate int flags = 0; 8147c478bd9Sstevel@tonic-gate kmutex_t *ihm; 8157c478bd9Sstevel@tonic-gate int elapsed; 8167c478bd9Sstevel@tonic-gate int status; 8177c478bd9Sstevel@tonic-gate extern int maxphys; 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate if (args_len == sizeof (struct ufs_args) && raw_argsp) 8207c478bd9Sstevel@tonic-gate flags = ((struct ufs_args *)raw_argsp)->flags; 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate ASSERT(vfs_lock_held(vfsp)); 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate if (why == ROOT_INIT) { 8257c478bd9Sstevel@tonic-gate /* 8267c478bd9Sstevel@tonic-gate * Open block device mounted on. 8277c478bd9Sstevel@tonic-gate * When bio is fixed for vnodes this can all be vnode 8287c478bd9Sstevel@tonic-gate * operations. 8297c478bd9Sstevel@tonic-gate */ 8307c478bd9Sstevel@tonic-gate error = VOP_OPEN(&devvp, 831da6c28aaSamw (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE, 832da6c28aaSamw cr, NULL); 8337c478bd9Sstevel@tonic-gate if (error) 8347c478bd9Sstevel@tonic-gate goto out; 8357c478bd9Sstevel@tonic-gate needclose = 1; 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate /* 8387c478bd9Sstevel@tonic-gate * Refuse to go any further if this 8397c478bd9Sstevel@tonic-gate * device is being used for swapping. 8407c478bd9Sstevel@tonic-gate */ 8417c478bd9Sstevel@tonic-gate if (IS_SWAPVP(devvp)) { 8427c478bd9Sstevel@tonic-gate error = EBUSY; 8437c478bd9Sstevel@tonic-gate goto out; 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate 8477c478bd9Sstevel@tonic-gate /* 8487c478bd9Sstevel@tonic-gate * check for dev already mounted on 8497c478bd9Sstevel@tonic-gate */ 8507c478bd9Sstevel@tonic-gate if (vfsp->vfs_flag & VFS_REMOUNT) { 8517c478bd9Sstevel@tonic-gate error = remountfs(vfsp, dev, raw_argsp, args_len); 8527c478bd9Sstevel@tonic-gate if (error == 0) 8537c478bd9Sstevel@tonic-gate VN_RELE(devvp); 8547c478bd9Sstevel@tonic-gate return (error); 8557c478bd9Sstevel@tonic-gate } 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate ASSERT(devvp != 0); 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate /* 8607c478bd9Sstevel@tonic-gate * Flush back any dirty pages on the block device to 8617c478bd9Sstevel@tonic-gate * try and keep the buffer cache in sync with the page 8627c478bd9Sstevel@tonic-gate * cache if someone is trying to use block devices when 8637c478bd9Sstevel@tonic-gate * they really should be using the raw device. 8647c478bd9Sstevel@tonic-gate */ 8657c478bd9Sstevel@tonic-gate (void) VOP_PUTPAGE(common_specvp(devvp), (offset_t)0, 866da6c28aaSamw (size_t)0, B_INVAL, cr, NULL); 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate /* 8697c478bd9Sstevel@tonic-gate * read in superblock 8707c478bd9Sstevel@tonic-gate */ 8717c478bd9Sstevel@tonic-gate ufsvfsp = kmem_zalloc(sizeof (struct ufsvfs), KM_SLEEP); 8727c478bd9Sstevel@tonic-gate tp = UFS_BREAD(ufsvfsp, dev, SBLOCK, SBSIZE); 8737c478bd9Sstevel@tonic-gate if (tp->b_flags & B_ERROR) 8747c478bd9Sstevel@tonic-gate goto out; 8757c478bd9Sstevel@tonic-gate fsp = (struct fs *)tp->b_un.b_addr; 8766451fdbcSvsakar 8777c478bd9Sstevel@tonic-gate if ((fsp->fs_magic != FS_MAGIC) && (fsp->fs_magic != MTB_UFS_MAGIC)) { 8787c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 8796451fdbcSvsakar "mount: not a UFS magic number (0x%x)", fsp->fs_magic); 8806451fdbcSvsakar error = EINVAL; 8816451fdbcSvsakar goto out; 8827c478bd9Sstevel@tonic-gate } 8836451fdbcSvsakar 8846451fdbcSvsakar if ((fsp->fs_magic == FS_MAGIC) && 8856451fdbcSvsakar (fsp->fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 && 8866451fdbcSvsakar fsp->fs_version != UFS_VERSION_MIN)) { 8876451fdbcSvsakar cmn_err(CE_NOTE, 8886451fdbcSvsakar "mount: unrecognized version of UFS on-disk format: %d", 8896451fdbcSvsakar fsp->fs_version); 8907c478bd9Sstevel@tonic-gate error = EINVAL; 8917c478bd9Sstevel@tonic-gate goto out; 8927c478bd9Sstevel@tonic-gate } 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate if ((fsp->fs_magic == MTB_UFS_MAGIC) && 8957c478bd9Sstevel@tonic-gate (fsp->fs_version > MTB_UFS_VERSION_1 || 8967c478bd9Sstevel@tonic-gate fsp->fs_version < MTB_UFS_VERSION_MIN)) { 8977c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 8987c478bd9Sstevel@tonic-gate "mount: unrecognized version of UFS on-disk format: %d", 8997c478bd9Sstevel@tonic-gate fsp->fs_version); 9007c478bd9Sstevel@tonic-gate error = EINVAL; 9017c478bd9Sstevel@tonic-gate goto out; 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 9046451fdbcSvsakar #ifndef _LP64 9057c478bd9Sstevel@tonic-gate if (fsp->fs_magic == MTB_UFS_MAGIC) { 9067c478bd9Sstevel@tonic-gate /* 9077c478bd9Sstevel@tonic-gate * Find the size of the device in sectors. If the 9087c478bd9Sstevel@tonic-gate * the size in sectors is greater than INT_MAX, it's 9097c478bd9Sstevel@tonic-gate * a multi-terabyte file system, which can't be 9107c478bd9Sstevel@tonic-gate * mounted by a 32-bit kernel. We can't use the 9117c478bd9Sstevel@tonic-gate * fsbtodb() macro in the next line because the macro 9127c478bd9Sstevel@tonic-gate * casts the intermediate values to daddr_t, which is 9137c478bd9Sstevel@tonic-gate * a 32-bit quantity in a 32-bit kernel. Here we 9147c478bd9Sstevel@tonic-gate * really do need the intermediate values to be held 9157c478bd9Sstevel@tonic-gate * in 64-bit quantities because we're checking for 9167c478bd9Sstevel@tonic-gate * overflow of a 32-bit field. 9177c478bd9Sstevel@tonic-gate */ 9187c478bd9Sstevel@tonic-gate if ((((diskaddr_t)(fsp->fs_size)) << fsp->fs_fsbtodb) 9197c478bd9Sstevel@tonic-gate > INT_MAX) { 9207c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 9217c478bd9Sstevel@tonic-gate "mount: multi-terabyte UFS cannot be" 9227c478bd9Sstevel@tonic-gate " mounted by a 32-bit kernel"); 9237c478bd9Sstevel@tonic-gate error = EINVAL; 9247c478bd9Sstevel@tonic-gate goto out; 9257c478bd9Sstevel@tonic-gate } 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate } 9286451fdbcSvsakar #endif 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate if (fsp->fs_bsize > MAXBSIZE || fsp->fs_frag > MAXFRAG || 9317c478bd9Sstevel@tonic-gate fsp->fs_bsize < sizeof (struct fs) || fsp->fs_bsize < PAGESIZE) { 9327c478bd9Sstevel@tonic-gate error = EINVAL; /* also needs translation */ 9337c478bd9Sstevel@tonic-gate goto out; 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate /* 9377c478bd9Sstevel@tonic-gate * Allocate VFS private data. 9387c478bd9Sstevel@tonic-gate */ 9397c478bd9Sstevel@tonic-gate vfsp->vfs_bcount = 0; 9407c478bd9Sstevel@tonic-gate vfsp->vfs_data = (caddr_t)ufsvfsp; 9417c478bd9Sstevel@tonic-gate vfsp->vfs_fstype = ufsfstype; 9427c478bd9Sstevel@tonic-gate vfsp->vfs_dev = dev; 9437c478bd9Sstevel@tonic-gate vfsp->vfs_flag |= VFS_NOTRUNC; 9447c478bd9Sstevel@tonic-gate vfs_make_fsid(&vfsp->vfs_fsid, dev, ufsfstype); 9457c478bd9Sstevel@tonic-gate ufsvfsp->vfs_devvp = devvp; 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate /* 9487c478bd9Sstevel@tonic-gate * Cross-link with vfs and add to instance list. 9497c478bd9Sstevel@tonic-gate */ 9507c478bd9Sstevel@tonic-gate ufsvfsp->vfs_vfs = vfsp; 9517c478bd9Sstevel@tonic-gate ufs_vfs_add(ufsvfsp); 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate ufsvfsp->vfs_dev = dev; 9547c478bd9Sstevel@tonic-gate ufsvfsp->vfs_bufp = tp; 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate ufsvfsp->vfs_dirsize = INODESIZE + (4 * ALLOCSIZE) + fsp->fs_fsize; 95780d34432Sfrankho ufsvfsp->vfs_minfrags = 95880d34432Sfrankho (int)((int64_t)fsp->fs_dsize * fsp->fs_minfree / 100); 9597c478bd9Sstevel@tonic-gate /* 9607c478bd9Sstevel@tonic-gate * if mount allows largefiles, indicate so in ufsvfs 9617c478bd9Sstevel@tonic-gate */ 9627c478bd9Sstevel@tonic-gate if (flags & UFSMNT_LARGEFILES) 9637c478bd9Sstevel@tonic-gate ufsvfsp->vfs_lfflags |= UFS_LARGEFILES; 9647c478bd9Sstevel@tonic-gate /* 9657c478bd9Sstevel@tonic-gate * Initialize threads 9667c478bd9Sstevel@tonic-gate */ 967121be23bSjkennedy ufs_delete_init(ufsvfsp, 1); 9687c478bd9Sstevel@tonic-gate ufs_thread_init(&ufsvfsp->vfs_reclaim, 0); 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate /* 9717c478bd9Sstevel@tonic-gate * Chicken and egg problem. The superblock may have deltas 9727c478bd9Sstevel@tonic-gate * in the log. So after the log is scanned we reread the 9737c478bd9Sstevel@tonic-gate * superblock. We guarantee that the fields needed to 9747c478bd9Sstevel@tonic-gate * scan the log will not be in the log. 9757c478bd9Sstevel@tonic-gate */ 9767c478bd9Sstevel@tonic-gate if (fsp->fs_logbno && fsp->fs_clean == FSLOG && 9777c478bd9Sstevel@tonic-gate (fsp->fs_state + fsp->fs_time == FSOKAY)) { 9787c478bd9Sstevel@tonic-gate error = lufs_snarf(ufsvfsp, fsp, (vfsp->vfs_flag & VFS_RDONLY)); 9797c478bd9Sstevel@tonic-gate if (error) { 9807c478bd9Sstevel@tonic-gate /* 9817c478bd9Sstevel@tonic-gate * Allow a ro mount to continue even if the 9827c478bd9Sstevel@tonic-gate * log cannot be processed - yet. 9837c478bd9Sstevel@tonic-gate */ 9847c478bd9Sstevel@tonic-gate if (!(vfsp->vfs_flag & VFS_RDONLY)) { 9857c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "Error accessing ufs " 98680d34432Sfrankho "log for %s; Please run fsck(1M)", path); 9877c478bd9Sstevel@tonic-gate goto out; 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate tp->b_flags |= (B_AGE | B_STALE); 9917c478bd9Sstevel@tonic-gate brelse(tp); 9927c478bd9Sstevel@tonic-gate tp = UFS_BREAD(ufsvfsp, dev, SBLOCK, SBSIZE); 9937c478bd9Sstevel@tonic-gate fsp = (struct fs *)tp->b_un.b_addr; 9947c478bd9Sstevel@tonic-gate ufsvfsp->vfs_bufp = tp; 9957c478bd9Sstevel@tonic-gate if (tp->b_flags & B_ERROR) 9967c478bd9Sstevel@tonic-gate goto out; 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate /* 10007c478bd9Sstevel@tonic-gate * Set logging mounted flag used by lockfs 10017c478bd9Sstevel@tonic-gate */ 10027c478bd9Sstevel@tonic-gate ufsvfsp->vfs_validfs = UT_MOUNTED; 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate /* 10057c478bd9Sstevel@tonic-gate * Copy the super block into a buffer in its native size. 10067c478bd9Sstevel@tonic-gate * Use ngeteblk to allocate the buffer 10077c478bd9Sstevel@tonic-gate */ 10087c478bd9Sstevel@tonic-gate bp = ngeteblk(fsp->fs_bsize); 10097c478bd9Sstevel@tonic-gate ufsvfsp->vfs_bufp = bp; 10107c478bd9Sstevel@tonic-gate bp->b_edev = dev; 10117c478bd9Sstevel@tonic-gate bp->b_dev = cmpdev(dev); 10127c478bd9Sstevel@tonic-gate bp->b_blkno = SBLOCK; 10137c478bd9Sstevel@tonic-gate bp->b_bcount = fsp->fs_sbsize; 10147c478bd9Sstevel@tonic-gate bcopy(tp->b_un.b_addr, bp->b_un.b_addr, fsp->fs_sbsize); 10157c478bd9Sstevel@tonic-gate tp->b_flags |= B_STALE | B_AGE; 10167c478bd9Sstevel@tonic-gate brelse(tp); 10177c478bd9Sstevel@tonic-gate tp = 0; 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate fsp = (struct fs *)bp->b_un.b_addr; 10207c478bd9Sstevel@tonic-gate /* 10217c478bd9Sstevel@tonic-gate * Mount fails if superblock flag indicates presence of large 10227c478bd9Sstevel@tonic-gate * files and filesystem is attempted to be mounted 'nolargefiles'. 10237c478bd9Sstevel@tonic-gate * The exception is for a read only mount of root, which we 10247c478bd9Sstevel@tonic-gate * always want to succeed, so fsck can fix potential problems. 10257c478bd9Sstevel@tonic-gate * The assumption is that we will remount root at some point, 10267c478bd9Sstevel@tonic-gate * and the remount will enforce the mount option. 10277c478bd9Sstevel@tonic-gate */ 10287c478bd9Sstevel@tonic-gate if (!(isroot & (vfsp->vfs_flag & VFS_RDONLY)) && 10297c478bd9Sstevel@tonic-gate (fsp->fs_flags & FSLARGEFILES) && 10307c478bd9Sstevel@tonic-gate !(flags & UFSMNT_LARGEFILES)) { 10317c478bd9Sstevel@tonic-gate error = EFBIG; 10327c478bd9Sstevel@tonic-gate goto out; 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate if (vfsp->vfs_flag & VFS_RDONLY) { 10367c478bd9Sstevel@tonic-gate fsp->fs_ronly = 1; 10377c478bd9Sstevel@tonic-gate fsp->fs_fmod = 0; 10387c478bd9Sstevel@tonic-gate if (((fsp->fs_state + fsp->fs_time) == FSOKAY) && 10397c478bd9Sstevel@tonic-gate ((fsp->fs_clean == FSCLEAN) || 10407c478bd9Sstevel@tonic-gate (fsp->fs_clean == FSSTABLE) || 10417c478bd9Sstevel@tonic-gate (fsp->fs_clean == FSLOG))) { 10427c478bd9Sstevel@tonic-gate if (isroot) { 10437c478bd9Sstevel@tonic-gate if (fsp->fs_clean == FSLOG) { 10447c478bd9Sstevel@tonic-gate if (fsp->fs_rolled == FS_ALL_ROLLED) { 10457c478bd9Sstevel@tonic-gate ufs_clean_root = 1; 10467c478bd9Sstevel@tonic-gate } 10477c478bd9Sstevel@tonic-gate } else { 10487c478bd9Sstevel@tonic-gate ufs_clean_root = 1; 10497c478bd9Sstevel@tonic-gate } 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate fsp->fs_clean = FSSTABLE; 10527c478bd9Sstevel@tonic-gate } else { 10537c478bd9Sstevel@tonic-gate fsp->fs_clean = FSBAD; 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate } else { 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate fsp->fs_fmod = 0; 10587c478bd9Sstevel@tonic-gate fsp->fs_ronly = 0; 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate TRANS_DOMATAMAP(ufsvfsp); 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate if ((TRANS_ISERROR(ufsvfsp)) || 10637c478bd9Sstevel@tonic-gate (((fsp->fs_state + fsp->fs_time) == FSOKAY) && 10647c478bd9Sstevel@tonic-gate fsp->fs_clean == FSLOG && !TRANS_ISTRANS(ufsvfsp))) { 10657c478bd9Sstevel@tonic-gate ufsvfsp->vfs_log = NULL; 10667c478bd9Sstevel@tonic-gate ufsvfsp->vfs_domatamap = 0; 10677c478bd9Sstevel@tonic-gate error = ENOSPC; 10687c478bd9Sstevel@tonic-gate goto out; 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate if (((fsp->fs_state + fsp->fs_time) == FSOKAY) && 10727c478bd9Sstevel@tonic-gate (fsp->fs_clean == FSCLEAN || 10737c478bd9Sstevel@tonic-gate fsp->fs_clean == FSSTABLE || 10747c478bd9Sstevel@tonic-gate fsp->fs_clean == FSLOG)) 10757c478bd9Sstevel@tonic-gate fsp->fs_clean = FSSTABLE; 10767c478bd9Sstevel@tonic-gate else { 10777c478bd9Sstevel@tonic-gate if (isroot) { 10787c478bd9Sstevel@tonic-gate /* 10797c478bd9Sstevel@tonic-gate * allow root partition to be mounted even 10807c478bd9Sstevel@tonic-gate * when fs_state is not ok 10817c478bd9Sstevel@tonic-gate * will be fixed later by a remount root 10827c478bd9Sstevel@tonic-gate */ 10837c478bd9Sstevel@tonic-gate fsp->fs_clean = FSBAD; 10847c478bd9Sstevel@tonic-gate ufsvfsp->vfs_log = NULL; 10857c478bd9Sstevel@tonic-gate ufsvfsp->vfs_domatamap = 0; 10867c478bd9Sstevel@tonic-gate } else { 10877c478bd9Sstevel@tonic-gate error = ENOSPC; 10887c478bd9Sstevel@tonic-gate goto out; 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate if (fsp->fs_clean == FSSTABLE && TRANS_ISTRANS(ufsvfsp)) 10937c478bd9Sstevel@tonic-gate fsp->fs_clean = FSLOG; 10947c478bd9Sstevel@tonic-gate } 10957c478bd9Sstevel@tonic-gate TRANS_MATA_MOUNT(ufsvfsp); 10967c478bd9Sstevel@tonic-gate needtrans = 1; 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate vfsp->vfs_bsize = fsp->fs_bsize; 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate /* 11017c478bd9Sstevel@tonic-gate * Read in summary info 11027c478bd9Sstevel@tonic-gate */ 11037c478bd9Sstevel@tonic-gate if (error = ufs_getsummaryinfo(dev, ufsvfsp, fsp)) 11047c478bd9Sstevel@tonic-gate goto out; 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate /* 11077c478bd9Sstevel@tonic-gate * lastwhinetime is set to zero rather than lbolt, so that after 11087c478bd9Sstevel@tonic-gate * mounting if the filesystem is found to be full, then immediately the 11097c478bd9Sstevel@tonic-gate * "file system message" will be logged. 11107c478bd9Sstevel@tonic-gate */ 11117c478bd9Sstevel@tonic-gate ufsvfsp->vfs_lastwhinetime = 0L; 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate mutex_init(&ufsvfsp->vfs_lock, NULL, MUTEX_DEFAULT, NULL); 11157c478bd9Sstevel@tonic-gate (void) copystr(path, fsp->fs_fsmnt, sizeof (fsp->fs_fsmnt) - 1, &len); 11167c478bd9Sstevel@tonic-gate bzero(fsp->fs_fsmnt + len, sizeof (fsp->fs_fsmnt) - len); 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate /* 11197c478bd9Sstevel@tonic-gate * Sanity checks for old file systems 11207c478bd9Sstevel@tonic-gate */ 11217c478bd9Sstevel@tonic-gate if (fsp->fs_postblformat == FS_42POSTBLFMT) 11227c478bd9Sstevel@tonic-gate ufsvfsp->vfs_nrpos = 8; 11237c478bd9Sstevel@tonic-gate else 11247c478bd9Sstevel@tonic-gate ufsvfsp->vfs_nrpos = fsp->fs_nrpos; 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate /* 11277c478bd9Sstevel@tonic-gate * Initialize lockfs structure to support file system locking 11287c478bd9Sstevel@tonic-gate */ 11297c478bd9Sstevel@tonic-gate bzero(&ufsvfsp->vfs_ulockfs.ul_lockfs, 11307c478bd9Sstevel@tonic-gate sizeof (struct lockfs)); 11317c478bd9Sstevel@tonic-gate ufsvfsp->vfs_ulockfs.ul_fs_lock = ULOCKFS_ULOCK; 11327c478bd9Sstevel@tonic-gate mutex_init(&ufsvfsp->vfs_ulockfs.ul_lock, NULL, 11337c478bd9Sstevel@tonic-gate MUTEX_DEFAULT, NULL); 11347c478bd9Sstevel@tonic-gate cv_init(&ufsvfsp->vfs_ulockfs.ul_cv, NULL, CV_DEFAULT, NULL); 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate /* 11377c478bd9Sstevel@tonic-gate * We don't need to grab vfs_dqrwlock for this ufs_iget() call. 11387c478bd9Sstevel@tonic-gate * We are in the process of mounting the file system so there 11397c478bd9Sstevel@tonic-gate * is no need to grab the quota lock. If a quota applies to the 11407c478bd9Sstevel@tonic-gate * root inode, then it will be updated when quotas are enabled. 11417c478bd9Sstevel@tonic-gate * 11427c478bd9Sstevel@tonic-gate * However, we have an ASSERT(RW_LOCK_HELD(&ufsvfsp->vfs_dqrwlock)) 11437c478bd9Sstevel@tonic-gate * in getinoquota() that we want to keep so grab it anyway. 11447c478bd9Sstevel@tonic-gate */ 11457c478bd9Sstevel@tonic-gate rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER); 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate error = ufs_iget_alloced(vfsp, UFSROOTINO, &rip, cr); 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate rw_exit(&ufsvfsp->vfs_dqrwlock); 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate if (error) 11527c478bd9Sstevel@tonic-gate goto out; 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate /* 11557c478bd9Sstevel@tonic-gate * make sure root inode is a directory. Returning ENOTDIR might 11567c478bd9Sstevel@tonic-gate * be confused with the mount point not being a directory, so 11577c478bd9Sstevel@tonic-gate * we use EIO instead. 11587c478bd9Sstevel@tonic-gate */ 11597c478bd9Sstevel@tonic-gate if ((rip->i_mode & IFMT) != IFDIR) { 11607c478bd9Sstevel@tonic-gate /* 11617c478bd9Sstevel@tonic-gate * Mark this inode as subject for cleanup 11627c478bd9Sstevel@tonic-gate * to avoid stray inodes in the cache. 11637c478bd9Sstevel@tonic-gate */ 11647c478bd9Sstevel@tonic-gate rvp = ITOV(rip); 11657c478bd9Sstevel@tonic-gate error = EIO; 11667c478bd9Sstevel@tonic-gate goto out; 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate rvp = ITOV(rip); 11707c478bd9Sstevel@tonic-gate mutex_enter(&rvp->v_lock); 11717c478bd9Sstevel@tonic-gate rvp->v_flag |= VROOT; 11727c478bd9Sstevel@tonic-gate mutex_exit(&rvp->v_lock); 11737c478bd9Sstevel@tonic-gate ufsvfsp->vfs_root = rvp; 11747c478bd9Sstevel@tonic-gate /* The buffer for the root inode does not contain a valid b_vp */ 11757c478bd9Sstevel@tonic-gate (void) bfinval(dev, 0); 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate /* options */ 11787c478bd9Sstevel@tonic-gate ufsvfsp->vfs_nosetsec = flags & UFSMNT_NOSETSEC; 11797c478bd9Sstevel@tonic-gate ufsvfsp->vfs_nointr = flags & UFSMNT_NOINTR; 11807c478bd9Sstevel@tonic-gate ufsvfsp->vfs_syncdir = flags & UFSMNT_SYNCDIR; 11817c478bd9Sstevel@tonic-gate ufsvfsp->vfs_noatime = flags & UFSMNT_NOATIME; 11827c478bd9Sstevel@tonic-gate if ((flags & UFSMNT_NODFRATIME) || ufsvfsp->vfs_noatime) 11837c478bd9Sstevel@tonic-gate ufsvfsp->vfs_dfritime &= ~UFS_DFRATIME; 11847c478bd9Sstevel@tonic-gate else /* dfratime, default behavior */ 11857c478bd9Sstevel@tonic-gate ufsvfsp->vfs_dfritime |= UFS_DFRATIME; 11867c478bd9Sstevel@tonic-gate if (flags & UFSMNT_FORCEDIRECTIO) 11877c478bd9Sstevel@tonic-gate ufsvfsp->vfs_forcedirectio = 1; 11887c478bd9Sstevel@tonic-gate else if (flags & UFSMNT_NOFORCEDIRECTIO) 11897c478bd9Sstevel@tonic-gate ufsvfsp->vfs_forcedirectio = 0; 1190d3d50737SRafael Vanoni ufsvfsp->vfs_iotstamp = ddi_get_lbolt(); 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate ufsvfsp->vfs_nindiroffset = fsp->fs_nindir - 1; 11937c478bd9Sstevel@tonic-gate ufsvfsp->vfs_nindirshift = highbit(ufsvfsp->vfs_nindiroffset); 11947c478bd9Sstevel@tonic-gate ufsvfsp->vfs_ioclustsz = fsp->fs_bsize * fsp->fs_maxcontig; 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate if (cdev_ioctl(dev, DKIOCINFO, (intptr_t)&ci, 11977c478bd9Sstevel@tonic-gate FKIOCTL|FNATIVE|FREAD, CRED(), &status) == 0) { 11987c478bd9Sstevel@tonic-gate ufsvfsp->vfs_iotransz = ci.dki_maxtransfer * DEV_BSIZE; 11997c478bd9Sstevel@tonic-gate } else { 12007c478bd9Sstevel@tonic-gate ufsvfsp->vfs_iotransz = MIN(maxphys, ufs_maxmaxphys); 12017c478bd9Sstevel@tonic-gate } 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_iotransz <= 0) { 12047c478bd9Sstevel@tonic-gate ufsvfsp->vfs_iotransz = MIN(maxphys, ufs_maxmaxphys); 12057c478bd9Sstevel@tonic-gate } 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate /* 12087c478bd9Sstevel@tonic-gate * When logging, used to reserve log space for writes and truncs 12097c478bd9Sstevel@tonic-gate */ 12107c478bd9Sstevel@tonic-gate ufsvfsp->vfs_avgbfree = fsp->fs_cstotal.cs_nbfree / fsp->fs_ncg; 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate /* 12137c478bd9Sstevel@tonic-gate * Determine whether to log cylinder group summary info. 12147c478bd9Sstevel@tonic-gate */ 12157c478bd9Sstevel@tonic-gate ufsvfsp->vfs_nolog_si = (fsp->fs_ncg < ufs_ncg_log); 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate if (TRANS_ISTRANS(ufsvfsp)) { 12187c478bd9Sstevel@tonic-gate /* 12197c478bd9Sstevel@tonic-gate * start the delete thread 12207c478bd9Sstevel@tonic-gate */ 12217c478bd9Sstevel@tonic-gate ufs_thread_start(&ufsvfsp->vfs_delete, ufs_thread_delete, vfsp); 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate /* 12247c478bd9Sstevel@tonic-gate * start reclaim thread if the filesystem was not mounted 12257c478bd9Sstevel@tonic-gate * read only. 12267c478bd9Sstevel@tonic-gate */ 12277c478bd9Sstevel@tonic-gate if (!fsp->fs_ronly && (fsp->fs_reclaim & 12287c478bd9Sstevel@tonic-gate (FS_RECLAIM|FS_RECLAIMING))) { 12297c478bd9Sstevel@tonic-gate fsp->fs_reclaim &= ~FS_RECLAIM; 12307c478bd9Sstevel@tonic-gate fsp->fs_reclaim |= FS_RECLAIMING; 12317c478bd9Sstevel@tonic-gate ufs_thread_start(&ufsvfsp->vfs_reclaim, 12327c478bd9Sstevel@tonic-gate ufs_thread_reclaim, vfsp); 12337c478bd9Sstevel@tonic-gate } 12347c478bd9Sstevel@tonic-gate 12357c478bd9Sstevel@tonic-gate /* Mark the fs as unrolled */ 12367c478bd9Sstevel@tonic-gate fsp->fs_rolled = FS_NEED_ROLL; 12377c478bd9Sstevel@tonic-gate } else if (!fsp->fs_ronly && (fsp->fs_reclaim & 12387c478bd9Sstevel@tonic-gate (FS_RECLAIM|FS_RECLAIMING))) { 12397c478bd9Sstevel@tonic-gate /* 12407c478bd9Sstevel@tonic-gate * If a file system that is mounted nologging, after 12417c478bd9Sstevel@tonic-gate * having previously been mounted logging, becomes 12427c478bd9Sstevel@tonic-gate * unmounted whilst the reclaim thread is in the throes 12437c478bd9Sstevel@tonic-gate * of reclaiming open/deleted inodes, a subsequent mount 12447c478bd9Sstevel@tonic-gate * of such a file system with logging disabled could lead 12457c478bd9Sstevel@tonic-gate * to inodes becoming lost. So, start reclaim now, even 12467c478bd9Sstevel@tonic-gate * though logging was disabled for the previous mount, to 12477c478bd9Sstevel@tonic-gate * tidy things up. 12487c478bd9Sstevel@tonic-gate */ 12497c478bd9Sstevel@tonic-gate fsp->fs_reclaim &= ~FS_RECLAIM; 12507c478bd9Sstevel@tonic-gate fsp->fs_reclaim |= FS_RECLAIMING; 12517c478bd9Sstevel@tonic-gate ufs_thread_start(&ufsvfsp->vfs_reclaim, 12527c478bd9Sstevel@tonic-gate ufs_thread_reclaim, vfsp); 12537c478bd9Sstevel@tonic-gate } 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate if (!fsp->fs_ronly) { 12567c478bd9Sstevel@tonic-gate TRANS_SBWRITE(ufsvfsp, TOP_MOUNT); 12577c478bd9Sstevel@tonic-gate if (error = geterror(ufsvfsp->vfs_bufp)) 12587c478bd9Sstevel@tonic-gate goto out; 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate /* fix-on-panic initialization */ 12627c478bd9Sstevel@tonic-gate if (isroot && !(flags & UFSMNT_ONERROR_FLGMASK)) 12637c478bd9Sstevel@tonic-gate flags |= UFSMNT_ONERROR_PANIC; /* XXX ..._RDONLY */ 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate if ((error = ufsfx_mount(ufsvfsp, flags)) != 0) 12667c478bd9Sstevel@tonic-gate goto out; 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate if (why == ROOT_INIT && isroot) 12697c478bd9Sstevel@tonic-gate rootvp = devvp; 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate return (0); 12727c478bd9Sstevel@tonic-gate out: 12737c478bd9Sstevel@tonic-gate if (error == 0) 12747c478bd9Sstevel@tonic-gate error = EIO; 12757c478bd9Sstevel@tonic-gate if (rvp) { 12767c478bd9Sstevel@tonic-gate /* the following sequence is similar to ufs_unmount() */ 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate /* 12797c478bd9Sstevel@tonic-gate * There's a problem that ufs_iget() puts inodes into 12807c478bd9Sstevel@tonic-gate * the inode cache before it returns them. If someone 12817c478bd9Sstevel@tonic-gate * traverses that cache and gets a reference to our 12827c478bd9Sstevel@tonic-gate * inode, there's a chance they'll still be using it 12837c478bd9Sstevel@tonic-gate * after we've destroyed it. This is a hard race to 12847c478bd9Sstevel@tonic-gate * hit, but it's happened (putting in a medium delay 12857c478bd9Sstevel@tonic-gate * here, and a large delay in ufs_scan_inodes() for 12867c478bd9Sstevel@tonic-gate * inodes on the device we're bailing out on, makes 12877c478bd9Sstevel@tonic-gate * the race easy to demonstrate). The symptom is some 12887c478bd9Sstevel@tonic-gate * other part of UFS faulting on bad inode contents, 12897c478bd9Sstevel@tonic-gate * or when grabbing one of the locks inside the inode, 12907c478bd9Sstevel@tonic-gate * etc. The usual victim is ufs_scan_inodes() or 12917c478bd9Sstevel@tonic-gate * someone called by it. 12927c478bd9Sstevel@tonic-gate */ 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate /* 12957c478bd9Sstevel@tonic-gate * First, isolate it so that no new references can be 12967c478bd9Sstevel@tonic-gate * gotten via the inode cache. 12977c478bd9Sstevel@tonic-gate */ 12987c478bd9Sstevel@tonic-gate ihm = &ih_lock[INOHASH(UFSROOTINO)]; 12997c478bd9Sstevel@tonic-gate mutex_enter(ihm); 13007c478bd9Sstevel@tonic-gate remque(rip); 13017c478bd9Sstevel@tonic-gate mutex_exit(ihm); 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate /* 13047c478bd9Sstevel@tonic-gate * Now wait for all outstanding references except our 13057c478bd9Sstevel@tonic-gate * own to drain. This could, in theory, take forever, 13067c478bd9Sstevel@tonic-gate * so don't wait *too* long. If we time out, mark 13077c478bd9Sstevel@tonic-gate * it stale and leak it, so we don't hit the problem 13087c478bd9Sstevel@tonic-gate * described above. 13097c478bd9Sstevel@tonic-gate * 13107c478bd9Sstevel@tonic-gate * Note that v_count is an int, which means we can read 13117c478bd9Sstevel@tonic-gate * it in one operation. Thus, there's no need to lock 13127c478bd9Sstevel@tonic-gate * around our tests. 13137c478bd9Sstevel@tonic-gate */ 13147c478bd9Sstevel@tonic-gate elapsed = 0; 13157c478bd9Sstevel@tonic-gate while ((rvp->v_count > 1) && (elapsed < ufs_mount_timeout)) { 13167c478bd9Sstevel@tonic-gate delay(ufs_mount_error_delay * drv_usectohz(1000)); 13177c478bd9Sstevel@tonic-gate elapsed += ufs_mount_error_delay; 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate if (rvp->v_count > 1) { 13217c478bd9Sstevel@tonic-gate mutex_enter(&rip->i_tlock); 13227c478bd9Sstevel@tonic-gate rip->i_flag |= ISTALE; 13237c478bd9Sstevel@tonic-gate mutex_exit(&rip->i_tlock); 13247c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 132580d34432Sfrankho "Timed out while cleaning up after " 132680d34432Sfrankho "failed mount of %s", path); 13277c478bd9Sstevel@tonic-gate } else { 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate /* 13307c478bd9Sstevel@tonic-gate * Now we're the only one with a handle left, so tear 13317c478bd9Sstevel@tonic-gate * it down the rest of the way. 13327c478bd9Sstevel@tonic-gate */ 13337c478bd9Sstevel@tonic-gate if (ufs_rmidle(rip)) 13347c478bd9Sstevel@tonic-gate VN_RELE(rvp); 13357c478bd9Sstevel@tonic-gate ufs_si_del(rip); 13367c478bd9Sstevel@tonic-gate rip->i_ufsvfs = NULL; 13377c478bd9Sstevel@tonic-gate rvp->v_vfsp = NULL; 13387c478bd9Sstevel@tonic-gate rvp->v_type = VBAD; 13397c478bd9Sstevel@tonic-gate VN_RELE(rvp); 13407c478bd9Sstevel@tonic-gate } 13417c478bd9Sstevel@tonic-gate } 13427c478bd9Sstevel@tonic-gate if (needtrans) { 13437c478bd9Sstevel@tonic-gate TRANS_MATA_UMOUNT(ufsvfsp); 13447c478bd9Sstevel@tonic-gate } 13457c478bd9Sstevel@tonic-gate if (ufsvfsp) { 13467c478bd9Sstevel@tonic-gate ufs_vfs_remove(ufsvfsp); 13477c478bd9Sstevel@tonic-gate ufs_thread_exit(&ufsvfsp->vfs_delete); 13487c478bd9Sstevel@tonic-gate ufs_thread_exit(&ufsvfsp->vfs_reclaim); 13497c478bd9Sstevel@tonic-gate mutex_destroy(&ufsvfsp->vfs_lock); 13507c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_log) { 13517c478bd9Sstevel@tonic-gate lufs_unsnarf(ufsvfsp); 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate kmem_free(ufsvfsp, sizeof (struct ufsvfs)); 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate if (bp) { 13567c478bd9Sstevel@tonic-gate bp->b_flags |= (B_STALE|B_AGE); 13577c478bd9Sstevel@tonic-gate brelse(bp); 13587c478bd9Sstevel@tonic-gate } 13597c478bd9Sstevel@tonic-gate if (tp) { 13607c478bd9Sstevel@tonic-gate tp->b_flags |= (B_STALE|B_AGE); 13617c478bd9Sstevel@tonic-gate brelse(tp); 13627c478bd9Sstevel@tonic-gate } 13637c478bd9Sstevel@tonic-gate if (needclose) { 13647c478bd9Sstevel@tonic-gate (void) VOP_CLOSE(devvp, (vfsp->vfs_flag & VFS_RDONLY) ? 1365da6c28aaSamw FREAD : FREAD|FWRITE, 1, (offset_t)0, cr, NULL); 13667c478bd9Sstevel@tonic-gate bflush(dev); 13677c478bd9Sstevel@tonic-gate (void) bfinval(dev, 1); 13687c478bd9Sstevel@tonic-gate } 13697c478bd9Sstevel@tonic-gate return (error); 13707c478bd9Sstevel@tonic-gate } 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate /* 13737c478bd9Sstevel@tonic-gate * vfs operations 13747c478bd9Sstevel@tonic-gate */ 13757c478bd9Sstevel@tonic-gate static int 13767c478bd9Sstevel@tonic-gate ufs_unmount(struct vfs *vfsp, int fflag, struct cred *cr) 13777c478bd9Sstevel@tonic-gate { 13787c478bd9Sstevel@tonic-gate dev_t dev = vfsp->vfs_dev; 13797c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = (struct ufsvfs *)vfsp->vfs_data; 13807c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs; 13817c478bd9Sstevel@tonic-gate struct ulockfs *ulp = &ufsvfsp->vfs_ulockfs; 13827c478bd9Sstevel@tonic-gate struct vnode *bvp, *vp; 13837c478bd9Sstevel@tonic-gate struct buf *bp; 13847c478bd9Sstevel@tonic-gate struct inode *ip, *inext, *rip; 13857c478bd9Sstevel@tonic-gate union ihead *ih; 13867c478bd9Sstevel@tonic-gate int error, flag, i; 13877c478bd9Sstevel@tonic-gate struct lockfs lockfs; 13887c478bd9Sstevel@tonic-gate int poll_events = POLLPRI; 13897c478bd9Sstevel@tonic-gate extern struct pollhead ufs_pollhd; 13907c478bd9Sstevel@tonic-gate refstr_t *mountpoint; 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate ASSERT(vfs_lock_held(vfsp)); 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate if (secpolicy_fs_unmount(cr, vfsp) != 0) 13957c478bd9Sstevel@tonic-gate return (EPERM); 13967c478bd9Sstevel@tonic-gate /* 13977c478bd9Sstevel@tonic-gate * Forced unmount is now supported through the 13987c478bd9Sstevel@tonic-gate * lockfs protocol. 13997c478bd9Sstevel@tonic-gate */ 14007c478bd9Sstevel@tonic-gate if (fflag & MS_FORCE) { 14017c478bd9Sstevel@tonic-gate /* 14027c478bd9Sstevel@tonic-gate * Mark the filesystem as being unmounted now in 14037c478bd9Sstevel@tonic-gate * case of a forcible umount before we take any 14047c478bd9Sstevel@tonic-gate * locks inside UFS to prevent racing with a VFS_VGET() 14057c478bd9Sstevel@tonic-gate * request. Throw these VFS_VGET() requests away for 14067c478bd9Sstevel@tonic-gate * the duration of the forcible umount so they won't 14077c478bd9Sstevel@tonic-gate * use stale or even freed data later on when we're done. 14087c478bd9Sstevel@tonic-gate * It may happen that the VFS has had a additional hold 14097c478bd9Sstevel@tonic-gate * placed on it by someone other than UFS and thus will 14107c478bd9Sstevel@tonic-gate * not get freed immediately once we're done with the 14117c478bd9Sstevel@tonic-gate * umount by dounmount() - use VFS_UNMOUNTED to inform 14127c478bd9Sstevel@tonic-gate * users of this still-alive VFS that its corresponding 14137c478bd9Sstevel@tonic-gate * filesystem being gone so they can detect that and error 14147c478bd9Sstevel@tonic-gate * out. 14157c478bd9Sstevel@tonic-gate */ 14167c478bd9Sstevel@tonic-gate vfsp->vfs_flag |= VFS_UNMOUNTED; 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate ufs_thread_suspend(&ufsvfsp->vfs_delete); 14197c478bd9Sstevel@tonic-gate mutex_enter(&ulp->ul_lock); 14207c478bd9Sstevel@tonic-gate /* 14217c478bd9Sstevel@tonic-gate * If file system is already hard locked, 14227c478bd9Sstevel@tonic-gate * unmount the file system, otherwise 14237c478bd9Sstevel@tonic-gate * hard lock it before unmounting. 14247c478bd9Sstevel@tonic-gate */ 14257c478bd9Sstevel@tonic-gate if (!ULOCKFS_IS_HLOCK(ulp)) { 14261a5e258fSJosef 'Jeff' Sipek atomic_inc_ulong(&ufs_quiesce_pend); 14277c478bd9Sstevel@tonic-gate lockfs.lf_lock = LOCKFS_HLOCK; 14287c478bd9Sstevel@tonic-gate lockfs.lf_flags = 0; 14297c478bd9Sstevel@tonic-gate lockfs.lf_key = ulp->ul_lockfs.lf_key + 1; 14307c478bd9Sstevel@tonic-gate lockfs.lf_comlen = 0; 14317c478bd9Sstevel@tonic-gate lockfs.lf_comment = NULL; 14327c478bd9Sstevel@tonic-gate ufs_freeze(ulp, &lockfs); 14337c478bd9Sstevel@tonic-gate ULOCKFS_SET_BUSY(ulp); 14347c478bd9Sstevel@tonic-gate LOCKFS_SET_BUSY(&ulp->ul_lockfs); 14357c478bd9Sstevel@tonic-gate (void) ufs_quiesce(ulp); 14367c478bd9Sstevel@tonic-gate (void) ufs_flush(vfsp); 14377c478bd9Sstevel@tonic-gate (void) ufs_thaw(vfsp, ufsvfsp, ulp); 14381a5e258fSJosef 'Jeff' Sipek atomic_dec_ulong(&ufs_quiesce_pend); 14397c478bd9Sstevel@tonic-gate ULOCKFS_CLR_BUSY(ulp); 14407c478bd9Sstevel@tonic-gate LOCKFS_CLR_BUSY(&ulp->ul_lockfs); 14417c478bd9Sstevel@tonic-gate poll_events |= POLLERR; 14427c478bd9Sstevel@tonic-gate pollwakeup(&ufs_pollhd, poll_events); 14437c478bd9Sstevel@tonic-gate } 14447c478bd9Sstevel@tonic-gate ufs_thread_continue(&ufsvfsp->vfs_delete); 14457c478bd9Sstevel@tonic-gate mutex_exit(&ulp->ul_lock); 14467c478bd9Sstevel@tonic-gate } 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate /* let all types of writes go through */ 1449d3d50737SRafael Vanoni ufsvfsp->vfs_iotstamp = ddi_get_lbolt(); 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate /* coordinate with global hlock thread */ 14527c478bd9Sstevel@tonic-gate if (TRANS_ISTRANS(ufsvfsp) && (ufsvfsp->vfs_validfs == UT_HLOCKING)) { 14537c478bd9Sstevel@tonic-gate /* 14547c478bd9Sstevel@tonic-gate * last possibility for a forced umount to fail hence clear 14557c478bd9Sstevel@tonic-gate * VFS_UNMOUNTED if appropriate. 14567c478bd9Sstevel@tonic-gate */ 14577c478bd9Sstevel@tonic-gate if (fflag & MS_FORCE) 14587c478bd9Sstevel@tonic-gate vfsp->vfs_flag &= ~VFS_UNMOUNTED; 14597c478bd9Sstevel@tonic-gate return (EAGAIN); 14607c478bd9Sstevel@tonic-gate } 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate ufsvfsp->vfs_validfs = UT_UNMOUNTED; 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate /* kill the reclaim thread */ 14657c478bd9Sstevel@tonic-gate ufs_thread_exit(&ufsvfsp->vfs_reclaim); 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate /* suspend the delete thread */ 14687c478bd9Sstevel@tonic-gate ufs_thread_suspend(&ufsvfsp->vfs_delete); 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate /* 14717c478bd9Sstevel@tonic-gate * drain the delete and idle queues 14727c478bd9Sstevel@tonic-gate */ 14737c478bd9Sstevel@tonic-gate ufs_delete_drain(vfsp, -1, 1); 14747c478bd9Sstevel@tonic-gate ufs_idle_drain(vfsp); 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate /* 14777c478bd9Sstevel@tonic-gate * use the lockfs protocol to prevent new ops from starting 14787c478bd9Sstevel@tonic-gate * a forcible umount can not fail beyond this point as 14797c478bd9Sstevel@tonic-gate * we hard-locked the filesystem and drained all current consumers 14807c478bd9Sstevel@tonic-gate * before. 14817c478bd9Sstevel@tonic-gate */ 14827c478bd9Sstevel@tonic-gate mutex_enter(&ulp->ul_lock); 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate /* 14857c478bd9Sstevel@tonic-gate * if the file system is busy; return EBUSY 14867c478bd9Sstevel@tonic-gate */ 1487303bf60bSsdebnath if (ulp->ul_vnops_cnt || ulp->ul_falloc_cnt || ULOCKFS_IS_SLOCK(ulp)) { 14887c478bd9Sstevel@tonic-gate error = EBUSY; 14897c478bd9Sstevel@tonic-gate goto out; 14907c478bd9Sstevel@tonic-gate } 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate /* 14937c478bd9Sstevel@tonic-gate * if this is not a forced unmount (!hard/error locked), then 14947c478bd9Sstevel@tonic-gate * get rid of every inode except the root and quota inodes 14957c478bd9Sstevel@tonic-gate * also, commit any outstanding transactions 14967c478bd9Sstevel@tonic-gate */ 14977c478bd9Sstevel@tonic-gate if (!ULOCKFS_IS_HLOCK(ulp) && !ULOCKFS_IS_ELOCK(ulp)) 14987c478bd9Sstevel@tonic-gate if (error = ufs_flush(vfsp)) 14997c478bd9Sstevel@tonic-gate goto out; 15007c478bd9Sstevel@tonic-gate 15017c478bd9Sstevel@tonic-gate /* 15027c478bd9Sstevel@tonic-gate * ignore inodes in the cache if fs is hard locked or error locked 15037c478bd9Sstevel@tonic-gate */ 15047c478bd9Sstevel@tonic-gate rip = VTOI(ufsvfsp->vfs_root); 15057c478bd9Sstevel@tonic-gate if (!ULOCKFS_IS_HLOCK(ulp) && !ULOCKFS_IS_ELOCK(ulp)) { 15067c478bd9Sstevel@tonic-gate /* 15077c478bd9Sstevel@tonic-gate * Otherwise, only the quota and root inodes are in the cache. 15087c478bd9Sstevel@tonic-gate * 15097c478bd9Sstevel@tonic-gate * Avoid racing with ufs_update() and ufs_sync(). 15107c478bd9Sstevel@tonic-gate */ 15117c478bd9Sstevel@tonic-gate mutex_enter(&ufs_scan_lock); 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate for (i = 0, ih = ihead; i < inohsz; i++, ih++) { 15147c478bd9Sstevel@tonic-gate mutex_enter(&ih_lock[i]); 15157c478bd9Sstevel@tonic-gate for (ip = ih->ih_chain[0]; 15167c478bd9Sstevel@tonic-gate ip != (struct inode *)ih; 15177c478bd9Sstevel@tonic-gate ip = ip->i_forw) { 15187c478bd9Sstevel@tonic-gate if (ip->i_ufsvfs != ufsvfsp) 15197c478bd9Sstevel@tonic-gate continue; 15207c478bd9Sstevel@tonic-gate if (ip == ufsvfsp->vfs_qinod) 15217c478bd9Sstevel@tonic-gate continue; 15227c478bd9Sstevel@tonic-gate if (ip == rip && ITOV(ip)->v_count == 1) 15237c478bd9Sstevel@tonic-gate continue; 15247c478bd9Sstevel@tonic-gate mutex_exit(&ih_lock[i]); 15257c478bd9Sstevel@tonic-gate mutex_exit(&ufs_scan_lock); 15267c478bd9Sstevel@tonic-gate error = EBUSY; 15277c478bd9Sstevel@tonic-gate goto out; 15287c478bd9Sstevel@tonic-gate } 15297c478bd9Sstevel@tonic-gate mutex_exit(&ih_lock[i]); 15307c478bd9Sstevel@tonic-gate } 15317c478bd9Sstevel@tonic-gate mutex_exit(&ufs_scan_lock); 15327c478bd9Sstevel@tonic-gate } 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate /* 15357c478bd9Sstevel@tonic-gate * if a snapshot exists and this is a forced unmount, then delete 15367c478bd9Sstevel@tonic-gate * the snapshot. Otherwise return EBUSY. This will insure the 15377c478bd9Sstevel@tonic-gate * snapshot always belongs to a valid file system. 15387c478bd9Sstevel@tonic-gate */ 15397c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_snapshot) { 15407c478bd9Sstevel@tonic-gate if (ULOCKFS_IS_HLOCK(ulp) || ULOCKFS_IS_ELOCK(ulp)) { 15417c478bd9Sstevel@tonic-gate (void) fssnap_delete(&ufsvfsp->vfs_snapshot); 15427c478bd9Sstevel@tonic-gate } else { 15437c478bd9Sstevel@tonic-gate error = EBUSY; 15447c478bd9Sstevel@tonic-gate goto out; 15457c478bd9Sstevel@tonic-gate } 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate /* 15497c478bd9Sstevel@tonic-gate * Close the quota file and invalidate anything left in the quota 15507c478bd9Sstevel@tonic-gate * cache for this file system. Pass kcred to allow all quota 15517c478bd9Sstevel@tonic-gate * manipulations. 15527c478bd9Sstevel@tonic-gate */ 15537c478bd9Sstevel@tonic-gate (void) closedq(ufsvfsp, kcred); 15547c478bd9Sstevel@tonic-gate invalidatedq(ufsvfsp); 15557c478bd9Sstevel@tonic-gate /* 15567c478bd9Sstevel@tonic-gate * drain the delete and idle queues 15577c478bd9Sstevel@tonic-gate */ 15587c478bd9Sstevel@tonic-gate ufs_delete_drain(vfsp, -1, 0); 15597c478bd9Sstevel@tonic-gate ufs_idle_drain(vfsp); 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate /* 15627c478bd9Sstevel@tonic-gate * discard the inodes for this fs (including root, shadow, and quota) 15637c478bd9Sstevel@tonic-gate */ 15647c478bd9Sstevel@tonic-gate for (i = 0, ih = ihead; i < inohsz; i++, ih++) { 15657c478bd9Sstevel@tonic-gate mutex_enter(&ih_lock[i]); 15667c478bd9Sstevel@tonic-gate for (inext = 0, ip = ih->ih_chain[0]; 15677c478bd9Sstevel@tonic-gate ip != (struct inode *)ih; 15687c478bd9Sstevel@tonic-gate ip = inext) { 15697c478bd9Sstevel@tonic-gate inext = ip->i_forw; 15707c478bd9Sstevel@tonic-gate if (ip->i_ufsvfs != ufsvfsp) 15717c478bd9Sstevel@tonic-gate continue; 15725bde59abSbatschul 15735bde59abSbatschul /* 15745bde59abSbatschul * We've found the inode in the cache and as we 15755bde59abSbatschul * hold the hash mutex the inode can not 15765bde59abSbatschul * disappear from underneath us. 15775bde59abSbatschul * We also know it must have at least a vnode 15785bde59abSbatschul * reference count of 1. 15795bde59abSbatschul * We perform an additional VN_HOLD so the VN_RELE 15805bde59abSbatschul * in case we take the inode off the idle queue 15815bde59abSbatschul * can not be the last one. 15825bde59abSbatschul * It is safe to grab the writer contents lock here 15835bde59abSbatschul * to prevent a race with ufs_iinactive() putting 15845bde59abSbatschul * inodes into the idle queue while we operate on 15855bde59abSbatschul * this inode. 15865bde59abSbatschul */ 15875bde59abSbatschul rw_enter(&ip->i_contents, RW_WRITER); 15885bde59abSbatschul 15897c478bd9Sstevel@tonic-gate vp = ITOV(ip); 15907c478bd9Sstevel@tonic-gate VN_HOLD(vp) 15917c478bd9Sstevel@tonic-gate remque(ip); 15927c478bd9Sstevel@tonic-gate if (ufs_rmidle(ip)) 15937c478bd9Sstevel@tonic-gate VN_RELE(vp); 15947c478bd9Sstevel@tonic-gate ufs_si_del(ip); 15957c478bd9Sstevel@tonic-gate /* 15967c478bd9Sstevel@tonic-gate * rip->i_ufsvfsp is needed by bflush() 15977c478bd9Sstevel@tonic-gate */ 15987c478bd9Sstevel@tonic-gate if (ip != rip) 15997c478bd9Sstevel@tonic-gate ip->i_ufsvfs = NULL; 16007c478bd9Sstevel@tonic-gate /* 16017c478bd9Sstevel@tonic-gate * Set vnode's vfsops to dummy ops, which return 16027c478bd9Sstevel@tonic-gate * EIO. This is needed to forced unmounts to work 16037c478bd9Sstevel@tonic-gate * with lofs/nfs properly. 16047c478bd9Sstevel@tonic-gate */ 16057c478bd9Sstevel@tonic-gate if (ULOCKFS_IS_HLOCK(ulp) || ULOCKFS_IS_ELOCK(ulp)) 16067c478bd9Sstevel@tonic-gate vp->v_vfsp = &EIO_vfs; 16077c478bd9Sstevel@tonic-gate else 16087c478bd9Sstevel@tonic-gate vp->v_vfsp = NULL; 16097c478bd9Sstevel@tonic-gate vp->v_type = VBAD; 16105bde59abSbatschul 16115bde59abSbatschul rw_exit(&ip->i_contents); 16125bde59abSbatschul 16137c478bd9Sstevel@tonic-gate VN_RELE(vp); 16147c478bd9Sstevel@tonic-gate } 16157c478bd9Sstevel@tonic-gate mutex_exit(&ih_lock[i]); 16167c478bd9Sstevel@tonic-gate } 16177c478bd9Sstevel@tonic-gate ufs_si_cache_flush(dev); 16187c478bd9Sstevel@tonic-gate 16197c478bd9Sstevel@tonic-gate /* 16207c478bd9Sstevel@tonic-gate * kill the delete thread and drain the idle queue 16217c478bd9Sstevel@tonic-gate */ 16227c478bd9Sstevel@tonic-gate ufs_thread_exit(&ufsvfsp->vfs_delete); 16237c478bd9Sstevel@tonic-gate ufs_idle_drain(vfsp); 16247c478bd9Sstevel@tonic-gate 16257c478bd9Sstevel@tonic-gate bp = ufsvfsp->vfs_bufp; 16267c478bd9Sstevel@tonic-gate bvp = ufsvfsp->vfs_devvp; 16277c478bd9Sstevel@tonic-gate flag = !fs->fs_ronly; 16287c478bd9Sstevel@tonic-gate if (flag) { 16297c478bd9Sstevel@tonic-gate bflush(dev); 16307c478bd9Sstevel@tonic-gate if (fs->fs_clean != FSBAD) { 16317c478bd9Sstevel@tonic-gate if (fs->fs_clean == FSSTABLE) 16327c478bd9Sstevel@tonic-gate fs->fs_clean = FSCLEAN; 16337c478bd9Sstevel@tonic-gate fs->fs_reclaim &= ~FS_RECLAIM; 16347c478bd9Sstevel@tonic-gate } 16357c478bd9Sstevel@tonic-gate if (TRANS_ISTRANS(ufsvfsp) && 16367c478bd9Sstevel@tonic-gate !TRANS_ISERROR(ufsvfsp) && 16377c478bd9Sstevel@tonic-gate !ULOCKFS_IS_HLOCK(ulp) && 16387c478bd9Sstevel@tonic-gate (fs->fs_rolled == FS_NEED_ROLL)) { 16397c478bd9Sstevel@tonic-gate /* 16407c478bd9Sstevel@tonic-gate * ufs_flush() above has flushed the last Moby. 16417c478bd9Sstevel@tonic-gate * This is needed to ensure the following superblock 16427c478bd9Sstevel@tonic-gate * update really is the last metadata update 16437c478bd9Sstevel@tonic-gate */ 16447c478bd9Sstevel@tonic-gate error = ufs_putsummaryinfo(dev, ufsvfsp, fs); 16457c478bd9Sstevel@tonic-gate if (error == 0) { 16467c478bd9Sstevel@tonic-gate fs->fs_rolled = FS_ALL_ROLLED; 16477c478bd9Sstevel@tonic-gate } 16487c478bd9Sstevel@tonic-gate } 16497c478bd9Sstevel@tonic-gate TRANS_SBUPDATE(ufsvfsp, vfsp, TOP_SBUPDATE_UNMOUNT); 16507c478bd9Sstevel@tonic-gate /* 16517c478bd9Sstevel@tonic-gate * push this last transaction 16527c478bd9Sstevel@tonic-gate */ 16537c478bd9Sstevel@tonic-gate curthread->t_flag |= T_DONTBLOCK; 16547c478bd9Sstevel@tonic-gate TRANS_BEGIN_SYNC(ufsvfsp, TOP_COMMIT_UNMOUNT, TOP_COMMIT_SIZE, 16557c478bd9Sstevel@tonic-gate error); 16567c478bd9Sstevel@tonic-gate if (!error) 16577c478bd9Sstevel@tonic-gate TRANS_END_SYNC(ufsvfsp, error, TOP_COMMIT_UNMOUNT, 16587c478bd9Sstevel@tonic-gate TOP_COMMIT_SIZE); 16597c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_DONTBLOCK; 16607c478bd9Sstevel@tonic-gate } 16617c478bd9Sstevel@tonic-gate 16627c478bd9Sstevel@tonic-gate TRANS_MATA_UMOUNT(ufsvfsp); 16637c478bd9Sstevel@tonic-gate lufs_unsnarf(ufsvfsp); /* Release the in-memory structs */ 16647c478bd9Sstevel@tonic-gate ufsfx_unmount(ufsvfsp); /* fix-on-panic bookkeeping */ 16657c478bd9Sstevel@tonic-gate kmem_free(fs->fs_u.fs_csp, fs->fs_cssize); 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate bp->b_flags |= B_STALE|B_AGE; 16687c478bd9Sstevel@tonic-gate ufsvfsp->vfs_bufp = NULL; /* don't point at freed buf */ 16697c478bd9Sstevel@tonic-gate brelse(bp); /* free the superblock buf */ 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate (void) VOP_PUTPAGE(common_specvp(bvp), (offset_t)0, (size_t)0, 1672da6c28aaSamw B_INVAL, cr, NULL); 1673da6c28aaSamw (void) VOP_CLOSE(bvp, flag, 1, (offset_t)0, cr, NULL); 16747c478bd9Sstevel@tonic-gate bflush(dev); 16757c478bd9Sstevel@tonic-gate (void) bfinval(dev, 1); 16767c478bd9Sstevel@tonic-gate VN_RELE(bvp); 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate /* 16797c478bd9Sstevel@tonic-gate * It is now safe to NULL out the ufsvfs pointer and discard 16807c478bd9Sstevel@tonic-gate * the root inode. 16817c478bd9Sstevel@tonic-gate */ 16827c478bd9Sstevel@tonic-gate rip->i_ufsvfs = NULL; 16837c478bd9Sstevel@tonic-gate VN_RELE(ITOV(rip)); 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate /* free up lockfs comment structure, if any */ 16867c478bd9Sstevel@tonic-gate if (ulp->ul_lockfs.lf_comlen && ulp->ul_lockfs.lf_comment) 16877c478bd9Sstevel@tonic-gate kmem_free(ulp->ul_lockfs.lf_comment, ulp->ul_lockfs.lf_comlen); 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate /* 16907c478bd9Sstevel@tonic-gate * Remove from instance list. 16917c478bd9Sstevel@tonic-gate */ 16927c478bd9Sstevel@tonic-gate ufs_vfs_remove(ufsvfsp); 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate /* 16957c478bd9Sstevel@tonic-gate * For a forcible unmount, threads may be asleep in 16967c478bd9Sstevel@tonic-gate * ufs_lockfs_begin/ufs_check_lockfs. These threads will need 16977c478bd9Sstevel@tonic-gate * the ufsvfs structure so we don't free it, yet. ufs_update 16987c478bd9Sstevel@tonic-gate * will free it up after awhile. 16997c478bd9Sstevel@tonic-gate */ 17007c478bd9Sstevel@tonic-gate if (ULOCKFS_IS_HLOCK(ulp) || ULOCKFS_IS_ELOCK(ulp)) { 17017c478bd9Sstevel@tonic-gate extern kmutex_t ufsvfs_mutex; 17027c478bd9Sstevel@tonic-gate extern struct ufsvfs *ufsvfslist; 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfs_mutex); 17057c478bd9Sstevel@tonic-gate ufsvfsp->vfs_dontblock = 1; 17067c478bd9Sstevel@tonic-gate ufsvfsp->vfs_next = ufsvfslist; 17077c478bd9Sstevel@tonic-gate ufsvfslist = ufsvfsp; 17087c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfs_mutex); 17097c478bd9Sstevel@tonic-gate /* wakeup any suspended threads */ 17107c478bd9Sstevel@tonic-gate cv_broadcast(&ulp->ul_cv); 17117c478bd9Sstevel@tonic-gate mutex_exit(&ulp->ul_lock); 17127c478bd9Sstevel@tonic-gate } else { 17137c478bd9Sstevel@tonic-gate mutex_destroy(&ufsvfsp->vfs_lock); 17147c478bd9Sstevel@tonic-gate kmem_free(ufsvfsp, sizeof (struct ufsvfs)); 17157c478bd9Sstevel@tonic-gate } 17167c478bd9Sstevel@tonic-gate 17177c478bd9Sstevel@tonic-gate /* 17187c478bd9Sstevel@tonic-gate * Now mark the filesystem as unmounted since we're done with it. 17197c478bd9Sstevel@tonic-gate */ 17207c478bd9Sstevel@tonic-gate vfsp->vfs_flag |= VFS_UNMOUNTED; 17217c478bd9Sstevel@tonic-gate 17227c478bd9Sstevel@tonic-gate return (0); 17237c478bd9Sstevel@tonic-gate out: 17247c478bd9Sstevel@tonic-gate /* open the fs to new ops */ 17257c478bd9Sstevel@tonic-gate cv_broadcast(&ulp->ul_cv); 17267c478bd9Sstevel@tonic-gate mutex_exit(&ulp->ul_lock); 17277c478bd9Sstevel@tonic-gate 17287c478bd9Sstevel@tonic-gate if (TRANS_ISTRANS(ufsvfsp)) { 17297c478bd9Sstevel@tonic-gate /* allow the delete thread to continue */ 17307c478bd9Sstevel@tonic-gate ufs_thread_continue(&ufsvfsp->vfs_delete); 17317c478bd9Sstevel@tonic-gate /* restart the reclaim thread */ 17327c478bd9Sstevel@tonic-gate ufs_thread_start(&ufsvfsp->vfs_reclaim, ufs_thread_reclaim, 17337c478bd9Sstevel@tonic-gate vfsp); 17347c478bd9Sstevel@tonic-gate /* coordinate with global hlock thread */ 17357c478bd9Sstevel@tonic-gate ufsvfsp->vfs_validfs = UT_MOUNTED; 17367c478bd9Sstevel@tonic-gate /* check for trans errors during umount */ 17377c478bd9Sstevel@tonic-gate ufs_trans_onerror(); 17387c478bd9Sstevel@tonic-gate 17397c478bd9Sstevel@tonic-gate /* 1740da6c28aaSamw * if we have a separate /usr it will never unmount 17417c478bd9Sstevel@tonic-gate * when halting. In order to not re-read all the 17427c478bd9Sstevel@tonic-gate * cylinder group summary info on mounting after 17437c478bd9Sstevel@tonic-gate * reboot the logging of summary info is re-enabled 17447c478bd9Sstevel@tonic-gate * and the super block written out. 17457c478bd9Sstevel@tonic-gate */ 17467c478bd9Sstevel@tonic-gate mountpoint = vfs_getmntpoint(vfsp); 17477c478bd9Sstevel@tonic-gate if ((fs->fs_si == FS_SI_OK) && 17487c478bd9Sstevel@tonic-gate (strcmp("/usr", refstr_value(mountpoint)) == 0)) { 17497c478bd9Sstevel@tonic-gate ufsvfsp->vfs_nolog_si = 0; 17507c478bd9Sstevel@tonic-gate UFS_BWRITE2(NULL, ufsvfsp->vfs_bufp); 17517c478bd9Sstevel@tonic-gate } 17527c478bd9Sstevel@tonic-gate refstr_rele(mountpoint); 17537c478bd9Sstevel@tonic-gate } 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate return (error); 17567c478bd9Sstevel@tonic-gate } 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate static int 17597c478bd9Sstevel@tonic-gate ufs_root(struct vfs *vfsp, struct vnode **vpp) 17607c478bd9Sstevel@tonic-gate { 17617c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp; 17627c478bd9Sstevel@tonic-gate struct vnode *vp; 17637c478bd9Sstevel@tonic-gate 17647c478bd9Sstevel@tonic-gate if (!vfsp) 17657c478bd9Sstevel@tonic-gate return (EIO); 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate ufsvfsp = (struct ufsvfs *)vfsp->vfs_data; 17687c478bd9Sstevel@tonic-gate if (!ufsvfsp || !ufsvfsp->vfs_root) 17697c478bd9Sstevel@tonic-gate return (EIO); /* forced unmount */ 17707c478bd9Sstevel@tonic-gate 17717c478bd9Sstevel@tonic-gate vp = ufsvfsp->vfs_root; 17727c478bd9Sstevel@tonic-gate VN_HOLD(vp); 17737c478bd9Sstevel@tonic-gate *vpp = vp; 17747c478bd9Sstevel@tonic-gate return (0); 17757c478bd9Sstevel@tonic-gate } 17767c478bd9Sstevel@tonic-gate 17777c478bd9Sstevel@tonic-gate /* 17787c478bd9Sstevel@tonic-gate * Get file system statistics. 17797c478bd9Sstevel@tonic-gate */ 17807c478bd9Sstevel@tonic-gate static int 17817c478bd9Sstevel@tonic-gate ufs_statvfs(struct vfs *vfsp, struct statvfs64 *sp) 17827c478bd9Sstevel@tonic-gate { 17837c478bd9Sstevel@tonic-gate struct fs *fsp; 17847c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp; 17857c478bd9Sstevel@tonic-gate int blk, i; 17867c478bd9Sstevel@tonic-gate long max_avail, used; 17877c478bd9Sstevel@tonic-gate dev32_t d32; 17887c478bd9Sstevel@tonic-gate 17897c478bd9Sstevel@tonic-gate if (vfsp->vfs_flag & VFS_UNMOUNTED) 17907c478bd9Sstevel@tonic-gate return (EIO); 17917c478bd9Sstevel@tonic-gate 17927c478bd9Sstevel@tonic-gate ufsvfsp = (struct ufsvfs *)vfsp->vfs_data; 17937c478bd9Sstevel@tonic-gate fsp = ufsvfsp->vfs_fs; 17947c478bd9Sstevel@tonic-gate if ((fsp->fs_magic != FS_MAGIC) && (fsp->fs_magic != MTB_UFS_MAGIC)) 17957c478bd9Sstevel@tonic-gate return (EINVAL); 17966451fdbcSvsakar if (fsp->fs_magic == FS_MAGIC && 17976451fdbcSvsakar (fsp->fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 && 17986451fdbcSvsakar fsp->fs_version != UFS_VERSION_MIN)) 17996451fdbcSvsakar return (EINVAL); 18007c478bd9Sstevel@tonic-gate if (fsp->fs_magic == MTB_UFS_MAGIC && 18017c478bd9Sstevel@tonic-gate (fsp->fs_version > MTB_UFS_VERSION_1 || 18027c478bd9Sstevel@tonic-gate fsp->fs_version < MTB_UFS_VERSION_MIN)) 18037c478bd9Sstevel@tonic-gate return (EINVAL); 18047c478bd9Sstevel@tonic-gate 18057c478bd9Sstevel@tonic-gate /* 18067c478bd9Sstevel@tonic-gate * get the basic numbers 18077c478bd9Sstevel@tonic-gate */ 18087c478bd9Sstevel@tonic-gate (void) bzero(sp, sizeof (*sp)); 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate sp->f_bsize = fsp->fs_bsize; 18117c478bd9Sstevel@tonic-gate sp->f_frsize = fsp->fs_fsize; 18127c478bd9Sstevel@tonic-gate sp->f_blocks = (fsblkcnt64_t)fsp->fs_dsize; 18137c478bd9Sstevel@tonic-gate sp->f_bfree = (fsblkcnt64_t)fsp->fs_cstotal.cs_nbfree * fsp->fs_frag + 18147c478bd9Sstevel@tonic-gate fsp->fs_cstotal.cs_nffree; 18157c478bd9Sstevel@tonic-gate 18167c478bd9Sstevel@tonic-gate sp->f_files = (fsfilcnt64_t)fsp->fs_ncg * fsp->fs_ipg; 18177c478bd9Sstevel@tonic-gate sp->f_ffree = (fsfilcnt64_t)fsp->fs_cstotal.cs_nifree; 18187c478bd9Sstevel@tonic-gate 18197c478bd9Sstevel@tonic-gate /* 18207c478bd9Sstevel@tonic-gate * Adjust the numbers based on things waiting to be deleted. 18217c478bd9Sstevel@tonic-gate * modifies f_bfree and f_ffree. Afterwards, everything we 18227c478bd9Sstevel@tonic-gate * come up with will be self-consistent. By definition, this 18237c478bd9Sstevel@tonic-gate * is a point-in-time snapshot, so the fact that the delete 18247c478bd9Sstevel@tonic-gate * thread's probably already invalidated the results is not a 1825121be23bSjkennedy * problem. Note that if the delete thread is ever extended to 1826121be23bSjkennedy * non-logging ufs, this adjustment must always be made. 18277c478bd9Sstevel@tonic-gate */ 1828121be23bSjkennedy if (TRANS_ISTRANS(ufsvfsp)) 18297c478bd9Sstevel@tonic-gate ufs_delete_adjust_stats(ufsvfsp, sp); 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate /* 18327c478bd9Sstevel@tonic-gate * avail = MAX(max_avail - used, 0) 18337c478bd9Sstevel@tonic-gate */ 18347c478bd9Sstevel@tonic-gate max_avail = fsp->fs_dsize - ufsvfsp->vfs_minfrags; 18357c478bd9Sstevel@tonic-gate 18367c478bd9Sstevel@tonic-gate used = (fsp->fs_dsize - sp->f_bfree); 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate if (max_avail > used) 18397c478bd9Sstevel@tonic-gate sp->f_bavail = (fsblkcnt64_t)max_avail - used; 18407c478bd9Sstevel@tonic-gate else 18417c478bd9Sstevel@tonic-gate sp->f_bavail = (fsblkcnt64_t)0; 18427c478bd9Sstevel@tonic-gate 18437c478bd9Sstevel@tonic-gate sp->f_favail = sp->f_ffree; 18447c478bd9Sstevel@tonic-gate (void) cmpldev(&d32, vfsp->vfs_dev); 18457c478bd9Sstevel@tonic-gate sp->f_fsid = d32; 18467c478bd9Sstevel@tonic-gate (void) strcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name); 18477c478bd9Sstevel@tonic-gate sp->f_flag = vf_to_stf(vfsp->vfs_flag); 18487c478bd9Sstevel@tonic-gate 18497c478bd9Sstevel@tonic-gate /* keep coordinated with ufs_l_pathconf() */ 18507c478bd9Sstevel@tonic-gate sp->f_namemax = MAXNAMLEN; 18517c478bd9Sstevel@tonic-gate 18527c478bd9Sstevel@tonic-gate if (fsp->fs_cpc == 0) { 18537c478bd9Sstevel@tonic-gate bzero(sp->f_fstr, 14); 18547c478bd9Sstevel@tonic-gate return (0); 18557c478bd9Sstevel@tonic-gate } 18567c478bd9Sstevel@tonic-gate blk = fsp->fs_spc * fsp->fs_cpc / NSPF(fsp); 18577c478bd9Sstevel@tonic-gate for (i = 0; i < blk; i += fsp->fs_frag) /* CSTYLED */ 18587c478bd9Sstevel@tonic-gate /* void */; 18597c478bd9Sstevel@tonic-gate i -= fsp->fs_frag; 18607c478bd9Sstevel@tonic-gate blk = i / fsp->fs_frag; 18617c478bd9Sstevel@tonic-gate bcopy(&(fs_rotbl(fsp)[blk]), sp->f_fstr, 14); 18627c478bd9Sstevel@tonic-gate return (0); 18637c478bd9Sstevel@tonic-gate } 18647c478bd9Sstevel@tonic-gate 18657c478bd9Sstevel@tonic-gate /* 18667c478bd9Sstevel@tonic-gate * Flush any pending I/O to file system vfsp. 18677c478bd9Sstevel@tonic-gate * The ufs_update() routine will only flush *all* ufs files. 18687c478bd9Sstevel@tonic-gate * If vfsp is non-NULL, only sync this ufs (in preparation 18697c478bd9Sstevel@tonic-gate * for a umount). 18707c478bd9Sstevel@tonic-gate */ 18717c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 18727c478bd9Sstevel@tonic-gate static int 18737c478bd9Sstevel@tonic-gate ufs_sync(struct vfs *vfsp, short flag, struct cred *cr) 18747c478bd9Sstevel@tonic-gate { 18757c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp; 18767c478bd9Sstevel@tonic-gate struct fs *fs; 18777c478bd9Sstevel@tonic-gate int cheap = flag & SYNC_ATTR; 18787c478bd9Sstevel@tonic-gate int error; 18797c478bd9Sstevel@tonic-gate 18807c478bd9Sstevel@tonic-gate /* 18817c478bd9Sstevel@tonic-gate * SYNC_CLOSE means we're rebooting. Toss everything 18827c478bd9Sstevel@tonic-gate * on the idle queue so we don't have to slog through 18837c478bd9Sstevel@tonic-gate * a bunch of uninteresting inodes over and over again. 18847c478bd9Sstevel@tonic-gate */ 18857c478bd9Sstevel@tonic-gate if (flag & SYNC_CLOSE) 18867c478bd9Sstevel@tonic-gate ufs_idle_drain(NULL); 18877c478bd9Sstevel@tonic-gate 18887c478bd9Sstevel@tonic-gate if (vfsp == NULL) { 18897c478bd9Sstevel@tonic-gate ufs_update(flag); 18907c478bd9Sstevel@tonic-gate return (0); 18917c478bd9Sstevel@tonic-gate } 18927c478bd9Sstevel@tonic-gate 18937c478bd9Sstevel@tonic-gate /* Flush a single ufs */ 18947c478bd9Sstevel@tonic-gate if (!vfs_matchops(vfsp, ufs_vfsops) || vfs_lock(vfsp) != 0) 18957c478bd9Sstevel@tonic-gate return (0); 18967c478bd9Sstevel@tonic-gate 18977c478bd9Sstevel@tonic-gate ufsvfsp = (struct ufsvfs *)vfsp->vfs_data; 18987c478bd9Sstevel@tonic-gate if (!ufsvfsp) 18997c478bd9Sstevel@tonic-gate return (EIO); 19007c478bd9Sstevel@tonic-gate fs = ufsvfsp->vfs_fs; 19017c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfsp->vfs_lock); 19027c478bd9Sstevel@tonic-gate 19037c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_dio && 19047c478bd9Sstevel@tonic-gate fs->fs_ronly == 0 && 19057c478bd9Sstevel@tonic-gate fs->fs_clean != FSBAD && 19067c478bd9Sstevel@tonic-gate fs->fs_clean != FSLOG) { 19077c478bd9Sstevel@tonic-gate /* turn off fast-io on unmount, so no fsck needed (4029401) */ 19087c478bd9Sstevel@tonic-gate ufsvfsp->vfs_dio = 0; 19097c478bd9Sstevel@tonic-gate fs->fs_clean = FSACTIVE; 19107c478bd9Sstevel@tonic-gate fs->fs_fmod = 1; 19117c478bd9Sstevel@tonic-gate } 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate /* Write back modified superblock */ 19147c478bd9Sstevel@tonic-gate if (fs->fs_fmod == 0) { 19157c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock); 19167c478bd9Sstevel@tonic-gate } else { 19177c478bd9Sstevel@tonic-gate if (fs->fs_ronly != 0) { 19187c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock); 19197c478bd9Sstevel@tonic-gate vfs_unlock(vfsp); 19207c478bd9Sstevel@tonic-gate return (ufs_fault(ufsvfsp->vfs_root, 192180d34432Sfrankho "fs = %s update: ro fs mod\n", fs->fs_fsmnt)); 19227c478bd9Sstevel@tonic-gate } 19237c478bd9Sstevel@tonic-gate fs->fs_fmod = 0; 19247c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock); 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate TRANS_SBUPDATE(ufsvfsp, vfsp, TOP_SBUPDATE_UPDATE); 19277c478bd9Sstevel@tonic-gate } 19287c478bd9Sstevel@tonic-gate vfs_unlock(vfsp); 19297c478bd9Sstevel@tonic-gate 19307c478bd9Sstevel@tonic-gate /* 19317c478bd9Sstevel@tonic-gate * Avoid racing with ufs_update() and ufs_unmount(). 19327c478bd9Sstevel@tonic-gate * 19337c478bd9Sstevel@tonic-gate */ 19347c478bd9Sstevel@tonic-gate mutex_enter(&ufs_scan_lock); 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate (void) ufs_scan_inodes(1, ufs_sync_inode, 19377c478bd9Sstevel@tonic-gate (void *)(uintptr_t)cheap, ufsvfsp); 19387c478bd9Sstevel@tonic-gate 19397c478bd9Sstevel@tonic-gate mutex_exit(&ufs_scan_lock); 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate bflush((dev_t)vfsp->vfs_dev); 19427c478bd9Sstevel@tonic-gate 19437c478bd9Sstevel@tonic-gate /* 19447c478bd9Sstevel@tonic-gate * commit any outstanding async transactions 19457c478bd9Sstevel@tonic-gate */ 19467c478bd9Sstevel@tonic-gate curthread->t_flag |= T_DONTBLOCK; 19477c478bd9Sstevel@tonic-gate TRANS_BEGIN_SYNC(ufsvfsp, TOP_COMMIT_UPDATE, TOP_COMMIT_SIZE, error); 19487c478bd9Sstevel@tonic-gate if (!error) { 19497c478bd9Sstevel@tonic-gate TRANS_END_SYNC(ufsvfsp, error, TOP_COMMIT_UPDATE, 19507c478bd9Sstevel@tonic-gate TOP_COMMIT_SIZE); 19517c478bd9Sstevel@tonic-gate } 19527c478bd9Sstevel@tonic-gate curthread->t_flag &= ~T_DONTBLOCK; 19537c478bd9Sstevel@tonic-gate 19547c478bd9Sstevel@tonic-gate return (0); 19557c478bd9Sstevel@tonic-gate } 19567c478bd9Sstevel@tonic-gate 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate void 19597c478bd9Sstevel@tonic-gate sbupdate(struct vfs *vfsp) 19607c478bd9Sstevel@tonic-gate { 19617c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = (struct ufsvfs *)vfsp->vfs_data; 19627c478bd9Sstevel@tonic-gate struct fs *fs = ufsvfsp->vfs_fs; 19637c478bd9Sstevel@tonic-gate struct buf *bp; 19647c478bd9Sstevel@tonic-gate int blks; 19657c478bd9Sstevel@tonic-gate caddr_t space; 19667c478bd9Sstevel@tonic-gate int i; 19677c478bd9Sstevel@tonic-gate size_t size; 19687c478bd9Sstevel@tonic-gate 19697c478bd9Sstevel@tonic-gate /* 19707c478bd9Sstevel@tonic-gate * for ulockfs processing, limit the superblock writes 19717c478bd9Sstevel@tonic-gate */ 19727c478bd9Sstevel@tonic-gate if ((ufsvfsp->vfs_ulockfs.ul_sbowner) && 19737c478bd9Sstevel@tonic-gate (curthread != ufsvfsp->vfs_ulockfs.ul_sbowner)) { 19747c478bd9Sstevel@tonic-gate /* process later */ 19757c478bd9Sstevel@tonic-gate fs->fs_fmod = 1; 19767c478bd9Sstevel@tonic-gate return; 19777c478bd9Sstevel@tonic-gate } 19787c478bd9Sstevel@tonic-gate ULOCKFS_SET_MOD((&ufsvfsp->vfs_ulockfs)); 19797c478bd9Sstevel@tonic-gate 19807c478bd9Sstevel@tonic-gate if (TRANS_ISTRANS(ufsvfsp)) { 19817c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfsp->vfs_lock); 19827c478bd9Sstevel@tonic-gate ufs_sbwrite(ufsvfsp); 19837c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock); 19847c478bd9Sstevel@tonic-gate return; 19857c478bd9Sstevel@tonic-gate } 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate blks = howmany(fs->fs_cssize, fs->fs_fsize); 19887c478bd9Sstevel@tonic-gate space = (caddr_t)fs->fs_u.fs_csp; 19897c478bd9Sstevel@tonic-gate for (i = 0; i < blks; i += fs->fs_frag) { 19907c478bd9Sstevel@tonic-gate size = fs->fs_bsize; 19917c478bd9Sstevel@tonic-gate if (i + fs->fs_frag > blks) 19927c478bd9Sstevel@tonic-gate size = (blks - i) * fs->fs_fsize; 19937c478bd9Sstevel@tonic-gate bp = UFS_GETBLK(ufsvfsp, ufsvfsp->vfs_dev, 19947c478bd9Sstevel@tonic-gate (daddr_t)(fsbtodb(fs, fs->fs_csaddr + i)), 19957c478bd9Sstevel@tonic-gate fs->fs_bsize); 19967c478bd9Sstevel@tonic-gate bcopy(space, bp->b_un.b_addr, size); 19977c478bd9Sstevel@tonic-gate space += size; 19987c478bd9Sstevel@tonic-gate bp->b_bcount = size; 19997c478bd9Sstevel@tonic-gate UFS_BRWRITE(ufsvfsp, bp); 20007c478bd9Sstevel@tonic-gate } 20017c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfsp->vfs_lock); 20027c478bd9Sstevel@tonic-gate ufs_sbwrite(ufsvfsp); 20037c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock); 20047c478bd9Sstevel@tonic-gate } 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate int ufs_vget_idle_count = 2; /* Number of inodes to idle each time */ 20077c478bd9Sstevel@tonic-gate static int 20087c478bd9Sstevel@tonic-gate ufs_vget(struct vfs *vfsp, struct vnode **vpp, struct fid *fidp) 20097c478bd9Sstevel@tonic-gate { 20107c478bd9Sstevel@tonic-gate int error = 0; 20117c478bd9Sstevel@tonic-gate struct ufid *ufid; 20127c478bd9Sstevel@tonic-gate struct inode *ip; 20137c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = (struct ufsvfs *)vfsp->vfs_data; 20147c478bd9Sstevel@tonic-gate struct ulockfs *ulp; 20157c478bd9Sstevel@tonic-gate 20167c478bd9Sstevel@tonic-gate /* 20177c478bd9Sstevel@tonic-gate * Check for unmounted filesystem. 20187c478bd9Sstevel@tonic-gate */ 20197c478bd9Sstevel@tonic-gate if (vfsp->vfs_flag & VFS_UNMOUNTED) { 20207c478bd9Sstevel@tonic-gate error = EIO; 20217c478bd9Sstevel@tonic-gate goto errout; 20227c478bd9Sstevel@tonic-gate } 20237c478bd9Sstevel@tonic-gate 20247c478bd9Sstevel@tonic-gate /* 20257c478bd9Sstevel@tonic-gate * Keep the idle queue from getting too long by 20267c478bd9Sstevel@tonic-gate * idling an inode before attempting to allocate another. 20277c478bd9Sstevel@tonic-gate * This operation must be performed before entering 20287c478bd9Sstevel@tonic-gate * lockfs or a transaction. 20297c478bd9Sstevel@tonic-gate */ 20307c478bd9Sstevel@tonic-gate if (ufs_idle_q.uq_ne > ufs_idle_q.uq_hiwat) 20317c478bd9Sstevel@tonic-gate if ((curthread->t_flag & T_DONTBLOCK) == 0) { 20327c478bd9Sstevel@tonic-gate ins.in_vidles.value.ul += ufs_vget_idle_count; 20337c478bd9Sstevel@tonic-gate ufs_idle_some(ufs_vget_idle_count); 20347c478bd9Sstevel@tonic-gate } 20357c478bd9Sstevel@tonic-gate 20367c478bd9Sstevel@tonic-gate ufid = (struct ufid *)fidp; 20377c478bd9Sstevel@tonic-gate 20387c478bd9Sstevel@tonic-gate if (error = ufs_lockfs_begin(ufsvfsp, &ulp, ULOCKFS_VGET_MASK)) 20397c478bd9Sstevel@tonic-gate goto errout; 20407c478bd9Sstevel@tonic-gate 20417c478bd9Sstevel@tonic-gate rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER); 20427c478bd9Sstevel@tonic-gate 20437c478bd9Sstevel@tonic-gate error = ufs_iget(vfsp, ufid->ufid_ino, &ip, CRED()); 20447c478bd9Sstevel@tonic-gate 20457c478bd9Sstevel@tonic-gate rw_exit(&ufsvfsp->vfs_dqrwlock); 20467c478bd9Sstevel@tonic-gate 20477c478bd9Sstevel@tonic-gate ufs_lockfs_end(ulp); 20487c478bd9Sstevel@tonic-gate 20497c478bd9Sstevel@tonic-gate if (error) 20507c478bd9Sstevel@tonic-gate goto errout; 20517c478bd9Sstevel@tonic-gate 20527c478bd9Sstevel@tonic-gate /* 20537c478bd9Sstevel@tonic-gate * Check if the inode has been deleted or freed or is in transient state 20547c478bd9Sstevel@tonic-gate * since the last VFS_VGET() request for it, release it and don't return 20557c478bd9Sstevel@tonic-gate * it to the caller, presumably NFS, as it's no longer valid. 20567c478bd9Sstevel@tonic-gate */ 20577c478bd9Sstevel@tonic-gate if (ip->i_gen != ufid->ufid_gen || ip->i_mode == 0 || 2058e07b36b5Sbatschul (ip->i_nlink <= 0)) { 20597c478bd9Sstevel@tonic-gate VN_RELE(ITOV(ip)); 20607c478bd9Sstevel@tonic-gate error = EINVAL; 20617c478bd9Sstevel@tonic-gate goto errout; 20627c478bd9Sstevel@tonic-gate } 20637c478bd9Sstevel@tonic-gate 20647c478bd9Sstevel@tonic-gate *vpp = ITOV(ip); 20657c478bd9Sstevel@tonic-gate return (0); 20667c478bd9Sstevel@tonic-gate 20677c478bd9Sstevel@tonic-gate errout: 20687c478bd9Sstevel@tonic-gate *vpp = NULL; 20697c478bd9Sstevel@tonic-gate return (error); 20707c478bd9Sstevel@tonic-gate } 20717c478bd9Sstevel@tonic-gate 20727c478bd9Sstevel@tonic-gate static int 20737c478bd9Sstevel@tonic-gate ufsinit(int fstype, char *name) 20747c478bd9Sstevel@tonic-gate { 20757c478bd9Sstevel@tonic-gate static const fs_operation_def_t ufs_vfsops_template[] = { 2076aa59c4cbSrsb VFSNAME_MOUNT, { .vfs_mount = ufs_mount }, 2077aa59c4cbSrsb VFSNAME_UNMOUNT, { .vfs_unmount = ufs_unmount }, 2078aa59c4cbSrsb VFSNAME_ROOT, { .vfs_root = ufs_root }, 2079aa59c4cbSrsb VFSNAME_STATVFS, { .vfs_statvfs = ufs_statvfs }, 2080aa59c4cbSrsb VFSNAME_SYNC, { .vfs_sync = ufs_sync }, 2081aa59c4cbSrsb VFSNAME_VGET, { .vfs_vget = ufs_vget }, 2082aa59c4cbSrsb VFSNAME_MOUNTROOT, { .vfs_mountroot = ufs_mountroot }, 20837c478bd9Sstevel@tonic-gate NULL, NULL 20847c478bd9Sstevel@tonic-gate }; 20857c478bd9Sstevel@tonic-gate int error; 20867c478bd9Sstevel@tonic-gate 20877c478bd9Sstevel@tonic-gate ufsfstype = fstype; 20887c478bd9Sstevel@tonic-gate 20897c478bd9Sstevel@tonic-gate error = vfs_setfsops(fstype, ufs_vfsops_template, &ufs_vfsops); 20907c478bd9Sstevel@tonic-gate if (error != 0) { 20917c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "ufsinit: bad vfs ops template"); 20927c478bd9Sstevel@tonic-gate return (error); 20937c478bd9Sstevel@tonic-gate } 20947c478bd9Sstevel@tonic-gate 20957c478bd9Sstevel@tonic-gate error = vn_make_ops(name, ufs_vnodeops_template, &ufs_vnodeops); 20967c478bd9Sstevel@tonic-gate if (error != 0) { 20977c478bd9Sstevel@tonic-gate (void) vfs_freevfsops_by_type(fstype); 20987c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "ufsinit: bad vnode ops template"); 20997c478bd9Sstevel@tonic-gate return (error); 21007c478bd9Sstevel@tonic-gate } 21017c478bd9Sstevel@tonic-gate 21027c478bd9Sstevel@tonic-gate ufs_iinit(); 21037c478bd9Sstevel@tonic-gate return (0); 21047c478bd9Sstevel@tonic-gate } 2105