[PATCH] swsusp: debugging

Add a swsusp debugging mode. This does everything that's needed for a suspend
except for actually suspending. So we can look in the log messages and work
out a) what code is being slow and b) which drivers are misbehaving.

(1)
# echo testproc > /sys/power/disk
# echo disk > /sys/power/state

This should turn off the non-boot CPU, freeze all processes, wait for 5
seconds and then thaw the processes and the CPU.

(2)
# echo test > /sys/power/disk
# echo disk > /sys/power/state

This should turn off the non-boot CPU, freeze all processes, shrink
memory, suspend all devices, wait for 5 seconds, resume the devices etc.

Cc: Pavel Machek <pavel@ucw.cz>
Cc: Stefan Seyfried <seife@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by Rafael J. Wysocki and committed by Linus Torvalds b918f6e6 90d53909

+60 -11
+16 -1
Documentation/ABI/testing/sysfs-power
··· 21 21 these states. 22 22 23 23 What: /sys/power/disk 24 - Date: August 2006 24 + Date: September 2006 25 25 Contact: Rafael J. Wysocki <rjw@sisk.pl> 26 26 Description: 27 27 The /sys/power/disk file controls the operating mode of the ··· 39 39 'reboot' - the memory image will be saved by the kernel and 40 40 the system will be rebooted. 41 41 42 + Additionally, /sys/power/disk can be used to turn on one of the 43 + two testing modes of the suspend-to-disk mechanism: 'testproc' 44 + or 'test'. If the suspend-to-disk mechanism is in the 45 + 'testproc' mode, writing 'disk' to /sys/power/state will cause 46 + the kernel to disable nonboot CPUs and freeze tasks, wait for 5 47 + seconds, unfreeze tasks and enable nonboot CPUs. If it is in 48 + the 'test' mode, writing 'disk' to /sys/power/state will cause 49 + the kernel to disable nonboot CPUs and freeze tasks, shrink 50 + memory, suspend devices, wait for 5 seconds, resume devices, 51 + unfreeze tasks and enable nonboot CPUs. Then, we are able to 52 + look in the log messages and work out, for example, which code 53 + is being slow and which device drivers are misbehaving. 54 + 42 55 The suspend-to-disk method may be chosen by writing to this 43 56 file one of the accepted strings: 44 57 ··· 59 46 'platform' 60 47 'shutdown' 61 48 'reboot' 49 + 'testproc' 50 + 'test' 62 51 63 52 It will only change to 'firmware' or 'platform' if the system 64 53 supports that.
+13
Documentation/power/interface.txt
··· 30 30 that is known a priori. But, the user may choose 'shutdown' or 31 31 'reboot' as alternatives. 32 32 33 + Additionally, /sys/power/disk can be used to turn on one of the two testing 34 + modes of the suspend-to-disk mechanism: 'testproc' or 'test'. If the 35 + suspend-to-disk mechanism is in the 'testproc' mode, writing 'disk' to 36 + /sys/power/state will cause the kernel to disable nonboot CPUs and freeze 37 + tasks, wait for 5 seconds, unfreeze tasks and enable nonboot CPUs. If it is 38 + in the 'test' mode, writing 'disk' to /sys/power/state will cause the kernel 39 + to disable nonboot CPUs and freeze tasks, shrink memory, suspend devices, wait 40 + for 5 seconds, resume devices, unfreeze tasks and enable nonboot CPUs. Then, 41 + we are able to look in the log messages and work out, for example, which code 42 + is being slow and which device drivers are misbehaving. 43 + 33 44 Reading from this file will display what the mode is currently set 34 45 to. Writing to this file will accept one of 35 46 ··· 48 37 'platform' 49 38 'shutdown' 50 39 'reboot' 40 + 'testproc' 41 + 'test' 51 42 52 43 It will only change to 'firmware' or 'platform' if the system supports 53 44 it.
+3 -1
include/linux/pm.h
··· 116 116 #define PM_DISK_PLATFORM ((__force suspend_disk_method_t) 2) 117 117 #define PM_DISK_SHUTDOWN ((__force suspend_disk_method_t) 3) 118 118 #define PM_DISK_REBOOT ((__force suspend_disk_method_t) 4) 119 - #define PM_DISK_MAX ((__force suspend_disk_method_t) 5) 119 + #define PM_DISK_TEST ((__force suspend_disk_method_t) 5) 120 + #define PM_DISK_TESTPROC ((__force suspend_disk_method_t) 6) 121 + #define PM_DISK_MAX ((__force suspend_disk_method_t) 7) 120 122 121 123 struct pm_ops { 122 124 suspend_disk_method_t pm_disk_mode;
+28 -9
kernel/power/disk.c
··· 71 71 72 72 static int prepare_processes(void) 73 73 { 74 - int error; 74 + int error = 0; 75 75 76 76 pm_prepare_console(); 77 77 ··· 81 81 82 82 if (freeze_processes()) { 83 83 error = -EBUSY; 84 + goto thaw; 85 + } 86 + 87 + if (pm_disk_mode == PM_DISK_TESTPROC) { 88 + printk("swsusp debug: Waiting for 5 seconds.\n"); 89 + mdelay(5000); 84 90 goto thaw; 85 91 } 86 92 ··· 126 120 if (error) 127 121 return error; 128 122 123 + if (pm_disk_mode == PM_DISK_TESTPROC) 124 + goto Thaw; 125 + 129 126 suspend_console(); 130 127 error = device_suspend(PMSG_FREEZE); 131 128 if (error) { 132 129 resume_console(); 133 130 printk("Some devices failed to suspend\n"); 134 - unprepare_processes(); 135 - return error; 131 + goto Thaw; 132 + } 133 + 134 + if (pm_disk_mode == PM_DISK_TEST) { 135 + printk("swsusp debug: Waiting for 5 seconds.\n"); 136 + mdelay(5000); 137 + goto Done; 136 138 } 137 139 138 140 pr_debug("PM: snapshotting memory.\n"); ··· 157 143 power_down(pm_disk_mode); 158 144 else { 159 145 swsusp_free(); 160 - unprepare_processes(); 161 - return error; 146 + goto Thaw; 162 147 } 163 - } else 148 + } else { 164 149 pr_debug("PM: Image restored successfully.\n"); 150 + } 165 151 166 152 swsusp_free(); 167 153 Done: 168 154 device_resume(); 169 155 resume_console(); 156 + Thaw: 170 157 unprepare_processes(); 171 158 return error; 172 159 } ··· 264 249 [PM_DISK_PLATFORM] = "platform", 265 250 [PM_DISK_SHUTDOWN] = "shutdown", 266 251 [PM_DISK_REBOOT] = "reboot", 252 + [PM_DISK_TEST] = "test", 253 + [PM_DISK_TESTPROC] = "testproc", 267 254 }; 268 255 269 256 /** ··· 320 303 } 321 304 } 322 305 if (mode) { 323 - if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT) 306 + if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT || 307 + mode == PM_DISK_TEST || mode == PM_DISK_TESTPROC) { 324 308 pm_disk_mode = mode; 325 - else { 309 + } else { 326 310 if (pm_ops && pm_ops->enter && 327 311 (mode == pm_ops->pm_disk_mode)) 328 312 pm_disk_mode = mode; 329 313 else 330 314 error = -EINVAL; 331 315 } 332 - } else 316 + } else { 333 317 error = -EINVAL; 318 + } 334 319 335 320 pr_debug("PM: suspend-to-disk mode set to '%s'\n", 336 321 pm_disk_modes[mode]);