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