4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
25 * Copyright 2012 Milan Jurik. All rights reserved.
29 * System call to checkpoint and resume the currently running kernel
31 #include <sys/types.h>
32 #include <sys/errno.h>
33 #include <sys/modctl.h>
34 #include <sys/syscall.h>
36 #include <sys/uadmin.h>
37 #include <sys/cmn_err.h>
38 #include <sys/systm.h>
42 #include <sys/autoconf.h>
43 #include <sys/machsystm.h>
45 extern int i_cpr_is_supported(int sleeptype
);
46 extern int cpr_is_ufs(struct vfs
*);
47 extern int cpr_is_zfs(struct vfs
*);
48 extern int cpr_check_spec_statefile(void);
49 extern int cpr_reusable_mount_check(void);
50 extern int i_cpr_reusable_supported(void);
51 extern int i_cpr_reusefini(void);
52 extern struct mod_ops mod_miscops
;
54 extern int cpr_init(int);
55 extern void cpr_done(void);
56 extern void i_cpr_stop_other_cpus(void);
57 extern int i_cpr_power_down(int);
60 extern void cpr_forget_cprconfig(void);
63 static struct modlmisc modlmisc
= {
64 &mod_miscops
, "checkpoint resume"
67 static struct modlinkage modlinkage
= {
68 MODREV_1
, (void *)&modlmisc
, NULL
71 int cpr_reusable_mode
;
73 kmutex_t cpr_slock
; /* cpr serial lock */
76 int cpr_test_mode
; /* true if called via uadmin testmode */
77 int cpr_test_point
= LOOP_BACK_NONE
; /* cpr test point */
78 int cpr_mp_enable
= 0; /* set to 1 to enable MP suspend */
79 major_t cpr_device
= 0; /* major number for S3 on one device */
82 * All the loadable module related code follows
89 if ((e
= mod_install(&modlinkage
)) == 0) {
90 mutex_init(&cpr_slock
, NULL
, MUTEX_DEFAULT
, NULL
);
100 if ((e
= mod_remove(&modlinkage
)) == 0) {
101 mutex_destroy(&cpr_slock
);
107 _info(struct modinfo
*modinfop
)
109 return (mod_info(&modlinkage
, modinfop
));
121 i
= 10 * i
+ (*p
++ - '0');
127 cpr(int fcn
, void *mdep
)
131 static const char noswapstr
[] = "reusable statefile requires "
132 "that no swap area be configured.\n";
133 static const char blockstr
[] = "reusable statefile must be "
134 "a block device. See power.conf(4) and pmconfig(1M).\n";
135 static const char normalfmt
[] = "cannot run normal "
136 "checkpoint/resume when in reusable statefile mode. "
137 "use uadmin A_FREEZE AD_REUSEFINI (uadmin %d %d) "
138 "to exit reusable statefile mode.\n";
139 static const char modefmt
[] = "%s in reusable mode.\n";
145 * First, reject commands that we don't (yet) support on this arch.
146 * This is easier to understand broken out like this than grotting
147 * through the second switch below.
152 case AD_CHECK_SUSPEND_TO_RAM
:
153 case AD_SUSPEND_TO_RAM
:
155 case AD_CHECK_SUSPEND_TO_DISK
:
156 case AD_SUSPEND_TO_DISK
:
157 case AD_CPR_REUSEINIT
:
158 case AD_CPR_NOCOMPRESS
:
160 case AD_CPR_REUSABLE
:
161 case AD_CPR_REUSEFINI
:
164 case AD_CPR_TESTHALT
:
165 case AD_CPR_SUSP_DEVICES
:
166 cpr_sleeptype
= CPR_TODISK
;
170 case AD_CHECK_SUSPEND_TO_DISK
:
171 case AD_SUSPEND_TO_DISK
:
172 case AD_CPR_REUSEINIT
:
173 case AD_CPR_NOCOMPRESS
:
175 case AD_CPR_REUSABLE
:
176 case AD_CPR_REUSEFINI
:
179 case AD_CPR_TESTHALT
:
182 /* The DEV_* values need to be removed after sys-syspend is fixed */
183 case DEV_CHECK_SUSPEND_TO_RAM
:
184 case DEV_SUSPEND_TO_RAM
:
185 case AD_CPR_SUSP_DEVICES
:
186 case AD_CHECK_SUSPEND_TO_RAM
:
187 case AD_SUSPEND_TO_RAM
:
188 case AD_LOOPBACK_SUSPEND_TO_RAM_PASS
:
189 case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL
:
190 case AD_FORCE_SUSPEND_TO_RAM
:
191 case AD_DEVICE_SUSPEND_TO_RAM
:
192 cpr_sleeptype
= CPR_TORAM
;
198 * Need to know if we're in reusable mode, but we will likely have
199 * rebooted since REUSEINIT, so we have to get the info from the
202 if (!cpr_reusable_mode
)
203 cpr_reusable_mode
= cpr_get_reusable_mode();
205 cpr_forget_cprconfig();
211 case AD_CPR_REUSEINIT
:
212 if (!i_cpr_reusable_supported())
214 if (!cpr_statefile_is_spec()) {
215 cpr_err(CE_CONT
, blockstr
);
218 if ((rc
= cpr_check_spec_statefile()) != 0)
221 cpr_err(CE_CONT
, noswapstr
);
227 case AD_CPR_NOCOMPRESS
:
228 case AD_CPR_COMPRESS
:
230 if (cpr_reusable_mode
) {
231 cpr_err(CE_CONT
, normalfmt
, A_FREEZE
, AD_REUSEFINI
);
237 case AD_CPR_REUSABLE
:
238 if (!i_cpr_reusable_supported())
240 if (!cpr_statefile_is_spec()) {
241 cpr_err(CE_CONT
, blockstr
);
244 if ((rc
= cpr_check_spec_statefile()) != 0)
247 cpr_err(CE_CONT
, noswapstr
);
250 if ((rc
= cpr_reusable_mount_check()) != 0)
255 case AD_CPR_REUSEFINI
:
256 if (!i_cpr_reusable_supported())
263 case AD_CPR_TESTHALT
:
264 if (cpr_reusable_mode
) {
265 cpr_err(CE_CONT
, normalfmt
, A_FREEZE
, AD_REUSEFINI
);
272 if (!i_cpr_is_supported(cpr_sleeptype
) || cpr_reusable_mode
)
277 CPR_STAT_EVENT_END("POST CPR DELAY");
278 cpr_stat_event_print();
293 cpr_debug
|= CPR_DEBUG_BIT(fcn
);
297 cpr_debug
|= CPR_DEBUG6
;
300 /* The DEV_* values need to be removed after sys-syspend is fixed */
301 case DEV_CHECK_SUSPEND_TO_RAM
:
302 case DEV_SUSPEND_TO_RAM
:
303 case AD_CHECK_SUSPEND_TO_RAM
:
304 case AD_SUSPEND_TO_RAM
:
305 cpr_test_point
= LOOP_BACK_NONE
;
308 case AD_LOOPBACK_SUSPEND_TO_RAM_PASS
:
309 cpr_test_point
= LOOP_BACK_PASS
;
312 case AD_LOOPBACK_SUSPEND_TO_RAM_FAIL
:
313 cpr_test_point
= LOOP_BACK_FAIL
;
316 case AD_FORCE_SUSPEND_TO_RAM
:
317 cpr_test_point
= FORCE_SUSPEND_TO_RAM
;
320 case AD_DEVICE_SUSPEND_TO_RAM
:
322 /* Didn't pass enough arguments */
325 cpr_test_point
= DEVICE_SUSPEND_TO_RAM
;
326 cpr_device
= (major_t
)atoi((char *)mdep
);
329 case AD_CPR_SUSP_DEVICES
:
330 cpr_test_point
= FORCE_SUSPEND_TO_RAM
;
331 if (cpr_suspend_devices(ddi_root_node()) != DDI_SUCCESS
)
333 "Some devices did not suspend "
334 "and may be unusable");
335 (void) cpr_resume_devices(ddi_root_node(), 0);
342 if (!i_cpr_is_supported(cpr_sleeptype
))
346 if ((cpr_sleeptype
== CPR_TODISK
&&
347 !cpr_is_ufs(rootvfs
) && !cpr_is_zfs(rootvfs
)))
351 if (fcn
== AD_CHECK_SUSPEND_TO_RAM
||
352 fcn
== DEV_CHECK_SUSPEND_TO_RAM
) {
353 ASSERT(i_cpr_is_supported(cpr_sleeptype
));
358 if (fcn
== AD_CPR_REUSEINIT
) {
359 if (mutex_tryenter(&cpr_slock
) == 0)
361 if (cpr_reusable_mode
) {
362 cpr_err(CE_CONT
, modefmt
, "already");
363 mutex_exit(&cpr_slock
);
366 rc
= i_cpr_reuseinit();
367 mutex_exit(&cpr_slock
);
371 if (fcn
== AD_CPR_REUSEFINI
) {
372 if (mutex_tryenter(&cpr_slock
) == 0)
374 if (!cpr_reusable_mode
) {
375 cpr_err(CE_CONT
, modefmt
, "not");
376 mutex_exit(&cpr_slock
);
379 rc
= i_cpr_reusefini();
380 mutex_exit(&cpr_slock
);
386 * acquire cpr serial lock and init cpr state structure.
388 if (rc
= cpr_init(fcn
))
392 if (fcn
== AD_CPR_REUSABLE
) {
393 if ((rc
= i_cpr_check_cprinfo()) != 0) {
394 mutex_exit(&cpr_slock
);
401 * Call the main cpr routine. If we are successful, we will be coming
402 * down from the resume side, otherwise we are still in suspend.
404 cpr_err(CE_CONT
, "System is being suspended");
405 if (rc
= cpr_main(cpr_sleeptype
)) {
406 CPR
->c_flags
|= C_ERROR
;
407 PMD(PMD_SX
, ("cpr: Suspend operation failed.\n"))
408 cpr_err(CE_NOTE
, "Suspend operation failed.");
409 } else if (CPR
->c_flags
& C_SUSPENDING
) {
412 * In the suspend to RAM case, by the time we get
413 * control back we're already resumed
415 if (cpr_sleeptype
== CPR_TORAM
) {
416 PMD(PMD_SX
, ("cpr: cpr CPR_TORAM done\n"))
423 PMD(PMD_SX
, ("cpr: Suspend operation succeeded.\n"))
425 * Back from a successful checkpoint
427 if (fcn
== AD_CPR_TESTZ
|| fcn
== AD_CPR_TESTNOZ
) {
428 mdboot(0, AD_BOOT
, "", B_FALSE
);
432 /* make sure there are no more changes to the device tree */
433 PMD(PMD_SX
, ("cpr: dev tree freeze\n"))
437 * stop other cpus and raise our priority. since there is only
438 * one active cpu after this, and our priority will be too high
439 * for us to be preempted, we're essentially single threaded
442 PMD(PMD_SX
, ("cpr: stop other cpus\n"))
443 i_cpr_stop_other_cpus();
444 PMD(PMD_SX
, ("cpr: spl6\n"))
448 * try and reset leaf devices. reset_leaves() should only
449 * be called when there are no other threads that could be
452 PMD(PMD_SX
, ("cpr: reset leaves\n"))
456 * If i_cpr_power_down() succeeds, it'll not return
458 * Drives with write-cache enabled need to flush
461 if (fcn
!= AD_CPR_TESTHALT
) {
462 PMD(PMD_SX
, ("cpr: power down\n"))
463 (void) i_cpr_power_down(cpr_sleeptype
);
465 ASSERT(cpr_sleeptype
== CPR_TODISK
);
466 /* currently CPR_TODISK comes back via a boot path */
467 CPR_DEBUG(CPR_DEBUG1
, "(Done. Please Switch Off)\n");
472 PMD(PMD_SX
, ("cpr: cpr done\n"))