1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * System call to checkpoint and resume the currently running kernel 31 */ 32 #include <sys/types.h> 33 #include <sys/errno.h> 34 #include <sys/modctl.h> 35 #include <sys/syscall.h> 36 #include <sys/cred.h> 37 #include <sys/uadmin.h> 38 #include <sys/cmn_err.h> 39 #include <sys/systm.h> 40 #include <sys/cpr.h> 41 #include <sys/swap.h> 42 #include <sys/vfs.h> 43 #include <sys/autoconf.h> 44 #include <sys/machsystm.h> 45 46 extern int i_cpr_is_supported(void); 47 extern int cpr_is_ufs(struct vfs *); 48 extern int cpr_check_spec_statefile(void); 49 extern int cpr_reusable_mount_check(void); 50 extern void cpr_forget_cprconfig(void); 51 extern int i_cpr_reusable_supported(void); 52 extern int i_cpr_reusefini(void); 53 54 extern struct mod_ops mod_miscops; 55 56 static struct modlmisc modlmisc = { 57 &mod_miscops, "checkpoint resume" 58 }; 59 60 static struct modlinkage modlinkage = { 61 MODREV_1, (void *)&modlmisc, NULL 62 }; 63 64 char _depends_on[] = "misc/bootdev"; /* i_devname_to_promname() */ 65 66 int cpr_reusable_mode; 67 68 kmutex_t cpr_slock; /* cpr serial lock */ 69 cpr_t cpr_state; 70 int cpr_debug; 71 int cpr_test_mode; /* true if called via uadmin testmode */ 72 73 /* 74 * All the loadable module related code follows 75 */ 76 int 77 _init(void) 78 { 79 register int e; 80 81 if ((e = mod_install(&modlinkage)) == 0) { 82 mutex_init(&cpr_slock, NULL, MUTEX_DEFAULT, NULL); 83 } 84 return (e); 85 } 86 87 int 88 _fini(void) 89 { 90 register int e; 91 92 if ((e = mod_remove(&modlinkage)) == 0) { 93 mutex_destroy(&cpr_slock); 94 } 95 return (e); 96 } 97 98 int 99 _info(struct modinfo *modinfop) 100 { 101 return (mod_info(&modlinkage, modinfop)); 102 } 103 104 int 105 cpr(int fcn) 106 { 107 static const char noswapstr[] = "reusable statefile requires " 108 "that no swap area be configured.\n"; 109 static const char blockstr[] = "reusable statefile must be " 110 "a block device. See power.conf(4) and pmconfig(1M).\n"; 111 static const char normalfmt[] = "cannot run normal " 112 "checkpoint/resume when in reusable statefile mode. " 113 "use uadmin A_FREEZE AD_REUSEFINI (uadmin %d %d) " 114 "to exit reusable statefile mode.\n"; 115 static const char modefmt[] = "%s in reusable mode.\n"; 116 register int rc = 0; 117 extern int cpr_init(int); 118 extern void cpr_done(void); 119 120 /* 121 * Need to know if we're in reusable mode, but we will likely have 122 * rebooted since REUSEINIT, so we have to get the info from the 123 * file system 124 */ 125 if (!cpr_reusable_mode) 126 cpr_reusable_mode = cpr_get_reusable_mode(); 127 128 cpr_forget_cprconfig(); 129 switch (fcn) { 130 131 case AD_CPR_REUSEINIT: 132 if (!i_cpr_reusable_supported()) 133 return (ENOTSUP); 134 if (!cpr_statefile_is_spec()) { 135 cpr_err(CE_CONT, blockstr); 136 return (EINVAL); 137 } 138 if ((rc = cpr_check_spec_statefile()) != 0) 139 return (rc); 140 if (swapinfo) { 141 cpr_err(CE_CONT, noswapstr); 142 return (EINVAL); 143 } 144 cpr_test_mode = 0; 145 break; 146 147 case AD_CPR_NOCOMPRESS: 148 case AD_CPR_COMPRESS: 149 case AD_CPR_FORCE: 150 if (cpr_reusable_mode) { 151 cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI); 152 return (ENOTSUP); 153 } 154 cpr_test_mode = 0; 155 break; 156 157 case AD_CPR_REUSABLE: 158 if (!i_cpr_reusable_supported()) 159 return (ENOTSUP); 160 if (!cpr_statefile_is_spec()) { 161 cpr_err(CE_CONT, blockstr); 162 return (EINVAL); 163 } 164 if ((rc = cpr_check_spec_statefile()) != 0) 165 return (rc); 166 if (swapinfo) { 167 cpr_err(CE_CONT, noswapstr); 168 return (EINVAL); 169 } 170 if ((rc = cpr_reusable_mount_check()) != 0) 171 return (rc); 172 cpr_test_mode = 0; 173 break; 174 175 case AD_CPR_REUSEFINI: 176 if (!i_cpr_reusable_supported()) 177 return (ENOTSUP); 178 cpr_test_mode = 0; 179 break; 180 181 case AD_CPR_TESTZ: 182 case AD_CPR_TESTNOZ: 183 case AD_CPR_TESTHALT: 184 if (cpr_reusable_mode) { 185 cpr_err(CE_CONT, normalfmt, A_FREEZE, AD_REUSEFINI); 186 return (ENOTSUP); 187 } 188 cpr_test_mode = 1; 189 break; 190 191 case AD_CPR_CHECK: 192 if (!i_cpr_is_supported() || cpr_reusable_mode) 193 return (ENOTSUP); 194 return (0); 195 196 case AD_CPR_PRINT: 197 CPR_STAT_EVENT_END("POST CPR DELAY"); 198 cpr_stat_event_print(); 199 return (0); 200 201 case AD_CPR_DEBUG0: 202 cpr_debug = 0; 203 return (0); 204 205 case AD_CPR_DEBUG1: 206 case AD_CPR_DEBUG2: 207 case AD_CPR_DEBUG3: 208 case AD_CPR_DEBUG4: 209 case AD_CPR_DEBUG5: 210 case AD_CPR_DEBUG7: 211 case AD_CPR_DEBUG8: 212 cpr_debug |= CPR_DEBUG_BIT(fcn); 213 return (0); 214 215 case AD_CPR_DEBUG9: 216 cpr_debug |= LEVEL6; 217 return (0); 218 219 default: 220 return (ENOTSUP); 221 } 222 223 if (!i_cpr_is_supported() || !cpr_is_ufs(rootvfs)) 224 return (ENOTSUP); 225 226 if (fcn == AD_CPR_REUSEINIT) { 227 if (mutex_tryenter(&cpr_slock) == 0) 228 return (EBUSY); 229 if (cpr_reusable_mode) { 230 cpr_err(CE_CONT, modefmt, "already"); 231 mutex_exit(&cpr_slock); 232 return (EBUSY); 233 } 234 rc = i_cpr_reuseinit(); 235 mutex_exit(&cpr_slock); 236 return (rc); 237 } 238 239 if (fcn == AD_CPR_REUSEFINI) { 240 if (mutex_tryenter(&cpr_slock) == 0) 241 return (EBUSY); 242 if (!cpr_reusable_mode) { 243 cpr_err(CE_CONT, modefmt, "not"); 244 mutex_exit(&cpr_slock); 245 return (EINVAL); 246 } 247 rc = i_cpr_reusefini(); 248 mutex_exit(&cpr_slock); 249 return (rc); 250 } 251 252 /* 253 * acquire cpr serial lock and init cpr state structure. 254 */ 255 if (rc = cpr_init(fcn)) 256 return (rc); 257 258 if (fcn == AD_CPR_REUSABLE) { 259 if ((rc = i_cpr_check_cprinfo()) != 0) { 260 mutex_exit(&cpr_slock); 261 return (rc); 262 } 263 } 264 265 /* 266 * Call the main cpr routine. If we are successful, we will be coming 267 * down from the resume side, otherwise we are still in suspend. 268 */ 269 cpr_err(CE_CONT, "System is being suspended"); 270 if (rc = cpr_main()) { 271 CPR->c_flags |= C_ERROR; 272 cpr_err(CE_NOTE, "Suspend operation failed."); 273 } else if (CPR->c_flags & C_SUSPENDING) { 274 extern void cpr_power_down(); 275 /* 276 * Back from a successful checkpoint 277 */ 278 if (fcn == AD_CPR_TESTZ || fcn == AD_CPR_TESTNOZ) { 279 mdboot(0, AD_BOOT, "", B_FALSE); 280 /* NOTREACHED */ 281 } 282 283 /* make sure there are no more changes to the device tree */ 284 devtree_freeze(); 285 286 /* 287 * stop other cpus and raise our priority. since there is only 288 * one active cpu after this, and our priority will be too high 289 * for us to be preempted, we're essentially single threaded 290 * from here on out. 291 */ 292 stop_other_cpus(); 293 (void) spl6(); 294 295 /* 296 * try and reset leaf devices. reset_leaves() should only 297 * be called when there are no other threads that could be 298 * accessing devices 299 */ 300 reset_leaves(); 301 302 /* 303 * If cpr_power_down() succeeds, it'll not return. 304 * 305 * Drives with write-cache enabled need to flush 306 * their cache. 307 */ 308 if (fcn != AD_CPR_TESTHALT) 309 cpr_power_down(); 310 311 errp("(Done. Please Switch Off)\n"); 312 halt(NULL); 313 /* NOTREACHED */ 314 } 315 /* 316 * For resuming: release resources and the serial lock. 317 */ 318 cpr_done(); 319 return (rc); 320 } 321