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