xref: /titanic_44/usr/src/uts/common/cpr/cpr_misc.c (revision 8fc99e42676a23421c75e76660640f9765d693b1)
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
5facf4a8dSllai1  * Common Development and Distribution License (the "License").
6facf4a8dSllai1  * 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  */
217c478bd9Sstevel@tonic-gate /*
22*8fc99e42STrevor Thompson  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/errno.h>
287c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
297c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
307c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
317c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
327c478bd9Sstevel@tonic-gate #include <sys/callb.h>
337c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
347c478bd9Sstevel@tonic-gate #include <vm/anon.h>
357c478bd9Sstevel@tonic-gate #include <sys/fs/swapnode.h>	/* for swapfs_minfree */
367c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
377c478bd9Sstevel@tonic-gate #include <sys/cpr.h>
387c478bd9Sstevel@tonic-gate #include <sys/conf.h>
392df1fe9cSrandyf #include <sys/machclock.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * CPR miscellaneous support routines
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate #define	cpr_open(path, mode,  vpp)	(vn_open(path, UIO_SYSSPACE, \
457c478bd9Sstevel@tonic-gate 		mode, 0600, vpp, CRCREAT, 0))
467c478bd9Sstevel@tonic-gate #define	cpr_rdwr(rw, vp, basep, cnt)	(vn_rdwr(rw, vp,  (caddr_t)(basep), \
477c478bd9Sstevel@tonic-gate 		cnt, 0LL, UIO_SYSSPACE, 0, (rlim64_t)MAXOFF_T, CRED(), \
487c478bd9Sstevel@tonic-gate 		(ssize_t *)NULL))
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate extern void clkset(time_t);
517c478bd9Sstevel@tonic-gate extern cpu_t *i_cpr_bootcpu(void);
527c478bd9Sstevel@tonic-gate extern caddr_t i_cpr_map_setup(void);
537c478bd9Sstevel@tonic-gate extern void i_cpr_free_memory_resources(void);
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate extern kmutex_t cpr_slock;
567c478bd9Sstevel@tonic-gate extern size_t cpr_buf_size;
577c478bd9Sstevel@tonic-gate extern char *cpr_buf;
587c478bd9Sstevel@tonic-gate extern size_t cpr_pagedata_size;
597c478bd9Sstevel@tonic-gate extern char *cpr_pagedata;
607c478bd9Sstevel@tonic-gate extern int cpr_bufs_allocated;
617c478bd9Sstevel@tonic-gate extern int cpr_bitmaps_allocated;
627c478bd9Sstevel@tonic-gate 
632df1fe9cSrandyf #if defined(__sparc)
647c478bd9Sstevel@tonic-gate static struct cprconfig cprconfig;
657c478bd9Sstevel@tonic-gate static int cprconfig_loaded = 0;
667c478bd9Sstevel@tonic-gate static int cpr_statefile_ok(vnode_t *, int);
677c478bd9Sstevel@tonic-gate static int cpr_p_online(cpu_t *, int);
687c478bd9Sstevel@tonic-gate static void cpr_save_mp_state(void);
692df1fe9cSrandyf #endif
702df1fe9cSrandyf 
717c478bd9Sstevel@tonic-gate int cpr_is_ufs(struct vfs *);
72e7cbe64fSgw25295 int cpr_is_zfs(struct vfs *);
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate char cpr_default_path[] = CPR_DEFAULT;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate #define	COMPRESS_PERCENT 40	/* approx compression ratio in percent */
777c478bd9Sstevel@tonic-gate #define	SIZE_RATE	115	/* increase size by 15% */
787c478bd9Sstevel@tonic-gate #define	INTEGRAL	100	/* for integer math */
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate /*
827c478bd9Sstevel@tonic-gate  * cmn_err() followed by a 1/4 second delay; this gives the
837c478bd9Sstevel@tonic-gate  * logging service a chance to flush messages and helps avoid
847c478bd9Sstevel@tonic-gate  * intermixing output from prom_printf().
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
877c478bd9Sstevel@tonic-gate void
cpr_err(int ce,const char * fmt,...)887c478bd9Sstevel@tonic-gate cpr_err(int ce, const char *fmt, ...)
897c478bd9Sstevel@tonic-gate {
907c478bd9Sstevel@tonic-gate 	va_list adx;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 	va_start(adx, fmt);
937c478bd9Sstevel@tonic-gate 	vcmn_err(ce, fmt, adx);
947c478bd9Sstevel@tonic-gate 	va_end(adx);
957c478bd9Sstevel@tonic-gate 	drv_usecwait(MICROSEC >> 2);
967c478bd9Sstevel@tonic-gate }
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate int
cpr_init(int fcn)1007c478bd9Sstevel@tonic-gate cpr_init(int fcn)
1017c478bd9Sstevel@tonic-gate {
1027c478bd9Sstevel@tonic-gate 	/*
1037c478bd9Sstevel@tonic-gate 	 * Allow only one suspend/resume process.
1047c478bd9Sstevel@tonic-gate 	 */
1057c478bd9Sstevel@tonic-gate 	if (mutex_tryenter(&cpr_slock) == 0)
1067c478bd9Sstevel@tonic-gate 		return (EBUSY);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	CPR->c_flags = 0;
1097c478bd9Sstevel@tonic-gate 	CPR->c_substate = 0;
1107c478bd9Sstevel@tonic-gate 	CPR->c_cprboot_magic = 0;
1117c478bd9Sstevel@tonic-gate 	CPR->c_alloc_cnt = 0;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	CPR->c_fcn = fcn;
1147c478bd9Sstevel@tonic-gate 	if (fcn == AD_CPR_REUSABLE)
1157c478bd9Sstevel@tonic-gate 		CPR->c_flags |= C_REUSABLE;
1167c478bd9Sstevel@tonic-gate 	else
1177c478bd9Sstevel@tonic-gate 		CPR->c_flags |= C_SUSPENDING;
1182df1fe9cSrandyf 	if (fcn == AD_SUSPEND_TO_RAM || fcn == DEV_SUSPEND_TO_RAM) {
1192df1fe9cSrandyf 		return (0);
1202df1fe9cSrandyf 	}
1212df1fe9cSrandyf #if defined(__sparc)
1227c478bd9Sstevel@tonic-gate 	if (fcn != AD_CPR_NOCOMPRESS && fcn != AD_CPR_TESTNOZ)
1237c478bd9Sstevel@tonic-gate 		CPR->c_flags |= C_COMPRESSING;
1247c478bd9Sstevel@tonic-gate 	/*
1257c478bd9Sstevel@tonic-gate 	 * reserve CPR_MAXCONTIG virtual pages for cpr_dump()
1267c478bd9Sstevel@tonic-gate 	 */
1277c478bd9Sstevel@tonic-gate 	CPR->c_mapping_area = i_cpr_map_setup();
1287c478bd9Sstevel@tonic-gate 	if (CPR->c_mapping_area == 0) {		/* no space in kernelmap */
1297c478bd9Sstevel@tonic-gate 		cpr_err(CE_CONT, "Unable to alloc from kernelmap.\n");
1307c478bd9Sstevel@tonic-gate 		mutex_exit(&cpr_slock);
1317c478bd9Sstevel@tonic-gate 		return (EAGAIN);
1327c478bd9Sstevel@tonic-gate 	}
133ae115bc7Smrj 	if (cpr_debug & CPR_DEBUG3)
134ae115bc7Smrj 		cpr_err(CE_CONT, "Reserved virtual range from 0x%p for writing "
135ae115bc7Smrj 		    "kas\n", (void *)CPR->c_mapping_area);
1362df1fe9cSrandyf #endif
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	return (0);
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate  * This routine releases any resources used during the checkpoint.
1437c478bd9Sstevel@tonic-gate  */
1447c478bd9Sstevel@tonic-gate void
cpr_done(void)1457c478bd9Sstevel@tonic-gate cpr_done(void)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate 	cpr_stat_cleanup();
1487c478bd9Sstevel@tonic-gate 	i_cpr_bitmap_cleanup();
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	/*
1517c478bd9Sstevel@tonic-gate 	 * Free pages used by cpr buffers.
1527c478bd9Sstevel@tonic-gate 	 */
1537c478bd9Sstevel@tonic-gate 	if (cpr_buf) {
1547c478bd9Sstevel@tonic-gate 		kmem_free(cpr_buf, cpr_buf_size);
1557c478bd9Sstevel@tonic-gate 		cpr_buf = NULL;
1567c478bd9Sstevel@tonic-gate 	}
1577c478bd9Sstevel@tonic-gate 	if (cpr_pagedata) {
1587c478bd9Sstevel@tonic-gate 		kmem_free(cpr_pagedata, cpr_pagedata_size);
1597c478bd9Sstevel@tonic-gate 		cpr_pagedata = NULL;
1607c478bd9Sstevel@tonic-gate 	}
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	i_cpr_free_memory_resources();
1637c478bd9Sstevel@tonic-gate 	mutex_exit(&cpr_slock);
1647c478bd9Sstevel@tonic-gate 	cpr_err(CE_CONT, "System has been resumed.\n");
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 
1682df1fe9cSrandyf #if defined(__sparc)
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate  * reads config data into cprconfig
1717c478bd9Sstevel@tonic-gate  */
1727c478bd9Sstevel@tonic-gate static int
cpr_get_config(void)1737c478bd9Sstevel@tonic-gate cpr_get_config(void)
1747c478bd9Sstevel@tonic-gate {
1757c478bd9Sstevel@tonic-gate 	static char config_path[] = CPR_CONFIG;
1767c478bd9Sstevel@tonic-gate 	struct cprconfig *cf = &cprconfig;
1777c478bd9Sstevel@tonic-gate 	struct vnode *vp;
1787c478bd9Sstevel@tonic-gate 	char *fmt;
1797c478bd9Sstevel@tonic-gate 	int err;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	if (cprconfig_loaded)
1827c478bd9Sstevel@tonic-gate 		return (0);
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	fmt = "cannot %s config file \"%s\", error %d\n";
1857c478bd9Sstevel@tonic-gate 	if (err = vn_open(config_path, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0)) {
1867c478bd9Sstevel@tonic-gate 		cpr_err(CE_CONT, fmt, "open", config_path, err);
1877c478bd9Sstevel@tonic-gate 		return (err);
1887c478bd9Sstevel@tonic-gate 	}
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	err = cpr_rdwr(UIO_READ, vp, cf, sizeof (*cf));
191da6c28aaSamw 	(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
1927c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
1937c478bd9Sstevel@tonic-gate 	if (err) {
1947c478bd9Sstevel@tonic-gate 		cpr_err(CE_CONT, fmt, "read", config_path, err);
1957c478bd9Sstevel@tonic-gate 		return (err);
1967c478bd9Sstevel@tonic-gate 	}
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	if (cf->cf_magic == CPR_CONFIG_MAGIC)
1997c478bd9Sstevel@tonic-gate 		cprconfig_loaded = 1;
2007c478bd9Sstevel@tonic-gate 	else {
2017c478bd9Sstevel@tonic-gate 		cpr_err(CE_CONT, "invalid config file \"%s\", "
2027c478bd9Sstevel@tonic-gate 		    "rerun pmconfig(1M)\n", config_path);
2037c478bd9Sstevel@tonic-gate 		err = EINVAL;
2047c478bd9Sstevel@tonic-gate 	}
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	return (err);
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate /*
2117c478bd9Sstevel@tonic-gate  * concat fs and path fields of the cprconfig structure;
2127c478bd9Sstevel@tonic-gate  * returns pointer to the base of static data
2137c478bd9Sstevel@tonic-gate  */
2147c478bd9Sstevel@tonic-gate static char *
cpr_cprconfig_to_path(void)2157c478bd9Sstevel@tonic-gate cpr_cprconfig_to_path(void)
2167c478bd9Sstevel@tonic-gate {
2177c478bd9Sstevel@tonic-gate 	static char full_path[MAXNAMELEN];
2187c478bd9Sstevel@tonic-gate 	struct cprconfig *cf = &cprconfig;
2197c478bd9Sstevel@tonic-gate 	char *ptr;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	/*
2227c478bd9Sstevel@tonic-gate 	 * build /fs/path without extra '/'
2237c478bd9Sstevel@tonic-gate 	 */
2247c478bd9Sstevel@tonic-gate 	(void) strcpy(full_path, cf->cf_fs);
2257c478bd9Sstevel@tonic-gate 	if (strcmp(cf->cf_fs, "/"))
2267c478bd9Sstevel@tonic-gate 		(void) strcat(full_path, "/");
2277c478bd9Sstevel@tonic-gate 	ptr = cf->cf_path;
2287c478bd9Sstevel@tonic-gate 	if (*ptr == '/')
2297c478bd9Sstevel@tonic-gate 		ptr++;
2307c478bd9Sstevel@tonic-gate 	(void) strcat(full_path, ptr);
2317c478bd9Sstevel@tonic-gate 	return (full_path);
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate /*
2367c478bd9Sstevel@tonic-gate  * Verify that the information in the configuration file regarding the
2377c478bd9Sstevel@tonic-gate  * location for the statefile is still valid, depending on cf_type.
2387c478bd9Sstevel@tonic-gate  * for CFT_UFS, cf_fs must still be a mounted filesystem, it must be
2397c478bd9Sstevel@tonic-gate  *	mounted on the same device as when pmconfig was last run,
2407c478bd9Sstevel@tonic-gate  *	and the translation of that device to a node in the prom's
2417c478bd9Sstevel@tonic-gate  *	device tree must be the same as when pmconfig was last run.
242e7cbe64fSgw25295  * for CFT_SPEC and CFT_ZVOL, cf_path must be the path to a block
243e7cbe64fSgw25295  *      special file, it must have no file system mounted on it,
2447c478bd9Sstevel@tonic-gate  *	and the translation of that device to a node in the prom's
2457c478bd9Sstevel@tonic-gate  *	device tree must be the same as when pmconfig was last run.
2467c478bd9Sstevel@tonic-gate  */
2477c478bd9Sstevel@tonic-gate static int
cpr_verify_statefile_path(void)2487c478bd9Sstevel@tonic-gate cpr_verify_statefile_path(void)
2497c478bd9Sstevel@tonic-gate {
2507c478bd9Sstevel@tonic-gate 	struct cprconfig *cf = &cprconfig;
2517c478bd9Sstevel@tonic-gate 	static const char long_name[] = "Statefile pathname is too long.\n";
2527c478bd9Sstevel@tonic-gate 	static const char lookup_fmt[] = "Lookup failed for "
2537c478bd9Sstevel@tonic-gate 	    "cpr statefile device %s.\n";
2547c478bd9Sstevel@tonic-gate 	static const char path_chg_fmt[] = "Device path for statefile "
2557c478bd9Sstevel@tonic-gate 	    "has changed from %s to %s.\t%s\n";
2567c478bd9Sstevel@tonic-gate 	static const char rerun[] = "Please rerun pmconfig(1m).";
2577c478bd9Sstevel@tonic-gate 	struct vfs *vfsp = NULL, *vfsp_save = rootvfs;
2587c478bd9Sstevel@tonic-gate 	ufsvfs_t *ufsvfsp = (ufsvfs_t *)rootvfs->vfs_data;
2597c478bd9Sstevel@tonic-gate 	ufsvfs_t *ufsvfsp_save = ufsvfsp;
2607c478bd9Sstevel@tonic-gate 	int error;
2617c478bd9Sstevel@tonic-gate 	struct vnode *vp;
2627c478bd9Sstevel@tonic-gate 	char *slash, *tail, *longest;
2637c478bd9Sstevel@tonic-gate 	char *errstr;
2647c478bd9Sstevel@tonic-gate 	int found = 0;
2657c478bd9Sstevel@tonic-gate 	union {
2667c478bd9Sstevel@tonic-gate 		char un_devpath[OBP_MAXPATHLEN];
2677c478bd9Sstevel@tonic-gate 		char un_sfpath[MAXNAMELEN];
2687c478bd9Sstevel@tonic-gate 	} un;
2697c478bd9Sstevel@tonic-gate #define	devpath	un.un_devpath
2707c478bd9Sstevel@tonic-gate #define	sfpath	un.un_sfpath
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	ASSERT(cprconfig_loaded);
2737c478bd9Sstevel@tonic-gate 	/*
2747c478bd9Sstevel@tonic-gate 	 * We need not worry about locking or the timing of releasing
2757c478bd9Sstevel@tonic-gate 	 * the vnode, since we are single-threaded now.
2767c478bd9Sstevel@tonic-gate 	 */
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	switch (cf->cf_type) {
2797c478bd9Sstevel@tonic-gate 	case CFT_SPEC:
280e7cbe64fSgw25295 		error = i_devname_to_promname(cf->cf_devfs, devpath,
281e7cbe64fSgw25295 		    OBP_MAXPATHLEN);
282e7cbe64fSgw25295 		if (error || strcmp(devpath, cf->cf_dev_prom)) {
283e7cbe64fSgw25295 			cpr_err(CE_CONT, path_chg_fmt,
284e7cbe64fSgw25295 			    cf->cf_dev_prom, devpath, rerun);
285e7cbe64fSgw25295 			return (error);
286e7cbe64fSgw25295 		}
287e7cbe64fSgw25295 		/*FALLTHROUGH*/
288e7cbe64fSgw25295 	case CFT_ZVOL:
2897c478bd9Sstevel@tonic-gate 		if (strlen(cf->cf_path) > sizeof (sfpath)) {
2907c478bd9Sstevel@tonic-gate 			cpr_err(CE_CONT, long_name);
2917c478bd9Sstevel@tonic-gate 			return (ENAMETOOLONG);
2927c478bd9Sstevel@tonic-gate 		}
2937c478bd9Sstevel@tonic-gate 		if ((error = lookupname(cf->cf_devfs,
2947c478bd9Sstevel@tonic-gate 		    UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) != 0) {
2957c478bd9Sstevel@tonic-gate 			cpr_err(CE_CONT, lookup_fmt, cf->cf_devfs);
2967c478bd9Sstevel@tonic-gate 			return (error);
2977c478bd9Sstevel@tonic-gate 		}
2987c478bd9Sstevel@tonic-gate 		if (vp->v_type != VBLK)
2997c478bd9Sstevel@tonic-gate 			errstr = "statefile must be a block device";
3007c478bd9Sstevel@tonic-gate 		else if (vfs_devismounted(vp->v_rdev))
3017c478bd9Sstevel@tonic-gate 			errstr = "statefile device must not "
3027c478bd9Sstevel@tonic-gate 			    "have a file system mounted on it";
3037c478bd9Sstevel@tonic-gate 		else if (IS_SWAPVP(vp))
3047c478bd9Sstevel@tonic-gate 			errstr = "statefile device must not "
3057c478bd9Sstevel@tonic-gate 			    "be configured as swap file";
3067c478bd9Sstevel@tonic-gate 		else
3077c478bd9Sstevel@tonic-gate 			errstr = NULL;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
3107c478bd9Sstevel@tonic-gate 		if (errstr) {
3117c478bd9Sstevel@tonic-gate 			cpr_err(CE_CONT, "%s.\n", errstr);
3127c478bd9Sstevel@tonic-gate 			return (ENOTSUP);
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 		return (error);
3167c478bd9Sstevel@tonic-gate 	case CFT_UFS:
3177c478bd9Sstevel@tonic-gate 		break;		/* don't indent all the original code */
3187c478bd9Sstevel@tonic-gate 	default:
3197c478bd9Sstevel@tonic-gate 		cpr_err(CE_PANIC, "invalid cf_type");
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	/*
3237c478bd9Sstevel@tonic-gate 	 * The original code for UFS statefile
3247c478bd9Sstevel@tonic-gate 	 */
3257c478bd9Sstevel@tonic-gate 	if (strlen(cf->cf_fs) + strlen(cf->cf_path) + 2 > sizeof (sfpath)) {
3267c478bd9Sstevel@tonic-gate 		cpr_err(CE_CONT, long_name);
3277c478bd9Sstevel@tonic-gate 		return (ENAMETOOLONG);
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	bzero(sfpath, sizeof (sfpath));
3317c478bd9Sstevel@tonic-gate 	(void) strcpy(sfpath, cpr_cprconfig_to_path());
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	if (*sfpath != '/') {
3347c478bd9Sstevel@tonic-gate 		cpr_err(CE_CONT, "Statefile pathname %s "
3357c478bd9Sstevel@tonic-gate 		    "must begin with a /\n", sfpath);
3367c478bd9Sstevel@tonic-gate 		return (EINVAL);
3377c478bd9Sstevel@tonic-gate 	}
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	/*
3407c478bd9Sstevel@tonic-gate 	 * Find the longest prefix of the statefile pathname which
3417c478bd9Sstevel@tonic-gate 	 * is the mountpoint of a filesystem.  This string must
3427c478bd9Sstevel@tonic-gate 	 * match the cf_fs field we read from the config file.  Other-
3437c478bd9Sstevel@tonic-gate 	 * wise the user has changed things without running pmconfig.
3447c478bd9Sstevel@tonic-gate 	 */
3457c478bd9Sstevel@tonic-gate 	tail = longest = sfpath + 1;	/* pt beyond the leading "/" */
3467c478bd9Sstevel@tonic-gate 	while ((slash = strchr(tail, '/')) != NULL) {
3477c478bd9Sstevel@tonic-gate 		*slash = '\0';	  /* temporarily terminate the string */
3487c478bd9Sstevel@tonic-gate 		if ((error = lookupname(sfpath,
3497c478bd9Sstevel@tonic-gate 		    UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) != 0) {
3507c478bd9Sstevel@tonic-gate 			*slash = '/';
3517c478bd9Sstevel@tonic-gate 			cpr_err(CE_CONT, "A directory in the "
3527c478bd9Sstevel@tonic-gate 			    "statefile path %s was not found.\n", sfpath);
3537c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 			return (error);
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 		vfs_list_read_lock();
3597c478bd9Sstevel@tonic-gate 		vfsp = rootvfs;
3607c478bd9Sstevel@tonic-gate 		do {
3617c478bd9Sstevel@tonic-gate 			ufsvfsp = (struct ufsvfs *)vfsp->vfs_data;
3627c478bd9Sstevel@tonic-gate 			if (ufsvfsp != NULL && ufsvfsp->vfs_root == vp) {
3637c478bd9Sstevel@tonic-gate 				found = 1;
3647c478bd9Sstevel@tonic-gate 				break;
3657c478bd9Sstevel@tonic-gate 			}
3667c478bd9Sstevel@tonic-gate 			vfsp = vfsp->vfs_next;
3677c478bd9Sstevel@tonic-gate 		} while (vfsp != rootvfs);
3687c478bd9Sstevel@tonic-gate 		vfs_list_unlock();
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 		/*
3717c478bd9Sstevel@tonic-gate 		 * If we have found a filesystem mounted on the current
3727c478bd9Sstevel@tonic-gate 		 * path prefix, remember the end of the string in
3737c478bd9Sstevel@tonic-gate 		 * "longest".  If it happens to be the the exact fs
3747c478bd9Sstevel@tonic-gate 		 * saved in the configuration file, save the current
3757c478bd9Sstevel@tonic-gate 		 * ufsvfsp so we can make additional checks further down.
3767c478bd9Sstevel@tonic-gate 		 */
3777c478bd9Sstevel@tonic-gate 		if (found) {
3787c478bd9Sstevel@tonic-gate 			longest = slash;
3797c478bd9Sstevel@tonic-gate 			if (strcmp(cf->cf_fs, sfpath) == 0) {
3807c478bd9Sstevel@tonic-gate 				ufsvfsp_save = ufsvfsp;
3817c478bd9Sstevel@tonic-gate 				vfsp_save = vfsp;
3827c478bd9Sstevel@tonic-gate 			}
3837c478bd9Sstevel@tonic-gate 			found = 0;
3847c478bd9Sstevel@tonic-gate 		}
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
3877c478bd9Sstevel@tonic-gate 		*slash = '/';
3887c478bd9Sstevel@tonic-gate 		tail = slash + 1;
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 	*longest = '\0';
3917c478bd9Sstevel@tonic-gate 	if (cpr_is_ufs(vfsp_save) == 0 || strcmp(cf->cf_fs, sfpath)) {
3927c478bd9Sstevel@tonic-gate 		cpr_err(CE_CONT, "Filesystem containing "
3937c478bd9Sstevel@tonic-gate 		    "the statefile when pmconfig was run (%s) has "
3947c478bd9Sstevel@tonic-gate 		    "changed to %s. %s\n", cf->cf_fs, sfpath, rerun);
3957c478bd9Sstevel@tonic-gate 		return (EINVAL);
3967c478bd9Sstevel@tonic-gate 	}
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	if ((error = lookupname(cf->cf_devfs,
3997c478bd9Sstevel@tonic-gate 	    UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) != 0) {
4007c478bd9Sstevel@tonic-gate 		cpr_err(CE_CONT, lookup_fmt, cf->cf_devfs);
4017c478bd9Sstevel@tonic-gate 		return (error);
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	if (ufsvfsp_save->vfs_devvp->v_rdev != vp->v_rdev) {
4057c478bd9Sstevel@tonic-gate 		cpr_err(CE_CONT, "Filesystem containing "
4067c478bd9Sstevel@tonic-gate 		    "statefile no longer mounted on device %s. "
4077c478bd9Sstevel@tonic-gate 		    "See power.conf(4).", cf->cf_devfs);
4087c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
4097c478bd9Sstevel@tonic-gate 		return (ENXIO);
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	error = i_devname_to_promname(cf->cf_devfs, devpath, OBP_MAXPATHLEN);
4147c478bd9Sstevel@tonic-gate 	if (error || strcmp(devpath, cf->cf_dev_prom)) {
4157c478bd9Sstevel@tonic-gate 		cpr_err(CE_CONT, path_chg_fmt,
4167c478bd9Sstevel@tonic-gate 		    cf->cf_dev_prom, devpath, rerun);
4177c478bd9Sstevel@tonic-gate 		return (error);
4187c478bd9Sstevel@tonic-gate 	}
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	return (0);
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate /*
4247c478bd9Sstevel@tonic-gate  * Make sure that the statefile can be used as a block special statefile
4257c478bd9Sstevel@tonic-gate  * (meaning that is exists and has nothing mounted on it)
4267c478bd9Sstevel@tonic-gate  * Returns errno if not a valid statefile.
4277c478bd9Sstevel@tonic-gate  */
4287c478bd9Sstevel@tonic-gate int
cpr_check_spec_statefile(void)4297c478bd9Sstevel@tonic-gate cpr_check_spec_statefile(void)
4307c478bd9Sstevel@tonic-gate {
4317c478bd9Sstevel@tonic-gate 	int err;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	if (err = cpr_get_config())
4347c478bd9Sstevel@tonic-gate 		return (err);
435e7cbe64fSgw25295 	ASSERT(cprconfig.cf_type == CFT_SPEC ||
436e7cbe64fSgw25295 	    cprconfig.cf_type == CFT_ZVOL);
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	if (cprconfig.cf_devfs == NULL)
4397c478bd9Sstevel@tonic-gate 		return (ENXIO);
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	return (cpr_verify_statefile_path());
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate int
cpr_alloc_statefile(int alloc_retry)4467c478bd9Sstevel@tonic-gate cpr_alloc_statefile(int alloc_retry)
4477c478bd9Sstevel@tonic-gate {
4487c478bd9Sstevel@tonic-gate 	register int rc = 0;
4497c478bd9Sstevel@tonic-gate 	char *str;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	/*
4527c478bd9Sstevel@tonic-gate 	 * Statefile size validation. If checkpoint the first time, disk blocks
4537c478bd9Sstevel@tonic-gate 	 * allocation will be done; otherwise, just do file size check.
4547c478bd9Sstevel@tonic-gate 	 * if statefile allocation is being retried, C_VP will be inited
4557c478bd9Sstevel@tonic-gate 	 */
4567c478bd9Sstevel@tonic-gate 	if (alloc_retry) {
4577c478bd9Sstevel@tonic-gate 		str = "\n-->Retrying statefile allocation...";
458ae115bc7Smrj 		if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG7))
459ae115bc7Smrj 			prom_printf(str);
4607c478bd9Sstevel@tonic-gate 		if (C_VP->v_type != VBLK)
461da6c28aaSamw 			(void) VOP_DUMPCTL(C_VP, DUMP_FREE, NULL, NULL);
4627c478bd9Sstevel@tonic-gate 	} else {
4637c478bd9Sstevel@tonic-gate 		/*
4647c478bd9Sstevel@tonic-gate 		 * Open an exiting file for writing, the state file needs to be
4657c478bd9Sstevel@tonic-gate 		 * pre-allocated since we can't and don't want to do allocation
4667c478bd9Sstevel@tonic-gate 		 * during checkpoint (too much of the OS is disabled).
4677c478bd9Sstevel@tonic-gate 		 *    - do a preliminary size checking here, if it is too small,
4687c478bd9Sstevel@tonic-gate 		 *	allocate more space internally and retry.
4697c478bd9Sstevel@tonic-gate 		 *    - check the vp to make sure it's the right type.
4707c478bd9Sstevel@tonic-gate 		 */
4717c478bd9Sstevel@tonic-gate 		char *path = cpr_build_statefile_path();
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 		if (path == NULL)
4747c478bd9Sstevel@tonic-gate 			return (ENXIO);
4757c478bd9Sstevel@tonic-gate 		else if (rc = cpr_verify_statefile_path())
4767c478bd9Sstevel@tonic-gate 			return (rc);
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 		if (rc = vn_open(path, UIO_SYSSPACE,
4797c478bd9Sstevel@tonic-gate 		    FCREAT|FWRITE, 0600, &C_VP, CRCREAT, 0)) {
4807c478bd9Sstevel@tonic-gate 			cpr_err(CE_WARN, "cannot open statefile %s", path);
4817c478bd9Sstevel@tonic-gate 			return (rc);
4827c478bd9Sstevel@tonic-gate 		}
4837c478bd9Sstevel@tonic-gate 	}
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	/*
4867c478bd9Sstevel@tonic-gate 	 * Only ufs and block special statefiles supported
4877c478bd9Sstevel@tonic-gate 	 */
4887c478bd9Sstevel@tonic-gate 	if (C_VP->v_type != VREG && C_VP->v_type != VBLK) {
4897c478bd9Sstevel@tonic-gate 		cpr_err(CE_CONT,
4907c478bd9Sstevel@tonic-gate 		    "Statefile must be regular file or block special file.");
4917c478bd9Sstevel@tonic-gate 		return (EACCES);
4927c478bd9Sstevel@tonic-gate 	}
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	if (rc = cpr_statefile_ok(C_VP, alloc_retry))
4957c478bd9Sstevel@tonic-gate 		return (rc);
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	if (C_VP->v_type != VBLK) {
4987c478bd9Sstevel@tonic-gate 		/*
4997c478bd9Sstevel@tonic-gate 		 * sync out the fs change due to the statefile reservation.
5007c478bd9Sstevel@tonic-gate 		 */
5017c478bd9Sstevel@tonic-gate 		(void) VFS_SYNC(C_VP->v_vfsp, 0, CRED());
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 		/*
5047c478bd9Sstevel@tonic-gate 		 * Validate disk blocks allocation for the state file.
5057c478bd9Sstevel@tonic-gate 		 * Ask the file system prepare itself for the dump operation.
5067c478bd9Sstevel@tonic-gate 		 */
507da6c28aaSamw 		if (rc = VOP_DUMPCTL(C_VP, DUMP_ALLOC, NULL, NULL)) {
5087c478bd9Sstevel@tonic-gate 			cpr_err(CE_CONT, "Error allocating "
5097c478bd9Sstevel@tonic-gate 			    "blocks for cpr statefile.");
5107c478bd9Sstevel@tonic-gate 			return (rc);
5117c478bd9Sstevel@tonic-gate 		}
5127c478bd9Sstevel@tonic-gate 	}
5137c478bd9Sstevel@tonic-gate 	return (0);
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate /*
518184cd04cScth  * Lookup device size and return available space in bytes.
519184cd04cScth  * NOTE: Since prop_op(9E) can't tell the difference between a character
520184cd04cScth  * and a block reference, it is ok to ask for "Size" instead of "Nblocks".
5217c478bd9Sstevel@tonic-gate  */
5227c478bd9Sstevel@tonic-gate size_t
cpr_get_devsize(dev_t dev)5237c478bd9Sstevel@tonic-gate cpr_get_devsize(dev_t dev)
5247c478bd9Sstevel@tonic-gate {
5257c478bd9Sstevel@tonic-gate 	size_t bytes = 0;
5267c478bd9Sstevel@tonic-gate 
527184cd04cScth 	bytes = cdev_Size(dev);
528184cd04cScth 	if (bytes == 0)
529184cd04cScth 		bytes = cdev_size(dev);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	if (bytes > CPR_SPEC_OFFSET)
5327c478bd9Sstevel@tonic-gate 		bytes -= CPR_SPEC_OFFSET;
5337c478bd9Sstevel@tonic-gate 	else
5347c478bd9Sstevel@tonic-gate 		bytes = 0;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	return (bytes);
5377c478bd9Sstevel@tonic-gate }
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate /*
5417c478bd9Sstevel@tonic-gate  * increase statefile size
5427c478bd9Sstevel@tonic-gate  */
5437c478bd9Sstevel@tonic-gate static int
cpr_grow_statefile(vnode_t * vp,u_longlong_t newsize)5447c478bd9Sstevel@tonic-gate cpr_grow_statefile(vnode_t *vp, u_longlong_t newsize)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate 	extern uchar_t cpr_pagecopy[];
5477c478bd9Sstevel@tonic-gate 	struct inode *ip = VTOI(vp);
5487c478bd9Sstevel@tonic-gate 	u_longlong_t offset;
5497c478bd9Sstevel@tonic-gate 	int error, increase;
5507c478bd9Sstevel@tonic-gate 	ssize_t resid;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	rw_enter(&ip->i_contents, RW_READER);
5537c478bd9Sstevel@tonic-gate 	increase = (ip->i_size < newsize);
5547c478bd9Sstevel@tonic-gate 	offset = ip->i_size;
5557c478bd9Sstevel@tonic-gate 	rw_exit(&ip->i_contents);
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	if (increase == 0)
5587c478bd9Sstevel@tonic-gate 		return (0);
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	/*
5617c478bd9Sstevel@tonic-gate 	 * write to each logical block to reserve disk space
5627c478bd9Sstevel@tonic-gate 	 */
5637c478bd9Sstevel@tonic-gate 	error = 0;
5647c478bd9Sstevel@tonic-gate 	cpr_pagecopy[0] = '1';
5657c478bd9Sstevel@tonic-gate 	for (; offset < newsize; offset += ip->i_fs->fs_bsize) {
5667c478bd9Sstevel@tonic-gate 		if (error = vn_rdwr(UIO_WRITE, vp, (caddr_t)cpr_pagecopy,
5677c478bd9Sstevel@tonic-gate 		    ip->i_fs->fs_bsize, (offset_t)offset, UIO_SYSSPACE, 0,
5687c478bd9Sstevel@tonic-gate 		    (rlim64_t)MAXOFF_T, CRED(), &resid)) {
5697c478bd9Sstevel@tonic-gate 			if (error == ENOSPC) {
5707c478bd9Sstevel@tonic-gate 				cpr_err(CE_WARN, "error %d while reserving "
5717c478bd9Sstevel@tonic-gate 				    "disk space for statefile %s\n"
5727c478bd9Sstevel@tonic-gate 				    "wanted %lld bytes, file is %lld short",
5737c478bd9Sstevel@tonic-gate 				    error, cpr_cprconfig_to_path(),
5747c478bd9Sstevel@tonic-gate 				    newsize, newsize - offset);
5757c478bd9Sstevel@tonic-gate 			}
5767c478bd9Sstevel@tonic-gate 			break;
5777c478bd9Sstevel@tonic-gate 		}
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate 	return (error);
5807c478bd9Sstevel@tonic-gate }
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate /*
5847c478bd9Sstevel@tonic-gate  * do a simple estimate of the space needed to hold the statefile
5857c478bd9Sstevel@tonic-gate  * taking compression into account, but be fairly conservative
5867c478bd9Sstevel@tonic-gate  * so we have a better chance of completing; when dump fails,
5877c478bd9Sstevel@tonic-gate  * the retry cost is fairly high.
5887c478bd9Sstevel@tonic-gate  *
5897c478bd9Sstevel@tonic-gate  * Do disk blocks allocation for the state file if no space has
5907c478bd9Sstevel@tonic-gate  * been allocated yet. Since the state file will not be removed,
5917c478bd9Sstevel@tonic-gate  * allocation should only be done once.
5927c478bd9Sstevel@tonic-gate  */
5937c478bd9Sstevel@tonic-gate static int
cpr_statefile_ok(vnode_t * vp,int alloc_retry)5947c478bd9Sstevel@tonic-gate cpr_statefile_ok(vnode_t *vp, int alloc_retry)
5957c478bd9Sstevel@tonic-gate {
5967c478bd9Sstevel@tonic-gate 	extern size_t cpr_bitmap_size;
5977c478bd9Sstevel@tonic-gate 	struct inode *ip = VTOI(vp);
5987c478bd9Sstevel@tonic-gate 	const int UCOMP_RATE = 20; /* comp. ratio*10 for user pages */
5997c478bd9Sstevel@tonic-gate 	u_longlong_t size, isize, ksize, raw_data;
6007c478bd9Sstevel@tonic-gate 	char *str, *est_fmt;
6017c478bd9Sstevel@tonic-gate 	size_t space;
6027c478bd9Sstevel@tonic-gate 	int error;
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	/*
6057c478bd9Sstevel@tonic-gate 	 * number of pages short for swapping.
6067c478bd9Sstevel@tonic-gate 	 */
6077c478bd9Sstevel@tonic-gate 	STAT->cs_nosw_pages = k_anoninfo.ani_mem_resv;
6087c478bd9Sstevel@tonic-gate 	if (STAT->cs_nosw_pages < 0)
6097c478bd9Sstevel@tonic-gate 		STAT->cs_nosw_pages = 0;
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	str = "cpr_statefile_ok:";
6127c478bd9Sstevel@tonic-gate 
613ae115bc7Smrj 	CPR_DEBUG(CPR_DEBUG9, "Phys swap: max=%lu resv=%lu\n",
614ae115bc7Smrj 	    k_anoninfo.ani_max, k_anoninfo.ani_phys_resv);
615ae115bc7Smrj 	CPR_DEBUG(CPR_DEBUG9, "Mem swap: max=%ld resv=%lu\n",
6167c478bd9Sstevel@tonic-gate 	    MAX(availrmem - swapfs_minfree, 0),
617ae115bc7Smrj 	    k_anoninfo.ani_mem_resv);
618ae115bc7Smrj 	CPR_DEBUG(CPR_DEBUG9, "Total available swap: %ld\n",
619ae115bc7Smrj 	    CURRENT_TOTAL_AVAILABLE_SWAP);
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	/*
6227c478bd9Sstevel@tonic-gate 	 * try increasing filesize by 15%
6237c478bd9Sstevel@tonic-gate 	 */
6247c478bd9Sstevel@tonic-gate 	if (alloc_retry) {
6257c478bd9Sstevel@tonic-gate 		/*
6267c478bd9Sstevel@tonic-gate 		 * block device doesn't get any bigger
6277c478bd9Sstevel@tonic-gate 		 */
6287c478bd9Sstevel@tonic-gate 		if (vp->v_type == VBLK) {
629ae115bc7Smrj 			if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG6))
630ae115bc7Smrj 				prom_printf(
631ae115bc7Smrj 				    "Retry statefile on special file\n");
6327c478bd9Sstevel@tonic-gate 			return (ENOMEM);
6337c478bd9Sstevel@tonic-gate 		} else {
6347c478bd9Sstevel@tonic-gate 			rw_enter(&ip->i_contents, RW_READER);
6357c478bd9Sstevel@tonic-gate 			size = (ip->i_size * SIZE_RATE) / INTEGRAL;
6367c478bd9Sstevel@tonic-gate 			rw_exit(&ip->i_contents);
6377c478bd9Sstevel@tonic-gate 		}
638ae115bc7Smrj 		if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG6))
639ae115bc7Smrj 			prom_printf("Retry statefile size = %lld\n", size);
6407c478bd9Sstevel@tonic-gate 	} else {
6417c478bd9Sstevel@tonic-gate 		u_longlong_t cpd_size;
6427c478bd9Sstevel@tonic-gate 		pgcnt_t npages, nback;
6437c478bd9Sstevel@tonic-gate 		int ndvram;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 		ndvram = 0;
646bf30efa4Smathue 		(void) callb_execute_class(CB_CL_CPR_FB,
647bf30efa4Smathue 		    (int)(uintptr_t)&ndvram);
648ae115bc7Smrj 		if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG6))
649ae115bc7Smrj 			prom_printf("ndvram size = %d\n", ndvram);
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 		/*
6527c478bd9Sstevel@tonic-gate 		 * estimate 1 cpd_t for every (CPR_MAXCONTIG / 2) pages
6537c478bd9Sstevel@tonic-gate 		 */
6547c478bd9Sstevel@tonic-gate 		npages = cpr_count_kpages(REGULAR_BITMAP, cpr_nobit);
6557c478bd9Sstevel@tonic-gate 		cpd_size = sizeof (cpd_t) * (npages / (CPR_MAXCONTIG / 2));
6567c478bd9Sstevel@tonic-gate 		raw_data = cpd_size + cpr_bitmap_size;
6577c478bd9Sstevel@tonic-gate 		ksize = ndvram + mmu_ptob(npages);
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 		est_fmt = "%s estimated size with "
6607c478bd9Sstevel@tonic-gate 		    "%scompression %lld, ksize %lld\n";
6617c478bd9Sstevel@tonic-gate 		nback = mmu_ptob(STAT->cs_nosw_pages);
6627c478bd9Sstevel@tonic-gate 		if (CPR->c_flags & C_COMPRESSING) {
6637c478bd9Sstevel@tonic-gate 			size = ((ksize * COMPRESS_PERCENT) / INTEGRAL) +
6647c478bd9Sstevel@tonic-gate 			    raw_data + ((nback * 10) / UCOMP_RATE);
665ae115bc7Smrj 			CPR_DEBUG(CPR_DEBUG1, est_fmt, str, "", size, ksize);
6667c478bd9Sstevel@tonic-gate 		} else {
6677c478bd9Sstevel@tonic-gate 			size = ksize + raw_data + nback;
668ae115bc7Smrj 			CPR_DEBUG(CPR_DEBUG1, est_fmt, str, "no ",
669ae115bc7Smrj 			    size, ksize);
6707c478bd9Sstevel@tonic-gate 		}
6717c478bd9Sstevel@tonic-gate 	}
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	/*
6747c478bd9Sstevel@tonic-gate 	 * All this is much simpler for a block device
6757c478bd9Sstevel@tonic-gate 	 */
6767c478bd9Sstevel@tonic-gate 	if (vp->v_type == VBLK) {
6777c478bd9Sstevel@tonic-gate 		space = cpr_get_devsize(vp->v_rdev);
678ae115bc7Smrj 		if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG6))
679ae115bc7Smrj 			prom_printf("statefile dev size %lu\n", space);
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 		/*
6827c478bd9Sstevel@tonic-gate 		 * Export the estimated filesize info, this value will be
6837c478bd9Sstevel@tonic-gate 		 * compared before dumping out the statefile in the case of
6847c478bd9Sstevel@tonic-gate 		 * no compression.
6857c478bd9Sstevel@tonic-gate 		 */
6867c478bd9Sstevel@tonic-gate 		STAT->cs_est_statefsz = size;
687ae115bc7Smrj 		if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG6))
688ae115bc7Smrj 			prom_printf("%s Estimated statefile size %llu, "
689ae115bc7Smrj 			    "space %lu\n", str, size, space);
6907c478bd9Sstevel@tonic-gate 		if (size > space) {
6917c478bd9Sstevel@tonic-gate 			cpr_err(CE_CONT, "Statefile partition too small.");
6927c478bd9Sstevel@tonic-gate 			return (ENOMEM);
6937c478bd9Sstevel@tonic-gate 		}
6947c478bd9Sstevel@tonic-gate 		return (0);
6957c478bd9Sstevel@tonic-gate 	} else {
6967c478bd9Sstevel@tonic-gate 		if (CPR->c_alloc_cnt++ > C_MAX_ALLOC_RETRY) {
6977c478bd9Sstevel@tonic-gate 			cpr_err(CE_CONT, "Statefile allocation retry failed\n");
6987c478bd9Sstevel@tonic-gate 			return (ENOMEM);
6997c478bd9Sstevel@tonic-gate 		}
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 		/*
7027c478bd9Sstevel@tonic-gate 		 * Estimate space needed for the state file.
7037c478bd9Sstevel@tonic-gate 		 *
7047c478bd9Sstevel@tonic-gate 		 * State file size in bytes:
7057c478bd9Sstevel@tonic-gate 		 * 	kernel size + non-cache pte seg +
7067c478bd9Sstevel@tonic-gate 		 *	bitmap size + cpr state file headers size
7077c478bd9Sstevel@tonic-gate 		 * (round up to fs->fs_bsize)
7087c478bd9Sstevel@tonic-gate 		 */
7097c478bd9Sstevel@tonic-gate 		size = blkroundup(ip->i_fs, size);
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 		/*
7127c478bd9Sstevel@tonic-gate 		 * Export the estimated filesize info, this value will be
7137c478bd9Sstevel@tonic-gate 		 * compared before dumping out the statefile in the case of
7147c478bd9Sstevel@tonic-gate 		 * no compression.
7157c478bd9Sstevel@tonic-gate 		 */
7167c478bd9Sstevel@tonic-gate 		STAT->cs_est_statefsz = size;
7177c478bd9Sstevel@tonic-gate 		error = cpr_grow_statefile(vp, size);
718ae115bc7Smrj 		if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG6)) {
7197c478bd9Sstevel@tonic-gate 			rw_enter(&ip->i_contents, RW_READER);
7207c478bd9Sstevel@tonic-gate 			isize = ip->i_size;
7217c478bd9Sstevel@tonic-gate 			rw_exit(&ip->i_contents);
722ae115bc7Smrj 			prom_printf("%s Estimated statefile size %lld, "
723ae115bc7Smrj 			    "i_size %lld\n", str, size, isize);
7247c478bd9Sstevel@tonic-gate 		}
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 		return (error);
7277c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate }
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate void
cpr_statef_close(void)7327c478bd9Sstevel@tonic-gate cpr_statef_close(void)
7337c478bd9Sstevel@tonic-gate {
7347c478bd9Sstevel@tonic-gate 	if (C_VP) {
7357c478bd9Sstevel@tonic-gate 		if (!cpr_reusable_mode)
736da6c28aaSamw 			(void) VOP_DUMPCTL(C_VP, DUMP_FREE, NULL, NULL);
737da6c28aaSamw 		(void) VOP_CLOSE(C_VP, FWRITE, 1, (offset_t)0, CRED(), NULL);
7387c478bd9Sstevel@tonic-gate 		VN_RELE(C_VP);
7397c478bd9Sstevel@tonic-gate 		C_VP = 0;
7407c478bd9Sstevel@tonic-gate 	}
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate /*
7457c478bd9Sstevel@tonic-gate  * open cpr default file and display error
7467c478bd9Sstevel@tonic-gate  */
7477c478bd9Sstevel@tonic-gate int
cpr_open_deffile(int mode,vnode_t ** vpp)7487c478bd9Sstevel@tonic-gate cpr_open_deffile(int mode, vnode_t **vpp)
7497c478bd9Sstevel@tonic-gate {
7507c478bd9Sstevel@tonic-gate 	int error;
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	if (error = cpr_open(cpr_default_path, mode, vpp))
7537c478bd9Sstevel@tonic-gate 		cpr_err(CE_CONT, "cannot open \"%s\", error %d\n",
7547c478bd9Sstevel@tonic-gate 		    cpr_default_path, error);
7557c478bd9Sstevel@tonic-gate 	return (error);
7567c478bd9Sstevel@tonic-gate }
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate /*
7607c478bd9Sstevel@tonic-gate  * write cdef_t to disk.  This contains the original values of prom
7617c478bd9Sstevel@tonic-gate  * properties that we modify.  We fill in the magic number of the file
7627c478bd9Sstevel@tonic-gate  * here as a signal to the booter code that the state file is valid.
7637c478bd9Sstevel@tonic-gate  * Be sure the file gets synced, since we may be shutting down the OS.
7647c478bd9Sstevel@tonic-gate  */
7657c478bd9Sstevel@tonic-gate int
cpr_write_deffile(cdef_t * cdef)7667c478bd9Sstevel@tonic-gate cpr_write_deffile(cdef_t *cdef)
7677c478bd9Sstevel@tonic-gate {
7687c478bd9Sstevel@tonic-gate 	struct vnode *vp;
7697c478bd9Sstevel@tonic-gate 	char *str;
7707c478bd9Sstevel@tonic-gate 	int rc;
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	if (rc = cpr_open_deffile(FCREAT|FWRITE, &vp))
7737c478bd9Sstevel@tonic-gate 		return (rc);
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	if (rc = cpr_rdwr(UIO_WRITE, vp, cdef, sizeof (*cdef)))
7767c478bd9Sstevel@tonic-gate 		str = "write";
777da6c28aaSamw 	else if (rc = VOP_FSYNC(vp, FSYNC, CRED(), NULL))
7787c478bd9Sstevel@tonic-gate 		str = "fsync";
779da6c28aaSamw 	(void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
7807c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	if (rc) {
7837c478bd9Sstevel@tonic-gate 		cpr_err(CE_WARN, "%s error %d, file \"%s\"",
7847c478bd9Sstevel@tonic-gate 		    str, rc, cpr_default_path);
7857c478bd9Sstevel@tonic-gate 	}
7867c478bd9Sstevel@tonic-gate 	return (rc);
7877c478bd9Sstevel@tonic-gate }
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate /*
7907c478bd9Sstevel@tonic-gate  * Clear the magic number in the defaults file.  This tells the booter
7917c478bd9Sstevel@tonic-gate  * program that the state file is not current and thus prevents
7927c478bd9Sstevel@tonic-gate  * any attempt to restore from an obsolete state file.
7937c478bd9Sstevel@tonic-gate  */
7947c478bd9Sstevel@tonic-gate void
cpr_clear_definfo(void)7957c478bd9Sstevel@tonic-gate cpr_clear_definfo(void)
7967c478bd9Sstevel@tonic-gate {
7977c478bd9Sstevel@tonic-gate 	struct vnode *vp;
7987c478bd9Sstevel@tonic-gate 	cmini_t mini;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	if ((CPR->c_cprboot_magic != CPR_DEFAULT_MAGIC) ||
8017c478bd9Sstevel@tonic-gate 	    cpr_open_deffile(FCREAT|FWRITE, &vp))
8027c478bd9Sstevel@tonic-gate 		return;
8037c478bd9Sstevel@tonic-gate 	mini.magic = mini.reusable = 0;
8047c478bd9Sstevel@tonic-gate 	(void) cpr_rdwr(UIO_WRITE, vp, &mini, sizeof (mini));
805da6c28aaSamw 	(void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
8067c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate /*
8107c478bd9Sstevel@tonic-gate  * If the cpr default file is invalid, then we must not be in reusable mode
8117c478bd9Sstevel@tonic-gate  * if it is valid, it tells us our mode
8127c478bd9Sstevel@tonic-gate  */
8137c478bd9Sstevel@tonic-gate int
cpr_get_reusable_mode(void)8147c478bd9Sstevel@tonic-gate cpr_get_reusable_mode(void)
8157c478bd9Sstevel@tonic-gate {
8167c478bd9Sstevel@tonic-gate 	struct vnode *vp;
8177c478bd9Sstevel@tonic-gate 	cmini_t mini;
8187c478bd9Sstevel@tonic-gate 	int rc;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	if (cpr_open(cpr_default_path, FREAD, &vp))
8217c478bd9Sstevel@tonic-gate 		return (0);
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	rc = cpr_rdwr(UIO_READ, vp, &mini, sizeof (mini));
824da6c28aaSamw 	(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
8257c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
8267c478bd9Sstevel@tonic-gate 	if (rc == 0 && mini.magic == CPR_DEFAULT_MAGIC)
8277c478bd9Sstevel@tonic-gate 		return (mini.reusable);
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	return (0);
8307c478bd9Sstevel@tonic-gate }
8312df1fe9cSrandyf #endif
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate /*
8347c478bd9Sstevel@tonic-gate  * clock/time related routines
8357c478bd9Sstevel@tonic-gate  */
8367c478bd9Sstevel@tonic-gate static time_t   cpr_time_stamp;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate void
cpr_tod_get(cpr_time_t * ctp)8407c478bd9Sstevel@tonic-gate cpr_tod_get(cpr_time_t *ctp)
8417c478bd9Sstevel@tonic-gate {
8427c478bd9Sstevel@tonic-gate 	timestruc_t ts;
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	mutex_enter(&tod_lock);
8452df1fe9cSrandyf 	ts = TODOP_GET(tod_ops);
8467c478bd9Sstevel@tonic-gate 	mutex_exit(&tod_lock);
8477c478bd9Sstevel@tonic-gate 	ctp->tv_sec = (time32_t)ts.tv_sec;
8487c478bd9Sstevel@tonic-gate 	ctp->tv_nsec = (int32_t)ts.tv_nsec;
8497c478bd9Sstevel@tonic-gate }
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate void
cpr_tod_status_set(int tod_flag)852*8fc99e42STrevor Thompson cpr_tod_status_set(int tod_flag)
8537c478bd9Sstevel@tonic-gate {
8547c478bd9Sstevel@tonic-gate 	mutex_enter(&tod_lock);
855*8fc99e42STrevor Thompson 	tod_status_set(tod_flag);
8567c478bd9Sstevel@tonic-gate 	mutex_exit(&tod_lock);
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate void
cpr_save_time(void)8607c478bd9Sstevel@tonic-gate cpr_save_time(void)
8617c478bd9Sstevel@tonic-gate {
8627c478bd9Sstevel@tonic-gate 	cpr_time_stamp = gethrestime_sec();
8637c478bd9Sstevel@tonic-gate }
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate /*
8667c478bd9Sstevel@tonic-gate  * correct time based on saved time stamp or hardware clock
8677c478bd9Sstevel@tonic-gate  */
8687c478bd9Sstevel@tonic-gate void
cpr_restore_time(void)8697c478bd9Sstevel@tonic-gate cpr_restore_time(void)
8707c478bd9Sstevel@tonic-gate {
8717c478bd9Sstevel@tonic-gate 	clkset(cpr_time_stamp);
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate 
8742df1fe9cSrandyf #if defined(__sparc)
8757c478bd9Sstevel@tonic-gate /*
8767c478bd9Sstevel@tonic-gate  * CPU ONLINE/OFFLINE CODE
8777c478bd9Sstevel@tonic-gate  */
8787c478bd9Sstevel@tonic-gate int
cpr_mp_offline(void)8797c478bd9Sstevel@tonic-gate cpr_mp_offline(void)
8807c478bd9Sstevel@tonic-gate {
8817c478bd9Sstevel@tonic-gate 	cpu_t *cp, *bootcpu;
8827c478bd9Sstevel@tonic-gate 	int rc = 0;
8837c478bd9Sstevel@tonic-gate 	int brought_up_boot = 0;
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	/*
8867c478bd9Sstevel@tonic-gate 	 * Do nothing for UP.
8877c478bd9Sstevel@tonic-gate 	 */
8887c478bd9Sstevel@tonic-gate 	if (ncpus == 1)
8897c478bd9Sstevel@tonic-gate 		return (0);
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	cpr_save_mp_state();
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	bootcpu = i_cpr_bootcpu();
8967c478bd9Sstevel@tonic-gate 	if (!CPU_ACTIVE(bootcpu)) {
8977c478bd9Sstevel@tonic-gate 		if ((rc = cpr_p_online(bootcpu, CPU_CPR_ONLINE))) {
8987c478bd9Sstevel@tonic-gate 			mutex_exit(&cpu_lock);
8997c478bd9Sstevel@tonic-gate 			return (rc);
9007c478bd9Sstevel@tonic-gate 		}
9017c478bd9Sstevel@tonic-gate 		brought_up_boot = 1;
9027c478bd9Sstevel@tonic-gate 	}
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	cp = cpu_list;
9057c478bd9Sstevel@tonic-gate 	do {
9067c478bd9Sstevel@tonic-gate 		if (cp == bootcpu)
9077c478bd9Sstevel@tonic-gate 			continue;
9087c478bd9Sstevel@tonic-gate 		if (cp->cpu_flags & CPU_OFFLINE)
9097c478bd9Sstevel@tonic-gate 			continue;
9107c478bd9Sstevel@tonic-gate 		if ((rc = cpr_p_online(cp, CPU_CPR_OFFLINE))) {
9117c478bd9Sstevel@tonic-gate 			mutex_exit(&cpu_lock);
9127c478bd9Sstevel@tonic-gate 			return (rc);
9137c478bd9Sstevel@tonic-gate 		}
9147c478bd9Sstevel@tonic-gate 	} while ((cp = cp->cpu_next) != cpu_list);
915ae115bc7Smrj 	if (brought_up_boot && (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG6)))
916ae115bc7Smrj 		prom_printf("changed cpu %p to state %d\n",
917903a11ebSrh87107 		    (void *)bootcpu, CPU_CPR_ONLINE);
9187c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	return (rc);
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate int
cpr_mp_online(void)9247c478bd9Sstevel@tonic-gate cpr_mp_online(void)
9257c478bd9Sstevel@tonic-gate {
9267c478bd9Sstevel@tonic-gate 	cpu_t *cp, *bootcpu = CPU;
9277c478bd9Sstevel@tonic-gate 	int rc = 0;
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	/*
9307c478bd9Sstevel@tonic-gate 	 * Do nothing for UP.
9317c478bd9Sstevel@tonic-gate 	 */
9327c478bd9Sstevel@tonic-gate 	if (ncpus == 1)
9337c478bd9Sstevel@tonic-gate 		return (0);
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	/*
9367c478bd9Sstevel@tonic-gate 	 * cpr_save_mp_state() sets CPU_CPR_ONLINE in cpu_cpr_flags
9377c478bd9Sstevel@tonic-gate 	 * to indicate a cpu was online at the time of cpr_suspend();
9387c478bd9Sstevel@tonic-gate 	 * now restart those cpus that were marked as CPU_CPR_ONLINE
9397c478bd9Sstevel@tonic-gate 	 * and actually are offline.
9407c478bd9Sstevel@tonic-gate 	 */
9417c478bd9Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
9427c478bd9Sstevel@tonic-gate 	for (cp = bootcpu->cpu_next; cp != bootcpu; cp = cp->cpu_next) {
9437c478bd9Sstevel@tonic-gate 		/*
9447c478bd9Sstevel@tonic-gate 		 * Clear the CPU_FROZEN flag in all cases.
9457c478bd9Sstevel@tonic-gate 		 */
9467c478bd9Sstevel@tonic-gate 		cp->cpu_flags &= ~CPU_FROZEN;
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 		if (CPU_CPR_IS_OFFLINE(cp))
9497c478bd9Sstevel@tonic-gate 			continue;
9507c478bd9Sstevel@tonic-gate 		if (CPU_ACTIVE(cp))
9517c478bd9Sstevel@tonic-gate 			continue;
9527c478bd9Sstevel@tonic-gate 		if ((rc = cpr_p_online(cp, CPU_CPR_ONLINE))) {
9537c478bd9Sstevel@tonic-gate 			mutex_exit(&cpu_lock);
9547c478bd9Sstevel@tonic-gate 			return (rc);
9557c478bd9Sstevel@tonic-gate 		}
9567c478bd9Sstevel@tonic-gate 	}
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	/*
9597c478bd9Sstevel@tonic-gate 	 * turn off the boot cpu if it was offlined
9607c478bd9Sstevel@tonic-gate 	 */
9617c478bd9Sstevel@tonic-gate 	if (CPU_CPR_IS_OFFLINE(bootcpu)) {
9627c478bd9Sstevel@tonic-gate 		if ((rc = cpr_p_online(bootcpu, CPU_CPR_OFFLINE))) {
9637c478bd9Sstevel@tonic-gate 			mutex_exit(&cpu_lock);
9647c478bd9Sstevel@tonic-gate 			return (rc);
9657c478bd9Sstevel@tonic-gate 		}
9667c478bd9Sstevel@tonic-gate 	}
9677c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
9687c478bd9Sstevel@tonic-gate 	return (0);
9697c478bd9Sstevel@tonic-gate }
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate static void
cpr_save_mp_state(void)9727c478bd9Sstevel@tonic-gate cpr_save_mp_state(void)
9737c478bd9Sstevel@tonic-gate {
9747c478bd9Sstevel@tonic-gate 	cpu_t *cp;
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	cp = cpu_list;
9797c478bd9Sstevel@tonic-gate 	do {
9807c478bd9Sstevel@tonic-gate 		cp->cpu_cpr_flags &= ~CPU_CPR_ONLINE;
9817c478bd9Sstevel@tonic-gate 		if (CPU_ACTIVE(cp))
9827c478bd9Sstevel@tonic-gate 			CPU_SET_CPR_FLAGS(cp, CPU_CPR_ONLINE);
9837c478bd9Sstevel@tonic-gate 	} while ((cp = cp->cpu_next) != cpu_list);
9847c478bd9Sstevel@tonic-gate }
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate /*
9877c478bd9Sstevel@tonic-gate  * change cpu to online/offline
9887c478bd9Sstevel@tonic-gate  */
9897c478bd9Sstevel@tonic-gate static int
cpr_p_online(cpu_t * cp,int state)9907c478bd9Sstevel@tonic-gate cpr_p_online(cpu_t *cp, int state)
9917c478bd9Sstevel@tonic-gate {
9927c478bd9Sstevel@tonic-gate 	int rc;
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	switch (state) {
9977c478bd9Sstevel@tonic-gate 	case CPU_CPR_ONLINE:
9987c478bd9Sstevel@tonic-gate 		rc = cpu_online(cp);
9997c478bd9Sstevel@tonic-gate 		break;
10007c478bd9Sstevel@tonic-gate 	case CPU_CPR_OFFLINE:
10017c478bd9Sstevel@tonic-gate 		rc = cpu_offline(cp, CPU_FORCED);
10027c478bd9Sstevel@tonic-gate 		break;
10037c478bd9Sstevel@tonic-gate 	}
10047c478bd9Sstevel@tonic-gate 	if (rc) {
10057c478bd9Sstevel@tonic-gate 		cpr_err(CE_WARN, "Failed to change processor %d to "
10067c478bd9Sstevel@tonic-gate 		    "state %d, (errno %d)", cp->cpu_id, state, rc);
10077c478bd9Sstevel@tonic-gate 	}
10087c478bd9Sstevel@tonic-gate 	return (rc);
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate /*
10127c478bd9Sstevel@tonic-gate  * Construct the pathname of the state file and return a pointer to
10137c478bd9Sstevel@tonic-gate  * caller.  Read the config file to get the mount point of the
10147c478bd9Sstevel@tonic-gate  * filesystem and the pathname within fs.
10157c478bd9Sstevel@tonic-gate  */
10167c478bd9Sstevel@tonic-gate char *
cpr_build_statefile_path(void)10177c478bd9Sstevel@tonic-gate cpr_build_statefile_path(void)
10187c478bd9Sstevel@tonic-gate {
10197c478bd9Sstevel@tonic-gate 	struct cprconfig *cf = &cprconfig;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	if (cpr_get_config())
10227c478bd9Sstevel@tonic-gate 		return (NULL);
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	switch (cf->cf_type) {
10257c478bd9Sstevel@tonic-gate 	case CFT_UFS:
10267c478bd9Sstevel@tonic-gate 		if (strlen(cf->cf_path) + strlen(cf->cf_fs) >= MAXNAMELEN - 1) {
10277c478bd9Sstevel@tonic-gate 			cpr_err(CE_CONT, "Statefile path is too long.\n");
10287c478bd9Sstevel@tonic-gate 			return (NULL);
10297c478bd9Sstevel@tonic-gate 		}
10307c478bd9Sstevel@tonic-gate 		return (cpr_cprconfig_to_path());
1031e7cbe64fSgw25295 	case CFT_ZVOL:
1032e7cbe64fSgw25295 		/*FALLTHROUGH*/
10337c478bd9Sstevel@tonic-gate 	case CFT_SPEC:
10347c478bd9Sstevel@tonic-gate 		return (cf->cf_devfs);
10357c478bd9Sstevel@tonic-gate 	default:
10367c478bd9Sstevel@tonic-gate 		cpr_err(CE_PANIC, "invalid statefile type");
10377c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1038bf30efa4Smathue 		return (NULL);
10397c478bd9Sstevel@tonic-gate 	}
10407c478bd9Sstevel@tonic-gate }
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate int
cpr_statefile_is_spec(void)10437c478bd9Sstevel@tonic-gate cpr_statefile_is_spec(void)
10447c478bd9Sstevel@tonic-gate {
10457c478bd9Sstevel@tonic-gate 	if (cpr_get_config())
10467c478bd9Sstevel@tonic-gate 		return (0);
10477c478bd9Sstevel@tonic-gate 	return (cprconfig.cf_type == CFT_SPEC);
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate char *
cpr_get_statefile_prom_path(void)10517c478bd9Sstevel@tonic-gate cpr_get_statefile_prom_path(void)
10527c478bd9Sstevel@tonic-gate {
10537c478bd9Sstevel@tonic-gate 	struct cprconfig *cf = &cprconfig;
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 	ASSERT(cprconfig_loaded);
10567c478bd9Sstevel@tonic-gate 	ASSERT(cf->cf_magic == CPR_CONFIG_MAGIC);
1057e7cbe64fSgw25295 	ASSERT(cf->cf_type == CFT_SPEC || cf->cf_type == CFT_ZVOL);
10587c478bd9Sstevel@tonic-gate 	return (cf->cf_dev_prom);
10597c478bd9Sstevel@tonic-gate }
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate /*
10637c478bd9Sstevel@tonic-gate  * XXX The following routines need to be in the vfs source code.
10647c478bd9Sstevel@tonic-gate  */
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate int
cpr_is_ufs(struct vfs * vfsp)10677c478bd9Sstevel@tonic-gate cpr_is_ufs(struct vfs *vfsp)
10687c478bd9Sstevel@tonic-gate {
10697c478bd9Sstevel@tonic-gate 	char *fsname;
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	fsname = vfssw[vfsp->vfs_fstype].vsw_name;
10727c478bd9Sstevel@tonic-gate 	return (strcmp(fsname, "ufs") == 0);
10737c478bd9Sstevel@tonic-gate }
10747c478bd9Sstevel@tonic-gate 
1075e7cbe64fSgw25295 int
cpr_is_zfs(struct vfs * vfsp)1076e7cbe64fSgw25295 cpr_is_zfs(struct vfs *vfsp)
1077e7cbe64fSgw25295 {
1078e7cbe64fSgw25295 	char *fsname;
1079e7cbe64fSgw25295 
1080e7cbe64fSgw25295 	fsname = vfssw[vfsp->vfs_fstype].vsw_name;
1081e7cbe64fSgw25295 	return (strcmp(fsname, "zfs") == 0);
1082e7cbe64fSgw25295 }
1083e7cbe64fSgw25295 
10847c478bd9Sstevel@tonic-gate /*
10857c478bd9Sstevel@tonic-gate  * This is a list of file systems that are allowed to be writeable when a
10867c478bd9Sstevel@tonic-gate  * reusable statefile checkpoint is taken.  They must not have any state that
10877c478bd9Sstevel@tonic-gate  * cannot be restored to consistency by simply rebooting using the checkpoint.
10887c478bd9Sstevel@tonic-gate  * (In contrast to ufs, cachefs and pcfs which have disk state that could get
10897c478bd9Sstevel@tonic-gate  * out of sync with the in-kernel data).
10907c478bd9Sstevel@tonic-gate  */
10917c478bd9Sstevel@tonic-gate int
cpr_reusable_mount_check(void)10927c478bd9Sstevel@tonic-gate cpr_reusable_mount_check(void)
10937c478bd9Sstevel@tonic-gate {
10947c478bd9Sstevel@tonic-gate 	struct vfs *vfsp;
10957c478bd9Sstevel@tonic-gate 	char *fsname;
10967c478bd9Sstevel@tonic-gate 	char **cpp;
10977c478bd9Sstevel@tonic-gate 	static char *cpr_writeok_fss[] = {
10987c478bd9Sstevel@tonic-gate 		"autofs", "devfs", "fd", "lofs", "mntfs", "namefs", "nfs",
1099facf4a8dSllai1 		"proc", "tmpfs", "ctfs", "objfs", "dev", NULL
11007c478bd9Sstevel@tonic-gate 	};
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 	vfs_list_read_lock();
11037c478bd9Sstevel@tonic-gate 	vfsp = rootvfs;
11047c478bd9Sstevel@tonic-gate 	do {
11057c478bd9Sstevel@tonic-gate 		if (vfsp->vfs_flag & VFS_RDONLY) {
11067c478bd9Sstevel@tonic-gate 			vfsp = vfsp->vfs_next;
11077c478bd9Sstevel@tonic-gate 			continue;
11087c478bd9Sstevel@tonic-gate 		}
11097c478bd9Sstevel@tonic-gate 		fsname = vfssw[vfsp->vfs_fstype].vsw_name;
11107c478bd9Sstevel@tonic-gate 		for (cpp = cpr_writeok_fss; *cpp; cpp++) {
11117c478bd9Sstevel@tonic-gate 			if (strcmp(fsname, *cpp) == 0)
11127c478bd9Sstevel@tonic-gate 				break;
11137c478bd9Sstevel@tonic-gate 		}
11147c478bd9Sstevel@tonic-gate 		/*
11157c478bd9Sstevel@tonic-gate 		 * if the inner loop reached the NULL terminator,
11167c478bd9Sstevel@tonic-gate 		 * the current fs-type does not match any OK-type
11177c478bd9Sstevel@tonic-gate 		 */
11187c478bd9Sstevel@tonic-gate 		if (*cpp == NULL) {
11197c478bd9Sstevel@tonic-gate 			cpr_err(CE_CONT, "a filesystem of type %s is "
11207c478bd9Sstevel@tonic-gate 			    "mounted read/write.\nReusable statefile requires "
11217c478bd9Sstevel@tonic-gate 			    "no writeable filesystem of this type be mounted\n",
11227c478bd9Sstevel@tonic-gate 			    fsname);
11237c478bd9Sstevel@tonic-gate 			vfs_list_unlock();
11247c478bd9Sstevel@tonic-gate 			return (EINVAL);
11257c478bd9Sstevel@tonic-gate 		}
11267c478bd9Sstevel@tonic-gate 		vfsp = vfsp->vfs_next;
11277c478bd9Sstevel@tonic-gate 	} while (vfsp != rootvfs);
11287c478bd9Sstevel@tonic-gate 	vfs_list_unlock();
11297c478bd9Sstevel@tonic-gate 	return (0);
11307c478bd9Sstevel@tonic-gate }
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate /*
11337c478bd9Sstevel@tonic-gate  * return statefile offset in DEV_BSIZE units
11347c478bd9Sstevel@tonic-gate  */
11357c478bd9Sstevel@tonic-gate int
cpr_statefile_offset(void)11367c478bd9Sstevel@tonic-gate cpr_statefile_offset(void)
11377c478bd9Sstevel@tonic-gate {
1138e7cbe64fSgw25295 	return (cprconfig.cf_type != CFT_UFS ? btod(CPR_SPEC_OFFSET) : 0);
11397c478bd9Sstevel@tonic-gate }
11402df1fe9cSrandyf 
11412df1fe9cSrandyf /*
11422df1fe9cSrandyf  * Force a fresh read of the cprinfo per uadmin 3 call
11432df1fe9cSrandyf  */
11442df1fe9cSrandyf void
cpr_forget_cprconfig(void)11452df1fe9cSrandyf cpr_forget_cprconfig(void)
11462df1fe9cSrandyf {
11472df1fe9cSrandyf 	cprconfig_loaded = 0;
11482df1fe9cSrandyf }
11492df1fe9cSrandyf #endif
1150