xref: /onnv-gate/usr/src/uts/common/cpr/cpr_misc.c (revision 11752:9c475fee0b48)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52621Sllai1  * Common Development and Distribution License (the "License").
62621Sllai1  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*11752STrevor.Thompson@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/errno.h>
280Sstevel@tonic-gate #include <sys/cpuvar.h>
290Sstevel@tonic-gate #include <sys/vfs.h>
300Sstevel@tonic-gate #include <sys/vnode.h>
310Sstevel@tonic-gate #include <sys/pathname.h>
320Sstevel@tonic-gate #include <sys/callb.h>
330Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
340Sstevel@tonic-gate #include <vm/anon.h>
350Sstevel@tonic-gate #include <sys/fs/swapnode.h>	/* for swapfs_minfree */
360Sstevel@tonic-gate #include <sys/kmem.h>
370Sstevel@tonic-gate #include <sys/cpr.h>
380Sstevel@tonic-gate #include <sys/conf.h>
395295Srandyf #include <sys/machclock.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate  * CPR miscellaneous support routines
430Sstevel@tonic-gate  */
440Sstevel@tonic-gate #define	cpr_open(path, mode,  vpp)	(vn_open(path, UIO_SYSSPACE, \
450Sstevel@tonic-gate 		mode, 0600, vpp, CRCREAT, 0))
460Sstevel@tonic-gate #define	cpr_rdwr(rw, vp, basep, cnt)	(vn_rdwr(rw, vp,  (caddr_t)(basep), \
470Sstevel@tonic-gate 		cnt, 0LL, UIO_SYSSPACE, 0, (rlim64_t)MAXOFF_T, CRED(), \
480Sstevel@tonic-gate 		(ssize_t *)NULL))
490Sstevel@tonic-gate 
500Sstevel@tonic-gate extern void clkset(time_t);
510Sstevel@tonic-gate extern cpu_t *i_cpr_bootcpu(void);
520Sstevel@tonic-gate extern caddr_t i_cpr_map_setup(void);
530Sstevel@tonic-gate extern void i_cpr_free_memory_resources(void);
540Sstevel@tonic-gate 
550Sstevel@tonic-gate extern kmutex_t cpr_slock;
560Sstevel@tonic-gate extern size_t cpr_buf_size;
570Sstevel@tonic-gate extern char *cpr_buf;
580Sstevel@tonic-gate extern size_t cpr_pagedata_size;
590Sstevel@tonic-gate extern char *cpr_pagedata;
600Sstevel@tonic-gate extern int cpr_bufs_allocated;
610Sstevel@tonic-gate extern int cpr_bitmaps_allocated;
620Sstevel@tonic-gate 
635295Srandyf #if defined(__sparc)
640Sstevel@tonic-gate static struct cprconfig cprconfig;
650Sstevel@tonic-gate static int cprconfig_loaded = 0;
660Sstevel@tonic-gate static int cpr_statefile_ok(vnode_t *, int);
670Sstevel@tonic-gate static int cpr_p_online(cpu_t *, int);
680Sstevel@tonic-gate static void cpr_save_mp_state(void);
695295Srandyf #endif
705295Srandyf 
710Sstevel@tonic-gate int cpr_is_ufs(struct vfs *);
726423Sgw25295 int cpr_is_zfs(struct vfs *);
730Sstevel@tonic-gate 
740Sstevel@tonic-gate char cpr_default_path[] = CPR_DEFAULT;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate #define	COMPRESS_PERCENT 40	/* approx compression ratio in percent */
770Sstevel@tonic-gate #define	SIZE_RATE	115	/* increase size by 15% */
780Sstevel@tonic-gate #define	INTEGRAL	100	/* for integer math */
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 
810Sstevel@tonic-gate /*
820Sstevel@tonic-gate  * cmn_err() followed by a 1/4 second delay; this gives the
830Sstevel@tonic-gate  * logging service a chance to flush messages and helps avoid
840Sstevel@tonic-gate  * intermixing output from prom_printf().
850Sstevel@tonic-gate  */
860Sstevel@tonic-gate /*PRINTFLIKE2*/
870Sstevel@tonic-gate void
cpr_err(int ce,const char * fmt,...)880Sstevel@tonic-gate cpr_err(int ce, const char *fmt, ...)
890Sstevel@tonic-gate {
900Sstevel@tonic-gate 	va_list adx;
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	va_start(adx, fmt);
930Sstevel@tonic-gate 	vcmn_err(ce, fmt, adx);
940Sstevel@tonic-gate 	va_end(adx);
950Sstevel@tonic-gate 	drv_usecwait(MICROSEC >> 2);
960Sstevel@tonic-gate }
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 
990Sstevel@tonic-gate int
cpr_init(int fcn)1000Sstevel@tonic-gate cpr_init(int fcn)
1010Sstevel@tonic-gate {
1020Sstevel@tonic-gate 	/*
1030Sstevel@tonic-gate 	 * Allow only one suspend/resume process.
1040Sstevel@tonic-gate 	 */
1050Sstevel@tonic-gate 	if (mutex_tryenter(&cpr_slock) == 0)
1060Sstevel@tonic-gate 		return (EBUSY);
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	CPR->c_flags = 0;
1090Sstevel@tonic-gate 	CPR->c_substate = 0;
1100Sstevel@tonic-gate 	CPR->c_cprboot_magic = 0;
1110Sstevel@tonic-gate 	CPR->c_alloc_cnt = 0;
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	CPR->c_fcn = fcn;
1140Sstevel@tonic-gate 	if (fcn == AD_CPR_REUSABLE)
1150Sstevel@tonic-gate 		CPR->c_flags |= C_REUSABLE;
1160Sstevel@tonic-gate 	else
1170Sstevel@tonic-gate 		CPR->c_flags |= C_SUSPENDING;
1185295Srandyf 	if (fcn == AD_SUSPEND_TO_RAM || fcn == DEV_SUSPEND_TO_RAM) {
1195295Srandyf 		return (0);
1205295Srandyf 	}
1215295Srandyf #if defined(__sparc)
1220Sstevel@tonic-gate 	if (fcn != AD_CPR_NOCOMPRESS && fcn != AD_CPR_TESTNOZ)
1230Sstevel@tonic-gate 		CPR->c_flags |= C_COMPRESSING;
1240Sstevel@tonic-gate 	/*
1250Sstevel@tonic-gate 	 * reserve CPR_MAXCONTIG virtual pages for cpr_dump()
1260Sstevel@tonic-gate 	 */
1270Sstevel@tonic-gate 	CPR->c_mapping_area = i_cpr_map_setup();
1280Sstevel@tonic-gate 	if (CPR->c_mapping_area == 0) {		/* no space in kernelmap */
1290Sstevel@tonic-gate 		cpr_err(CE_CONT, "Unable to alloc from kernelmap.\n");
1300Sstevel@tonic-gate 		mutex_exit(&cpr_slock);
1310Sstevel@tonic-gate 		return (EAGAIN);
1320Sstevel@tonic-gate 	}
1333446Smrj 	if (cpr_debug & CPR_DEBUG3)
1343446Smrj 		cpr_err(CE_CONT, "Reserved virtual range from 0x%p for writing "
1353446Smrj 		    "kas\n", (void *)CPR->c_mapping_area);
1365295Srandyf #endif
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	return (0);
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate /*
1420Sstevel@tonic-gate  * This routine releases any resources used during the checkpoint.
1430Sstevel@tonic-gate  */
1440Sstevel@tonic-gate void
cpr_done(void)1450Sstevel@tonic-gate cpr_done(void)
1460Sstevel@tonic-gate {
1470Sstevel@tonic-gate 	cpr_stat_cleanup();
1480Sstevel@tonic-gate 	i_cpr_bitmap_cleanup();
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	/*
1510Sstevel@tonic-gate 	 * Free pages used by cpr buffers.
1520Sstevel@tonic-gate 	 */
1530Sstevel@tonic-gate 	if (cpr_buf) {
1540Sstevel@tonic-gate 		kmem_free(cpr_buf, cpr_buf_size);
1550Sstevel@tonic-gate 		cpr_buf = NULL;
1560Sstevel@tonic-gate 	}
1570Sstevel@tonic-gate 	if (cpr_pagedata) {
1580Sstevel@tonic-gate 		kmem_free(cpr_pagedata, cpr_pagedata_size);
1590Sstevel@tonic-gate 		cpr_pagedata = NULL;
1600Sstevel@tonic-gate 	}
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	i_cpr_free_memory_resources();
1630Sstevel@tonic-gate 	mutex_exit(&cpr_slock);
1640Sstevel@tonic-gate 	cpr_err(CE_CONT, "System has been resumed.\n");
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 
1685295Srandyf #if defined(__sparc)
1690Sstevel@tonic-gate /*
1700Sstevel@tonic-gate  * reads config data into cprconfig
1710Sstevel@tonic-gate  */
1720Sstevel@tonic-gate static int
cpr_get_config(void)1730Sstevel@tonic-gate cpr_get_config(void)
1740Sstevel@tonic-gate {
1750Sstevel@tonic-gate 	static char config_path[] = CPR_CONFIG;
1760Sstevel@tonic-gate 	struct cprconfig *cf = &cprconfig;
1770Sstevel@tonic-gate 	struct vnode *vp;
1780Sstevel@tonic-gate 	char *fmt;
1790Sstevel@tonic-gate 	int err;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	if (cprconfig_loaded)
1820Sstevel@tonic-gate 		return (0);
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	fmt = "cannot %s config file \"%s\", error %d\n";
1850Sstevel@tonic-gate 	if (err = vn_open(config_path, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0)) {
1860Sstevel@tonic-gate 		cpr_err(CE_CONT, fmt, "open", config_path, err);
1870Sstevel@tonic-gate 		return (err);
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	err = cpr_rdwr(UIO_READ, vp, cf, sizeof (*cf));
1915331Samw 	(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
1920Sstevel@tonic-gate 	VN_RELE(vp);
1930Sstevel@tonic-gate 	if (err) {
1940Sstevel@tonic-gate 		cpr_err(CE_CONT, fmt, "read", config_path, err);
1950Sstevel@tonic-gate 		return (err);
1960Sstevel@tonic-gate 	}
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	if (cf->cf_magic == CPR_CONFIG_MAGIC)
1990Sstevel@tonic-gate 		cprconfig_loaded = 1;
2000Sstevel@tonic-gate 	else {
2010Sstevel@tonic-gate 		cpr_err(CE_CONT, "invalid config file \"%s\", "
2020Sstevel@tonic-gate 		    "rerun pmconfig(1M)\n", config_path);
2030Sstevel@tonic-gate 		err = EINVAL;
2040Sstevel@tonic-gate 	}
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	return (err);
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate /*
2110Sstevel@tonic-gate  * concat fs and path fields of the cprconfig structure;
2120Sstevel@tonic-gate  * returns pointer to the base of static data
2130Sstevel@tonic-gate  */
2140Sstevel@tonic-gate static char *
cpr_cprconfig_to_path(void)2150Sstevel@tonic-gate cpr_cprconfig_to_path(void)
2160Sstevel@tonic-gate {
2170Sstevel@tonic-gate 	static char full_path[MAXNAMELEN];
2180Sstevel@tonic-gate 	struct cprconfig *cf = &cprconfig;
2190Sstevel@tonic-gate 	char *ptr;
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	/*
2220Sstevel@tonic-gate 	 * build /fs/path without extra '/'
2230Sstevel@tonic-gate 	 */
2240Sstevel@tonic-gate 	(void) strcpy(full_path, cf->cf_fs);
2250Sstevel@tonic-gate 	if (strcmp(cf->cf_fs, "/"))
2260Sstevel@tonic-gate 		(void) strcat(full_path, "/");
2270Sstevel@tonic-gate 	ptr = cf->cf_path;
2280Sstevel@tonic-gate 	if (*ptr == '/')
2290Sstevel@tonic-gate 		ptr++;
2300Sstevel@tonic-gate 	(void) strcat(full_path, ptr);
2310Sstevel@tonic-gate 	return (full_path);
2320Sstevel@tonic-gate }
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate /*
2360Sstevel@tonic-gate  * Verify that the information in the configuration file regarding the
2370Sstevel@tonic-gate  * location for the statefile is still valid, depending on cf_type.
2380Sstevel@tonic-gate  * for CFT_UFS, cf_fs must still be a mounted filesystem, it must be
2390Sstevel@tonic-gate  *	mounted on the same device as when pmconfig was last run,
2400Sstevel@tonic-gate  *	and the translation of that device to a node in the prom's
2410Sstevel@tonic-gate  *	device tree must be the same as when pmconfig was last run.
2426423Sgw25295  * for CFT_SPEC and CFT_ZVOL, cf_path must be the path to a block
2436423Sgw25295  *      special file, it must have no file system mounted on it,
2440Sstevel@tonic-gate  *	and the translation of that device to a node in the prom's
2450Sstevel@tonic-gate  *	device tree must be the same as when pmconfig was last run.
2460Sstevel@tonic-gate  */
2470Sstevel@tonic-gate static int
cpr_verify_statefile_path(void)2480Sstevel@tonic-gate cpr_verify_statefile_path(void)
2490Sstevel@tonic-gate {
2500Sstevel@tonic-gate 	struct cprconfig *cf = &cprconfig;
2510Sstevel@tonic-gate 	static const char long_name[] = "Statefile pathname is too long.\n";
2520Sstevel@tonic-gate 	static const char lookup_fmt[] = "Lookup failed for "
2530Sstevel@tonic-gate 	    "cpr statefile device %s.\n";
2540Sstevel@tonic-gate 	static const char path_chg_fmt[] = "Device path for statefile "
2550Sstevel@tonic-gate 	    "has changed from %s to %s.\t%s\n";
2560Sstevel@tonic-gate 	static const char rerun[] = "Please rerun pmconfig(1m).";
2570Sstevel@tonic-gate 	struct vfs *vfsp = NULL, *vfsp_save = rootvfs;
2580Sstevel@tonic-gate 	ufsvfs_t *ufsvfsp = (ufsvfs_t *)rootvfs->vfs_data;
2590Sstevel@tonic-gate 	ufsvfs_t *ufsvfsp_save = ufsvfsp;
2600Sstevel@tonic-gate 	int error;
2610Sstevel@tonic-gate 	struct vnode *vp;
2620Sstevel@tonic-gate 	char *slash, *tail, *longest;
2630Sstevel@tonic-gate 	char *errstr;
2640Sstevel@tonic-gate 	int found = 0;
2650Sstevel@tonic-gate 	union {
2660Sstevel@tonic-gate 		char un_devpath[OBP_MAXPATHLEN];
2670Sstevel@tonic-gate 		char un_sfpath[MAXNAMELEN];
2680Sstevel@tonic-gate 	} un;
2690Sstevel@tonic-gate #define	devpath	un.un_devpath
2700Sstevel@tonic-gate #define	sfpath	un.un_sfpath
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	ASSERT(cprconfig_loaded);
2730Sstevel@tonic-gate 	/*
2740Sstevel@tonic-gate 	 * We need not worry about locking or the timing of releasing
2750Sstevel@tonic-gate 	 * the vnode, since we are single-threaded now.
2760Sstevel@tonic-gate 	 */
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	switch (cf->cf_type) {
2790Sstevel@tonic-gate 	case CFT_SPEC:
2806423Sgw25295 		error = i_devname_to_promname(cf->cf_devfs, devpath,
2816423Sgw25295 		    OBP_MAXPATHLEN);
2826423Sgw25295 		if (error || strcmp(devpath, cf->cf_dev_prom)) {
2836423Sgw25295 			cpr_err(CE_CONT, path_chg_fmt,
2846423Sgw25295 			    cf->cf_dev_prom, devpath, rerun);
2856423Sgw25295 			return (error);
2866423Sgw25295 		}
2876423Sgw25295 		/*FALLTHROUGH*/
2886423Sgw25295 	case CFT_ZVOL:
2890Sstevel@tonic-gate 		if (strlen(cf->cf_path) > sizeof (sfpath)) {
2900Sstevel@tonic-gate 			cpr_err(CE_CONT, long_name);
2910Sstevel@tonic-gate 			return (ENAMETOOLONG);
2920Sstevel@tonic-gate 		}
2930Sstevel@tonic-gate 		if ((error = lookupname(cf->cf_devfs,
2940Sstevel@tonic-gate 		    UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) != 0) {
2950Sstevel@tonic-gate 			cpr_err(CE_CONT, lookup_fmt, cf->cf_devfs);
2960Sstevel@tonic-gate 			return (error);
2970Sstevel@tonic-gate 		}
2980Sstevel@tonic-gate 		if (vp->v_type != VBLK)
2990Sstevel@tonic-gate 			errstr = "statefile must be a block device";
3000Sstevel@tonic-gate 		else if (vfs_devismounted(vp->v_rdev))
3010Sstevel@tonic-gate 			errstr = "statefile device must not "
3020Sstevel@tonic-gate 			    "have a file system mounted on it";
3030Sstevel@tonic-gate 		else if (IS_SWAPVP(vp))
3040Sstevel@tonic-gate 			errstr = "statefile device must not "
3050Sstevel@tonic-gate 			    "be configured as swap file";
3060Sstevel@tonic-gate 		else
3070Sstevel@tonic-gate 			errstr = NULL;
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 		VN_RELE(vp);
3100Sstevel@tonic-gate 		if (errstr) {
3110Sstevel@tonic-gate 			cpr_err(CE_CONT, "%s.\n", errstr);
3120Sstevel@tonic-gate 			return (ENOTSUP);
3130Sstevel@tonic-gate 		}
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 		return (error);
3160Sstevel@tonic-gate 	case CFT_UFS:
3170Sstevel@tonic-gate 		break;		/* don't indent all the original code */
3180Sstevel@tonic-gate 	default:
3190Sstevel@tonic-gate 		cpr_err(CE_PANIC, "invalid cf_type");
3200Sstevel@tonic-gate 	}
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	/*
3230Sstevel@tonic-gate 	 * The original code for UFS statefile
3240Sstevel@tonic-gate 	 */
3250Sstevel@tonic-gate 	if (strlen(cf->cf_fs) + strlen(cf->cf_path) + 2 > sizeof (sfpath)) {
3260Sstevel@tonic-gate 		cpr_err(CE_CONT, long_name);
3270Sstevel@tonic-gate 		return (ENAMETOOLONG);
3280Sstevel@tonic-gate 	}
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	bzero(sfpath, sizeof (sfpath));
3310Sstevel@tonic-gate 	(void) strcpy(sfpath, cpr_cprconfig_to_path());
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	if (*sfpath != '/') {
3340Sstevel@tonic-gate 		cpr_err(CE_CONT, "Statefile pathname %s "
3350Sstevel@tonic-gate 		    "must begin with a /\n", sfpath);
3360Sstevel@tonic-gate 		return (EINVAL);
3370Sstevel@tonic-gate 	}
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	/*
3400Sstevel@tonic-gate 	 * Find the longest prefix of the statefile pathname which
3410Sstevel@tonic-gate 	 * is the mountpoint of a filesystem.  This string must
3420Sstevel@tonic-gate 	 * match the cf_fs field we read from the config file.  Other-
3430Sstevel@tonic-gate 	 * wise the user has changed things without running pmconfig.
3440Sstevel@tonic-gate 	 */
3450Sstevel@tonic-gate 	tail = longest = sfpath + 1;	/* pt beyond the leading "/" */
3460Sstevel@tonic-gate 	while ((slash = strchr(tail, '/')) != NULL) {
3470Sstevel@tonic-gate 		*slash = '\0';	  /* temporarily terminate the string */
3480Sstevel@tonic-gate 		if ((error = lookupname(sfpath,
3490Sstevel@tonic-gate 		    UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) != 0) {
3500Sstevel@tonic-gate 			*slash = '/';
3510Sstevel@tonic-gate 			cpr_err(CE_CONT, "A directory in the "
3520Sstevel@tonic-gate 			    "statefile path %s was not found.\n", sfpath);
3530Sstevel@tonic-gate 			VN_RELE(vp);
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 			return (error);
3560Sstevel@tonic-gate 		}
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 		vfs_list_read_lock();
3590Sstevel@tonic-gate 		vfsp = rootvfs;
3600Sstevel@tonic-gate 		do {
3610Sstevel@tonic-gate 			ufsvfsp = (struct ufsvfs *)vfsp->vfs_data;
3620Sstevel@tonic-gate 			if (ufsvfsp != NULL && ufsvfsp->vfs_root == vp) {
3630Sstevel@tonic-gate 				found = 1;
3640Sstevel@tonic-gate 				break;
3650Sstevel@tonic-gate 			}
3660Sstevel@tonic-gate 			vfsp = vfsp->vfs_next;
3670Sstevel@tonic-gate 		} while (vfsp != rootvfs);
3680Sstevel@tonic-gate 		vfs_list_unlock();
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 		/*
3710Sstevel@tonic-gate 		 * If we have found a filesystem mounted on the current
3720Sstevel@tonic-gate 		 * path prefix, remember the end of the string in
3730Sstevel@tonic-gate 		 * "longest".  If it happens to be the the exact fs
3740Sstevel@tonic-gate 		 * saved in the configuration file, save the current
3750Sstevel@tonic-gate 		 * ufsvfsp so we can make additional checks further down.
3760Sstevel@tonic-gate 		 */
3770Sstevel@tonic-gate 		if (found) {
3780Sstevel@tonic-gate 			longest = slash;
3790Sstevel@tonic-gate 			if (strcmp(cf->cf_fs, sfpath) == 0) {
3800Sstevel@tonic-gate 				ufsvfsp_save = ufsvfsp;
3810Sstevel@tonic-gate 				vfsp_save = vfsp;
3820Sstevel@tonic-gate 			}
3830Sstevel@tonic-gate 			found = 0;
3840Sstevel@tonic-gate 		}
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 		VN_RELE(vp);
3870Sstevel@tonic-gate 		*slash = '/';
3880Sstevel@tonic-gate 		tail = slash + 1;
3890Sstevel@tonic-gate 	}
3900Sstevel@tonic-gate 	*longest = '\0';
3910Sstevel@tonic-gate 	if (cpr_is_ufs(vfsp_save) == 0 || strcmp(cf->cf_fs, sfpath)) {
3920Sstevel@tonic-gate 		cpr_err(CE_CONT, "Filesystem containing "
3930Sstevel@tonic-gate 		    "the statefile when pmconfig was run (%s) has "
3940Sstevel@tonic-gate 		    "changed to %s. %s\n", cf->cf_fs, sfpath, rerun);
3950Sstevel@tonic-gate 		return (EINVAL);
3960Sstevel@tonic-gate 	}
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	if ((error = lookupname(cf->cf_devfs,
3990Sstevel@tonic-gate 	    UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) != 0) {
4000Sstevel@tonic-gate 		cpr_err(CE_CONT, lookup_fmt, cf->cf_devfs);
4010Sstevel@tonic-gate 		return (error);
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	if (ufsvfsp_save->vfs_devvp->v_rdev != vp->v_rdev) {
4050Sstevel@tonic-gate 		cpr_err(CE_CONT, "Filesystem containing "
4060Sstevel@tonic-gate 		    "statefile no longer mounted on device %s. "
4070Sstevel@tonic-gate 		    "See power.conf(4).", cf->cf_devfs);
4080Sstevel@tonic-gate 		VN_RELE(vp);
4090Sstevel@tonic-gate 		return (ENXIO);
4100Sstevel@tonic-gate 	}
4110Sstevel@tonic-gate 	VN_RELE(vp);
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	error = i_devname_to_promname(cf->cf_devfs, devpath, OBP_MAXPATHLEN);
4140Sstevel@tonic-gate 	if (error || strcmp(devpath, cf->cf_dev_prom)) {
4150Sstevel@tonic-gate 		cpr_err(CE_CONT, path_chg_fmt,
4160Sstevel@tonic-gate 		    cf->cf_dev_prom, devpath, rerun);
4170Sstevel@tonic-gate 		return (error);
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	return (0);
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate /*
4240Sstevel@tonic-gate  * Make sure that the statefile can be used as a block special statefile
4250Sstevel@tonic-gate  * (meaning that is exists and has nothing mounted on it)
4260Sstevel@tonic-gate  * Returns errno if not a valid statefile.
4270Sstevel@tonic-gate  */
4280Sstevel@tonic-gate int
cpr_check_spec_statefile(void)4290Sstevel@tonic-gate cpr_check_spec_statefile(void)
4300Sstevel@tonic-gate {
4310Sstevel@tonic-gate 	int err;
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	if (err = cpr_get_config())
4340Sstevel@tonic-gate 		return (err);
4356423Sgw25295 	ASSERT(cprconfig.cf_type == CFT_SPEC ||
4366423Sgw25295 	    cprconfig.cf_type == CFT_ZVOL);
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	if (cprconfig.cf_devfs == NULL)
4390Sstevel@tonic-gate 		return (ENXIO);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	return (cpr_verify_statefile_path());
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate int
cpr_alloc_statefile(int alloc_retry)4460Sstevel@tonic-gate cpr_alloc_statefile(int alloc_retry)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate 	register int rc = 0;
4490Sstevel@tonic-gate 	char *str;
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	/*
4520Sstevel@tonic-gate 	 * Statefile size validation. If checkpoint the first time, disk blocks
4530Sstevel@tonic-gate 	 * allocation will be done; otherwise, just do file size check.
4540Sstevel@tonic-gate 	 * if statefile allocation is being retried, C_VP will be inited
4550Sstevel@tonic-gate 	 */
4560Sstevel@tonic-gate 	if (alloc_retry) {
4570Sstevel@tonic-gate 		str = "\n-->Retrying statefile allocation...";
4583446Smrj 		if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG7))
4593446Smrj 			prom_printf(str);
4600Sstevel@tonic-gate 		if (C_VP->v_type != VBLK)
4615331Samw 			(void) VOP_DUMPCTL(C_VP, DUMP_FREE, NULL, NULL);
4620Sstevel@tonic-gate 	} else {
4630Sstevel@tonic-gate 		/*
4640Sstevel@tonic-gate 		 * Open an exiting file for writing, the state file needs to be
4650Sstevel@tonic-gate 		 * pre-allocated since we can't and don't want to do allocation
4660Sstevel@tonic-gate 		 * during checkpoint (too much of the OS is disabled).
4670Sstevel@tonic-gate 		 *    - do a preliminary size checking here, if it is too small,
4680Sstevel@tonic-gate 		 *	allocate more space internally and retry.
4690Sstevel@tonic-gate 		 *    - check the vp to make sure it's the right type.
4700Sstevel@tonic-gate 		 */
4710Sstevel@tonic-gate 		char *path = cpr_build_statefile_path();
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 		if (path == NULL)
4740Sstevel@tonic-gate 			return (ENXIO);
4750Sstevel@tonic-gate 		else if (rc = cpr_verify_statefile_path())
4760Sstevel@tonic-gate 			return (rc);
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 		if (rc = vn_open(path, UIO_SYSSPACE,
4790Sstevel@tonic-gate 		    FCREAT|FWRITE, 0600, &C_VP, CRCREAT, 0)) {
4800Sstevel@tonic-gate 			cpr_err(CE_WARN, "cannot open statefile %s", path);
4810Sstevel@tonic-gate 			return (rc);
4820Sstevel@tonic-gate 		}
4830Sstevel@tonic-gate 	}
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	/*
4860Sstevel@tonic-gate 	 * Only ufs and block special statefiles supported
4870Sstevel@tonic-gate 	 */
4880Sstevel@tonic-gate 	if (C_VP->v_type != VREG && C_VP->v_type != VBLK) {
4890Sstevel@tonic-gate 		cpr_err(CE_CONT,
4900Sstevel@tonic-gate 		    "Statefile must be regular file or block special file.");
4910Sstevel@tonic-gate 		return (EACCES);
4920Sstevel@tonic-gate 	}
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	if (rc = cpr_statefile_ok(C_VP, alloc_retry))
4950Sstevel@tonic-gate 		return (rc);
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	if (C_VP->v_type != VBLK) {
4980Sstevel@tonic-gate 		/*
4990Sstevel@tonic-gate 		 * sync out the fs change due to the statefile reservation.
5000Sstevel@tonic-gate 		 */
5010Sstevel@tonic-gate 		(void) VFS_SYNC(C_VP->v_vfsp, 0, CRED());
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 		/*
5040Sstevel@tonic-gate 		 * Validate disk blocks allocation for the state file.
5050Sstevel@tonic-gate 		 * Ask the file system prepare itself for the dump operation.
5060Sstevel@tonic-gate 		 */
5075331Samw 		if (rc = VOP_DUMPCTL(C_VP, DUMP_ALLOC, NULL, NULL)) {
5080Sstevel@tonic-gate 			cpr_err(CE_CONT, "Error allocating "
5090Sstevel@tonic-gate 			    "blocks for cpr statefile.");
5100Sstevel@tonic-gate 			return (rc);
5110Sstevel@tonic-gate 		}
5120Sstevel@tonic-gate 	}
5130Sstevel@tonic-gate 	return (0);
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate /*
5184582Scth  * Lookup device size and return available space in bytes.
5194582Scth  * NOTE: Since prop_op(9E) can't tell the difference between a character
5204582Scth  * and a block reference, it is ok to ask for "Size" instead of "Nblocks".
5210Sstevel@tonic-gate  */
5220Sstevel@tonic-gate size_t
cpr_get_devsize(dev_t dev)5230Sstevel@tonic-gate cpr_get_devsize(dev_t dev)
5240Sstevel@tonic-gate {
5250Sstevel@tonic-gate 	size_t bytes = 0;
5260Sstevel@tonic-gate 
5274582Scth 	bytes = cdev_Size(dev);
5284582Scth 	if (bytes == 0)
5294582Scth 		bytes = cdev_size(dev);
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	if (bytes > CPR_SPEC_OFFSET)
5320Sstevel@tonic-gate 		bytes -= CPR_SPEC_OFFSET;
5330Sstevel@tonic-gate 	else
5340Sstevel@tonic-gate 		bytes = 0;
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	return (bytes);
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate /*
5410Sstevel@tonic-gate  * increase statefile size
5420Sstevel@tonic-gate  */
5430Sstevel@tonic-gate static int
cpr_grow_statefile(vnode_t * vp,u_longlong_t newsize)5440Sstevel@tonic-gate cpr_grow_statefile(vnode_t *vp, u_longlong_t newsize)
5450Sstevel@tonic-gate {
5460Sstevel@tonic-gate 	extern uchar_t cpr_pagecopy[];
5470Sstevel@tonic-gate 	struct inode *ip = VTOI(vp);
5480Sstevel@tonic-gate 	u_longlong_t offset;
5490Sstevel@tonic-gate 	int error, increase;
5500Sstevel@tonic-gate 	ssize_t resid;
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	rw_enter(&ip->i_contents, RW_READER);
5530Sstevel@tonic-gate 	increase = (ip->i_size < newsize);
5540Sstevel@tonic-gate 	offset = ip->i_size;
5550Sstevel@tonic-gate 	rw_exit(&ip->i_contents);
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	if (increase == 0)
5580Sstevel@tonic-gate 		return (0);
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	/*
5610Sstevel@tonic-gate 	 * write to each logical block to reserve disk space
5620Sstevel@tonic-gate 	 */
5630Sstevel@tonic-gate 	error = 0;
5640Sstevel@tonic-gate 	cpr_pagecopy[0] = '1';
5650Sstevel@tonic-gate 	for (; offset < newsize; offset += ip->i_fs->fs_bsize) {
5660Sstevel@tonic-gate 		if (error = vn_rdwr(UIO_WRITE, vp, (caddr_t)cpr_pagecopy,
5670Sstevel@tonic-gate 		    ip->i_fs->fs_bsize, (offset_t)offset, UIO_SYSSPACE, 0,
5680Sstevel@tonic-gate 		    (rlim64_t)MAXOFF_T, CRED(), &resid)) {
5690Sstevel@tonic-gate 			if (error == ENOSPC) {
5700Sstevel@tonic-gate 				cpr_err(CE_WARN, "error %d while reserving "
5710Sstevel@tonic-gate 				    "disk space for statefile %s\n"
5720Sstevel@tonic-gate 				    "wanted %lld bytes, file is %lld short",
5730Sstevel@tonic-gate 				    error, cpr_cprconfig_to_path(),
5740Sstevel@tonic-gate 				    newsize, newsize - offset);
5750Sstevel@tonic-gate 			}
5760Sstevel@tonic-gate 			break;
5770Sstevel@tonic-gate 		}
5780Sstevel@tonic-gate 	}
5790Sstevel@tonic-gate 	return (error);
5800Sstevel@tonic-gate }
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate /*
5840Sstevel@tonic-gate  * do a simple estimate of the space needed to hold the statefile
5850Sstevel@tonic-gate  * taking compression into account, but be fairly conservative
5860Sstevel@tonic-gate  * so we have a better chance of completing; when dump fails,
5870Sstevel@tonic-gate  * the retry cost is fairly high.
5880Sstevel@tonic-gate  *
5890Sstevel@tonic-gate  * Do disk blocks allocation for the state file if no space has
5900Sstevel@tonic-gate  * been allocated yet. Since the state file will not be removed,
5910Sstevel@tonic-gate  * allocation should only be done once.
5920Sstevel@tonic-gate  */
5930Sstevel@tonic-gate static int
cpr_statefile_ok(vnode_t * vp,int alloc_retry)5940Sstevel@tonic-gate cpr_statefile_ok(vnode_t *vp, int alloc_retry)
5950Sstevel@tonic-gate {
5960Sstevel@tonic-gate 	extern size_t cpr_bitmap_size;
5970Sstevel@tonic-gate 	struct inode *ip = VTOI(vp);
5980Sstevel@tonic-gate 	const int UCOMP_RATE = 20; /* comp. ratio*10 for user pages */
5990Sstevel@tonic-gate 	u_longlong_t size, isize, ksize, raw_data;
6000Sstevel@tonic-gate 	char *str, *est_fmt;
6010Sstevel@tonic-gate 	size_t space;
6020Sstevel@tonic-gate 	int error;
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	/*
6050Sstevel@tonic-gate 	 * number of pages short for swapping.
6060Sstevel@tonic-gate 	 */
6070Sstevel@tonic-gate 	STAT->cs_nosw_pages = k_anoninfo.ani_mem_resv;
6080Sstevel@tonic-gate 	if (STAT->cs_nosw_pages < 0)
6090Sstevel@tonic-gate 		STAT->cs_nosw_pages = 0;
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	str = "cpr_statefile_ok:";
6120Sstevel@tonic-gate 
6133446Smrj 	CPR_DEBUG(CPR_DEBUG9, "Phys swap: max=%lu resv=%lu\n",
6143446Smrj 	    k_anoninfo.ani_max, k_anoninfo.ani_phys_resv);
6153446Smrj 	CPR_DEBUG(CPR_DEBUG9, "Mem swap: max=%ld resv=%lu\n",
6160Sstevel@tonic-gate 	    MAX(availrmem - swapfs_minfree, 0),
6173446Smrj 	    k_anoninfo.ani_mem_resv);
6183446Smrj 	CPR_DEBUG(CPR_DEBUG9, "Total available swap: %ld\n",
6194582Scth 	    CURRENT_TOTAL_AVAILABLE_SWAP);
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	/*
6220Sstevel@tonic-gate 	 * try increasing filesize by 15%
6230Sstevel@tonic-gate 	 */
6240Sstevel@tonic-gate 	if (alloc_retry) {
6250Sstevel@tonic-gate 		/*
6260Sstevel@tonic-gate 		 * block device doesn't get any bigger
6270Sstevel@tonic-gate 		 */
6280Sstevel@tonic-gate 		if (vp->v_type == VBLK) {
6293446Smrj 			if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG6))
6303446Smrj 				prom_printf(
6313446Smrj 				    "Retry statefile on special file\n");
6320Sstevel@tonic-gate 			return (ENOMEM);
6330Sstevel@tonic-gate 		} else {
6340Sstevel@tonic-gate 			rw_enter(&ip->i_contents, RW_READER);
6350Sstevel@tonic-gate 			size = (ip->i_size * SIZE_RATE) / INTEGRAL;
6360Sstevel@tonic-gate 			rw_exit(&ip->i_contents);
6370Sstevel@tonic-gate 		}
6383446Smrj 		if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG6))
6393446Smrj 			prom_printf("Retry statefile size = %lld\n", size);
6400Sstevel@tonic-gate 	} else {
6410Sstevel@tonic-gate 		u_longlong_t cpd_size;
6420Sstevel@tonic-gate 		pgcnt_t npages, nback;
6430Sstevel@tonic-gate 		int ndvram;
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 		ndvram = 0;
646931Smathue 		(void) callb_execute_class(CB_CL_CPR_FB,
647931Smathue 		    (int)(uintptr_t)&ndvram);
6483446Smrj 		if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG6))
6493446Smrj 			prom_printf("ndvram size = %d\n", ndvram);
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 		/*
6520Sstevel@tonic-gate 		 * estimate 1 cpd_t for every (CPR_MAXCONTIG / 2) pages
6530Sstevel@tonic-gate 		 */
6540Sstevel@tonic-gate 		npages = cpr_count_kpages(REGULAR_BITMAP, cpr_nobit);
6550Sstevel@tonic-gate 		cpd_size = sizeof (cpd_t) * (npages / (CPR_MAXCONTIG / 2));
6560Sstevel@tonic-gate 		raw_data = cpd_size + cpr_bitmap_size;
6570Sstevel@tonic-gate 		ksize = ndvram + mmu_ptob(npages);
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 		est_fmt = "%s estimated size with "
6600Sstevel@tonic-gate 		    "%scompression %lld, ksize %lld\n";
6610Sstevel@tonic-gate 		nback = mmu_ptob(STAT->cs_nosw_pages);
6620Sstevel@tonic-gate 		if (CPR->c_flags & C_COMPRESSING) {
6630Sstevel@tonic-gate 			size = ((ksize * COMPRESS_PERCENT) / INTEGRAL) +
6640Sstevel@tonic-gate 			    raw_data + ((nback * 10) / UCOMP_RATE);
6653446Smrj 			CPR_DEBUG(CPR_DEBUG1, est_fmt, str, "", size, ksize);
6660Sstevel@tonic-gate 		} else {
6670Sstevel@tonic-gate 			size = ksize + raw_data + nback;
6683446Smrj 			CPR_DEBUG(CPR_DEBUG1, est_fmt, str, "no ",
6693446Smrj 			    size, ksize);
6700Sstevel@tonic-gate 		}
6710Sstevel@tonic-gate 	}
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	/*
6740Sstevel@tonic-gate 	 * All this is much simpler for a block device
6750Sstevel@tonic-gate 	 */
6760Sstevel@tonic-gate 	if (vp->v_type == VBLK) {
6770Sstevel@tonic-gate 		space = cpr_get_devsize(vp->v_rdev);
6783446Smrj 		if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG6))
6793446Smrj 			prom_printf("statefile dev size %lu\n", space);
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 		/*
6820Sstevel@tonic-gate 		 * Export the estimated filesize info, this value will be
6830Sstevel@tonic-gate 		 * compared before dumping out the statefile in the case of
6840Sstevel@tonic-gate 		 * no compression.
6850Sstevel@tonic-gate 		 */
6860Sstevel@tonic-gate 		STAT->cs_est_statefsz = size;
6873446Smrj 		if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG6))
6883446Smrj 			prom_printf("%s Estimated statefile size %llu, "
6893446Smrj 			    "space %lu\n", str, size, space);
6900Sstevel@tonic-gate 		if (size > space) {
6910Sstevel@tonic-gate 			cpr_err(CE_CONT, "Statefile partition too small.");
6920Sstevel@tonic-gate 			return (ENOMEM);
6930Sstevel@tonic-gate 		}
6940Sstevel@tonic-gate 		return (0);
6950Sstevel@tonic-gate 	} else {
6960Sstevel@tonic-gate 		if (CPR->c_alloc_cnt++ > C_MAX_ALLOC_RETRY) {
6970Sstevel@tonic-gate 			cpr_err(CE_CONT, "Statefile allocation retry failed\n");
6980Sstevel@tonic-gate 			return (ENOMEM);
6990Sstevel@tonic-gate 		}
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 		/*
7020Sstevel@tonic-gate 		 * Estimate space needed for the state file.
7030Sstevel@tonic-gate 		 *
7040Sstevel@tonic-gate 		 * State file size in bytes:
7050Sstevel@tonic-gate 		 * 	kernel size + non-cache pte seg +
7060Sstevel@tonic-gate 		 *	bitmap size + cpr state file headers size
7070Sstevel@tonic-gate 		 * (round up to fs->fs_bsize)
7080Sstevel@tonic-gate 		 */
7090Sstevel@tonic-gate 		size = blkroundup(ip->i_fs, size);
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 		/*
7120Sstevel@tonic-gate 		 * Export the estimated filesize info, this value will be
7130Sstevel@tonic-gate 		 * compared before dumping out the statefile in the case of
7140Sstevel@tonic-gate 		 * no compression.
7150Sstevel@tonic-gate 		 */
7160Sstevel@tonic-gate 		STAT->cs_est_statefsz = size;
7170Sstevel@tonic-gate 		error = cpr_grow_statefile(vp, size);
7183446Smrj 		if (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG6)) {
7190Sstevel@tonic-gate 			rw_enter(&ip->i_contents, RW_READER);
7200Sstevel@tonic-gate 			isize = ip->i_size;
7210Sstevel@tonic-gate 			rw_exit(&ip->i_contents);
7223446Smrj 			prom_printf("%s Estimated statefile size %lld, "
7233446Smrj 			    "i_size %lld\n", str, size, isize);
7240Sstevel@tonic-gate 		}
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 		return (error);
7270Sstevel@tonic-gate 	}
7280Sstevel@tonic-gate }
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate void
cpr_statef_close(void)7320Sstevel@tonic-gate cpr_statef_close(void)
7330Sstevel@tonic-gate {
7340Sstevel@tonic-gate 	if (C_VP) {
7350Sstevel@tonic-gate 		if (!cpr_reusable_mode)
7365331Samw 			(void) VOP_DUMPCTL(C_VP, DUMP_FREE, NULL, NULL);
7375331Samw 		(void) VOP_CLOSE(C_VP, FWRITE, 1, (offset_t)0, CRED(), NULL);
7380Sstevel@tonic-gate 		VN_RELE(C_VP);
7390Sstevel@tonic-gate 		C_VP = 0;
7400Sstevel@tonic-gate 	}
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate /*
7450Sstevel@tonic-gate  * open cpr default file and display error
7460Sstevel@tonic-gate  */
7470Sstevel@tonic-gate int
cpr_open_deffile(int mode,vnode_t ** vpp)7480Sstevel@tonic-gate cpr_open_deffile(int mode, vnode_t **vpp)
7490Sstevel@tonic-gate {
7500Sstevel@tonic-gate 	int error;
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	if (error = cpr_open(cpr_default_path, mode, vpp))
7530Sstevel@tonic-gate 		cpr_err(CE_CONT, "cannot open \"%s\", error %d\n",
7540Sstevel@tonic-gate 		    cpr_default_path, error);
7550Sstevel@tonic-gate 	return (error);
7560Sstevel@tonic-gate }
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate /*
7600Sstevel@tonic-gate  * write cdef_t to disk.  This contains the original values of prom
7610Sstevel@tonic-gate  * properties that we modify.  We fill in the magic number of the file
7620Sstevel@tonic-gate  * here as a signal to the booter code that the state file is valid.
7630Sstevel@tonic-gate  * Be sure the file gets synced, since we may be shutting down the OS.
7640Sstevel@tonic-gate  */
7650Sstevel@tonic-gate int
cpr_write_deffile(cdef_t * cdef)7660Sstevel@tonic-gate cpr_write_deffile(cdef_t *cdef)
7670Sstevel@tonic-gate {
7680Sstevel@tonic-gate 	struct vnode *vp;
7690Sstevel@tonic-gate 	char *str;
7700Sstevel@tonic-gate 	int rc;
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	if (rc = cpr_open_deffile(FCREAT|FWRITE, &vp))
7730Sstevel@tonic-gate 		return (rc);
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	if (rc = cpr_rdwr(UIO_WRITE, vp, cdef, sizeof (*cdef)))
7760Sstevel@tonic-gate 		str = "write";
7775331Samw 	else if (rc = VOP_FSYNC(vp, FSYNC, CRED(), NULL))
7780Sstevel@tonic-gate 		str = "fsync";
7795331Samw 	(void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
7800Sstevel@tonic-gate 	VN_RELE(vp);
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	if (rc) {
7830Sstevel@tonic-gate 		cpr_err(CE_WARN, "%s error %d, file \"%s\"",
7840Sstevel@tonic-gate 		    str, rc, cpr_default_path);
7850Sstevel@tonic-gate 	}
7860Sstevel@tonic-gate 	return (rc);
7870Sstevel@tonic-gate }
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate /*
7900Sstevel@tonic-gate  * Clear the magic number in the defaults file.  This tells the booter
7910Sstevel@tonic-gate  * program that the state file is not current and thus prevents
7920Sstevel@tonic-gate  * any attempt to restore from an obsolete state file.
7930Sstevel@tonic-gate  */
7940Sstevel@tonic-gate void
cpr_clear_definfo(void)7950Sstevel@tonic-gate cpr_clear_definfo(void)
7960Sstevel@tonic-gate {
7970Sstevel@tonic-gate 	struct vnode *vp;
7980Sstevel@tonic-gate 	cmini_t mini;
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	if ((CPR->c_cprboot_magic != CPR_DEFAULT_MAGIC) ||
8010Sstevel@tonic-gate 	    cpr_open_deffile(FCREAT|FWRITE, &vp))
8020Sstevel@tonic-gate 		return;
8030Sstevel@tonic-gate 	mini.magic = mini.reusable = 0;
8040Sstevel@tonic-gate 	(void) cpr_rdwr(UIO_WRITE, vp, &mini, sizeof (mini));
8055331Samw 	(void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
8060Sstevel@tonic-gate 	VN_RELE(vp);
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate /*
8100Sstevel@tonic-gate  * If the cpr default file is invalid, then we must not be in reusable mode
8110Sstevel@tonic-gate  * if it is valid, it tells us our mode
8120Sstevel@tonic-gate  */
8130Sstevel@tonic-gate int
cpr_get_reusable_mode(void)8140Sstevel@tonic-gate cpr_get_reusable_mode(void)
8150Sstevel@tonic-gate {
8160Sstevel@tonic-gate 	struct vnode *vp;
8170Sstevel@tonic-gate 	cmini_t mini;
8180Sstevel@tonic-gate 	int rc;
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	if (cpr_open(cpr_default_path, FREAD, &vp))
8210Sstevel@tonic-gate 		return (0);
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	rc = cpr_rdwr(UIO_READ, vp, &mini, sizeof (mini));
8245331Samw 	(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
8250Sstevel@tonic-gate 	VN_RELE(vp);
8260Sstevel@tonic-gate 	if (rc == 0 && mini.magic == CPR_DEFAULT_MAGIC)
8270Sstevel@tonic-gate 		return (mini.reusable);
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	return (0);
8300Sstevel@tonic-gate }
8315295Srandyf #endif
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate /*
8340Sstevel@tonic-gate  * clock/time related routines
8350Sstevel@tonic-gate  */
8360Sstevel@tonic-gate static time_t   cpr_time_stamp;
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate void
cpr_tod_get(cpr_time_t * ctp)8400Sstevel@tonic-gate cpr_tod_get(cpr_time_t *ctp)
8410Sstevel@tonic-gate {
8420Sstevel@tonic-gate 	timestruc_t ts;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 	mutex_enter(&tod_lock);
8455295Srandyf 	ts = TODOP_GET(tod_ops);
8460Sstevel@tonic-gate 	mutex_exit(&tod_lock);
8470Sstevel@tonic-gate 	ctp->tv_sec = (time32_t)ts.tv_sec;
8480Sstevel@tonic-gate 	ctp->tv_nsec = (int32_t)ts.tv_nsec;
8490Sstevel@tonic-gate }
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate void
cpr_tod_status_set(int tod_flag)852*11752STrevor.Thompson@Sun.COM cpr_tod_status_set(int tod_flag)
8530Sstevel@tonic-gate {
8540Sstevel@tonic-gate 	mutex_enter(&tod_lock);
855*11752STrevor.Thompson@Sun.COM 	tod_status_set(tod_flag);
8560Sstevel@tonic-gate 	mutex_exit(&tod_lock);
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate void
cpr_save_time(void)8600Sstevel@tonic-gate cpr_save_time(void)
8610Sstevel@tonic-gate {
8620Sstevel@tonic-gate 	cpr_time_stamp = gethrestime_sec();
8630Sstevel@tonic-gate }
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate /*
8660Sstevel@tonic-gate  * correct time based on saved time stamp or hardware clock
8670Sstevel@tonic-gate  */
8680Sstevel@tonic-gate void
cpr_restore_time(void)8690Sstevel@tonic-gate cpr_restore_time(void)
8700Sstevel@tonic-gate {
8710Sstevel@tonic-gate 	clkset(cpr_time_stamp);
8720Sstevel@tonic-gate }
8730Sstevel@tonic-gate 
8745295Srandyf #if defined(__sparc)
8750Sstevel@tonic-gate /*
8760Sstevel@tonic-gate  * CPU ONLINE/OFFLINE CODE
8770Sstevel@tonic-gate  */
8780Sstevel@tonic-gate int
cpr_mp_offline(void)8790Sstevel@tonic-gate cpr_mp_offline(void)
8800Sstevel@tonic-gate {
8810Sstevel@tonic-gate 	cpu_t *cp, *bootcpu;
8820Sstevel@tonic-gate 	int rc = 0;
8830Sstevel@tonic-gate 	int brought_up_boot = 0;
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	/*
8860Sstevel@tonic-gate 	 * Do nothing for UP.
8870Sstevel@tonic-gate 	 */
8880Sstevel@tonic-gate 	if (ncpus == 1)
8890Sstevel@tonic-gate 		return (0);
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	cpr_save_mp_state();
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	bootcpu = i_cpr_bootcpu();
8960Sstevel@tonic-gate 	if (!CPU_ACTIVE(bootcpu)) {
8970Sstevel@tonic-gate 		if ((rc = cpr_p_online(bootcpu, CPU_CPR_ONLINE))) {
8980Sstevel@tonic-gate 			mutex_exit(&cpu_lock);
8990Sstevel@tonic-gate 			return (rc);
9000Sstevel@tonic-gate 		}
9010Sstevel@tonic-gate 		brought_up_boot = 1;
9020Sstevel@tonic-gate 	}
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	cp = cpu_list;
9050Sstevel@tonic-gate 	do {
9060Sstevel@tonic-gate 		if (cp == bootcpu)
9070Sstevel@tonic-gate 			continue;
9080Sstevel@tonic-gate 		if (cp->cpu_flags & CPU_OFFLINE)
9090Sstevel@tonic-gate 			continue;
9100Sstevel@tonic-gate 		if ((rc = cpr_p_online(cp, CPU_CPR_OFFLINE))) {
9110Sstevel@tonic-gate 			mutex_exit(&cpu_lock);
9120Sstevel@tonic-gate 			return (rc);
9130Sstevel@tonic-gate 		}
9140Sstevel@tonic-gate 	} while ((cp = cp->cpu_next) != cpu_list);
9153446Smrj 	if (brought_up_boot && (cpr_debug & (CPR_DEBUG1 | CPR_DEBUG6)))
9163446Smrj 		prom_printf("changed cpu %p to state %d\n",
9177240Srh87107 		    (void *)bootcpu, CPU_CPR_ONLINE);
9180Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	return (rc);
9210Sstevel@tonic-gate }
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate int
cpr_mp_online(void)9240Sstevel@tonic-gate cpr_mp_online(void)
9250Sstevel@tonic-gate {
9260Sstevel@tonic-gate 	cpu_t *cp, *bootcpu = CPU;
9270Sstevel@tonic-gate 	int rc = 0;
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	/*
9300Sstevel@tonic-gate 	 * Do nothing for UP.
9310Sstevel@tonic-gate 	 */
9320Sstevel@tonic-gate 	if (ncpus == 1)
9330Sstevel@tonic-gate 		return (0);
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	/*
9360Sstevel@tonic-gate 	 * cpr_save_mp_state() sets CPU_CPR_ONLINE in cpu_cpr_flags
9370Sstevel@tonic-gate 	 * to indicate a cpu was online at the time of cpr_suspend();
9380Sstevel@tonic-gate 	 * now restart those cpus that were marked as CPU_CPR_ONLINE
9390Sstevel@tonic-gate 	 * and actually are offline.
9400Sstevel@tonic-gate 	 */
9410Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
9420Sstevel@tonic-gate 	for (cp = bootcpu->cpu_next; cp != bootcpu; cp = cp->cpu_next) {
9430Sstevel@tonic-gate 		/*
9440Sstevel@tonic-gate 		 * Clear the CPU_FROZEN flag in all cases.
9450Sstevel@tonic-gate 		 */
9460Sstevel@tonic-gate 		cp->cpu_flags &= ~CPU_FROZEN;
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 		if (CPU_CPR_IS_OFFLINE(cp))
9490Sstevel@tonic-gate 			continue;
9500Sstevel@tonic-gate 		if (CPU_ACTIVE(cp))
9510Sstevel@tonic-gate 			continue;
9520Sstevel@tonic-gate 		if ((rc = cpr_p_online(cp, CPU_CPR_ONLINE))) {
9530Sstevel@tonic-gate 			mutex_exit(&cpu_lock);
9540Sstevel@tonic-gate 			return (rc);
9550Sstevel@tonic-gate 		}
9560Sstevel@tonic-gate 	}
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	/*
9590Sstevel@tonic-gate 	 * turn off the boot cpu if it was offlined
9600Sstevel@tonic-gate 	 */
9610Sstevel@tonic-gate 	if (CPU_CPR_IS_OFFLINE(bootcpu)) {
9620Sstevel@tonic-gate 		if ((rc = cpr_p_online(bootcpu, CPU_CPR_OFFLINE))) {
9630Sstevel@tonic-gate 			mutex_exit(&cpu_lock);
9640Sstevel@tonic-gate 			return (rc);
9650Sstevel@tonic-gate 		}
9660Sstevel@tonic-gate 	}
9670Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
9680Sstevel@tonic-gate 	return (0);
9690Sstevel@tonic-gate }
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate static void
cpr_save_mp_state(void)9720Sstevel@tonic-gate cpr_save_mp_state(void)
9730Sstevel@tonic-gate {
9740Sstevel@tonic-gate 	cpu_t *cp;
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	cp = cpu_list;
9790Sstevel@tonic-gate 	do {
9800Sstevel@tonic-gate 		cp->cpu_cpr_flags &= ~CPU_CPR_ONLINE;
9810Sstevel@tonic-gate 		if (CPU_ACTIVE(cp))
9820Sstevel@tonic-gate 			CPU_SET_CPR_FLAGS(cp, CPU_CPR_ONLINE);
9830Sstevel@tonic-gate 	} while ((cp = cp->cpu_next) != cpu_list);
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate /*
9870Sstevel@tonic-gate  * change cpu to online/offline
9880Sstevel@tonic-gate  */
9890Sstevel@tonic-gate static int
cpr_p_online(cpu_t * cp,int state)9900Sstevel@tonic-gate cpr_p_online(cpu_t *cp, int state)
9910Sstevel@tonic-gate {
9920Sstevel@tonic-gate 	int rc;
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 	switch (state) {
9970Sstevel@tonic-gate 	case CPU_CPR_ONLINE:
9980Sstevel@tonic-gate 		rc = cpu_online(cp);
9990Sstevel@tonic-gate 		break;
10000Sstevel@tonic-gate 	case CPU_CPR_OFFLINE:
10010Sstevel@tonic-gate 		rc = cpu_offline(cp, CPU_FORCED);
10020Sstevel@tonic-gate 		break;
10030Sstevel@tonic-gate 	}
10040Sstevel@tonic-gate 	if (rc) {
10050Sstevel@tonic-gate 		cpr_err(CE_WARN, "Failed to change processor %d to "
10060Sstevel@tonic-gate 		    "state %d, (errno %d)", cp->cpu_id, state, rc);
10070Sstevel@tonic-gate 	}
10080Sstevel@tonic-gate 	return (rc);
10090Sstevel@tonic-gate }
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate /*
10120Sstevel@tonic-gate  * Construct the pathname of the state file and return a pointer to
10130Sstevel@tonic-gate  * caller.  Read the config file to get the mount point of the
10140Sstevel@tonic-gate  * filesystem and the pathname within fs.
10150Sstevel@tonic-gate  */
10160Sstevel@tonic-gate char *
cpr_build_statefile_path(void)10170Sstevel@tonic-gate cpr_build_statefile_path(void)
10180Sstevel@tonic-gate {
10190Sstevel@tonic-gate 	struct cprconfig *cf = &cprconfig;
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	if (cpr_get_config())
10220Sstevel@tonic-gate 		return (NULL);
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	switch (cf->cf_type) {
10250Sstevel@tonic-gate 	case CFT_UFS:
10260Sstevel@tonic-gate 		if (strlen(cf->cf_path) + strlen(cf->cf_fs) >= MAXNAMELEN - 1) {
10270Sstevel@tonic-gate 			cpr_err(CE_CONT, "Statefile path is too long.\n");
10280Sstevel@tonic-gate 			return (NULL);
10290Sstevel@tonic-gate 		}
10300Sstevel@tonic-gate 		return (cpr_cprconfig_to_path());
10316423Sgw25295 	case CFT_ZVOL:
10326423Sgw25295 		/*FALLTHROUGH*/
10330Sstevel@tonic-gate 	case CFT_SPEC:
10340Sstevel@tonic-gate 		return (cf->cf_devfs);
10350Sstevel@tonic-gate 	default:
10360Sstevel@tonic-gate 		cpr_err(CE_PANIC, "invalid statefile type");
10370Sstevel@tonic-gate 		/*NOTREACHED*/
1038931Smathue 		return (NULL);
10390Sstevel@tonic-gate 	}
10400Sstevel@tonic-gate }
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate int
cpr_statefile_is_spec(void)10430Sstevel@tonic-gate cpr_statefile_is_spec(void)
10440Sstevel@tonic-gate {
10450Sstevel@tonic-gate 	if (cpr_get_config())
10460Sstevel@tonic-gate 		return (0);
10470Sstevel@tonic-gate 	return (cprconfig.cf_type == CFT_SPEC);
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate char *
cpr_get_statefile_prom_path(void)10510Sstevel@tonic-gate cpr_get_statefile_prom_path(void)
10520Sstevel@tonic-gate {
10530Sstevel@tonic-gate 	struct cprconfig *cf = &cprconfig;
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	ASSERT(cprconfig_loaded);
10560Sstevel@tonic-gate 	ASSERT(cf->cf_magic == CPR_CONFIG_MAGIC);
10576423Sgw25295 	ASSERT(cf->cf_type == CFT_SPEC || cf->cf_type == CFT_ZVOL);
10580Sstevel@tonic-gate 	return (cf->cf_dev_prom);
10590Sstevel@tonic-gate }
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate /*
10630Sstevel@tonic-gate  * XXX The following routines need to be in the vfs source code.
10640Sstevel@tonic-gate  */
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate int
cpr_is_ufs(struct vfs * vfsp)10670Sstevel@tonic-gate cpr_is_ufs(struct vfs *vfsp)
10680Sstevel@tonic-gate {
10690Sstevel@tonic-gate 	char *fsname;
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	fsname = vfssw[vfsp->vfs_fstype].vsw_name;
10720Sstevel@tonic-gate 	return (strcmp(fsname, "ufs") == 0);
10730Sstevel@tonic-gate }
10740Sstevel@tonic-gate 
10756423Sgw25295 int
cpr_is_zfs(struct vfs * vfsp)10766423Sgw25295 cpr_is_zfs(struct vfs *vfsp)
10776423Sgw25295 {
10786423Sgw25295 	char *fsname;
10796423Sgw25295 
10806423Sgw25295 	fsname = vfssw[vfsp->vfs_fstype].vsw_name;
10816423Sgw25295 	return (strcmp(fsname, "zfs") == 0);
10826423Sgw25295 }
10836423Sgw25295 
10840Sstevel@tonic-gate /*
10850Sstevel@tonic-gate  * This is a list of file systems that are allowed to be writeable when a
10860Sstevel@tonic-gate  * reusable statefile checkpoint is taken.  They must not have any state that
10870Sstevel@tonic-gate  * cannot be restored to consistency by simply rebooting using the checkpoint.
10880Sstevel@tonic-gate  * (In contrast to ufs, cachefs and pcfs which have disk state that could get
10890Sstevel@tonic-gate  * out of sync with the in-kernel data).
10900Sstevel@tonic-gate  */
10910Sstevel@tonic-gate int
cpr_reusable_mount_check(void)10920Sstevel@tonic-gate cpr_reusable_mount_check(void)
10930Sstevel@tonic-gate {
10940Sstevel@tonic-gate 	struct vfs *vfsp;
10950Sstevel@tonic-gate 	char *fsname;
10960Sstevel@tonic-gate 	char **cpp;
10970Sstevel@tonic-gate 	static char *cpr_writeok_fss[] = {
10980Sstevel@tonic-gate 		"autofs", "devfs", "fd", "lofs", "mntfs", "namefs", "nfs",
10992621Sllai1 		"proc", "tmpfs", "ctfs", "objfs", "dev", NULL
11000Sstevel@tonic-gate 	};
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 	vfs_list_read_lock();
11030Sstevel@tonic-gate 	vfsp = rootvfs;
11040Sstevel@tonic-gate 	do {
11050Sstevel@tonic-gate 		if (vfsp->vfs_flag & VFS_RDONLY) {
11060Sstevel@tonic-gate 			vfsp = vfsp->vfs_next;
11070Sstevel@tonic-gate 			continue;
11080Sstevel@tonic-gate 		}
11090Sstevel@tonic-gate 		fsname = vfssw[vfsp->vfs_fstype].vsw_name;
11100Sstevel@tonic-gate 		for (cpp = cpr_writeok_fss; *cpp; cpp++) {
11110Sstevel@tonic-gate 			if (strcmp(fsname, *cpp) == 0)
11120Sstevel@tonic-gate 				break;
11130Sstevel@tonic-gate 		}
11140Sstevel@tonic-gate 		/*
11150Sstevel@tonic-gate 		 * if the inner loop reached the NULL terminator,
11160Sstevel@tonic-gate 		 * the current fs-type does not match any OK-type
11170Sstevel@tonic-gate 		 */
11180Sstevel@tonic-gate 		if (*cpp == NULL) {
11190Sstevel@tonic-gate 			cpr_err(CE_CONT, "a filesystem of type %s is "
11200Sstevel@tonic-gate 			    "mounted read/write.\nReusable statefile requires "
11210Sstevel@tonic-gate 			    "no writeable filesystem of this type be mounted\n",
11220Sstevel@tonic-gate 			    fsname);
11230Sstevel@tonic-gate 			vfs_list_unlock();
11240Sstevel@tonic-gate 			return (EINVAL);
11250Sstevel@tonic-gate 		}
11260Sstevel@tonic-gate 		vfsp = vfsp->vfs_next;
11270Sstevel@tonic-gate 	} while (vfsp != rootvfs);
11280Sstevel@tonic-gate 	vfs_list_unlock();
11290Sstevel@tonic-gate 	return (0);
11300Sstevel@tonic-gate }
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate /*
11335295Srandyf  * return statefile offset in DEV_BSIZE units
11345295Srandyf  */
11355295Srandyf int
cpr_statefile_offset(void)11365295Srandyf cpr_statefile_offset(void)
11375295Srandyf {
11386423Sgw25295 	return (cprconfig.cf_type != CFT_UFS ? btod(CPR_SPEC_OFFSET) : 0);
11395295Srandyf }
11405295Srandyf 
11415295Srandyf /*
11420Sstevel@tonic-gate  * Force a fresh read of the cprinfo per uadmin 3 call
11430Sstevel@tonic-gate  */
11440Sstevel@tonic-gate void
cpr_forget_cprconfig(void)11450Sstevel@tonic-gate cpr_forget_cprconfig(void)
11460Sstevel@tonic-gate {
11470Sstevel@tonic-gate 	cprconfig_loaded = 0;
11480Sstevel@tonic-gate }
11495295Srandyf #endif
1150