Skip to contentSkip to conversation

Suspend2 2.1.9.8 for 2.6.12

PATCH In review Nigel Cunningham 17 participants 187 messages Jul 6, 2005 – Jul 12, 2005 1 message not in the archive Page 1 of 2

Subsystems (48)
lore
Share & tools
lore
#0 lore raw

cover Suspend2 2.1.9.8 for 2.6.12

As requested, here are the patches that form Suspend2, for review.

I've tried to split it up into byte size chunks, but please don't expect that these will be patches that can mutate swsusp into Suspend2. That would roughly equivalent to asking for patches that patch Reiser3 into Reiser4 - it's a redesign.

There are a few extra patches not included here, all of which are not core to Suspend2. Since I'm not expecting this code to get merged as is, I haven't worried about including them. If that's a problem, let me know.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#1 lore raw

PATCH 1/48 Suspend2 2.1.9.8 for 2.6.12: submit_intro

kernel/sys.c +3 -3
diff -ruNp 300-reboot-handler-hook.patch-old/kernel/sys.c 300-reboot-handler-hook.patch-new/kernel/sys.c
@@ -436,12 +436,12 @@ asmlinkage long sys_reboot(int magic1, i
 		machine_restart(buffer);
 		break;
 
-#ifdef CONFIG_SOFTWARE_SUSPEND
+#ifdef CONFIG_SUSPEND2
 	case LINUX_REBOOT_CMD_SW_SUSPEND:
 		{
-			int ret = software_suspend();
+			suspend2_try_suspend();
 			unlock_kernel();
-			return ret;
+			return 0;
 		}
 #endif
 
#2 lore raw

Re: [PATCH] [1/48] Suspend2 2.1.9.8 for 2.6.12: submit_intro

Quoted 5 lines · Nigel Cunningham

diff -ruNp 300-reboot-handler-hook.patch-old/kernel/sys.c 300-reboot-handler-hook.patch-new/kernel/sys.c

kernel/sys.c 2005-07-04 23:14:18.000000000 +1000 renamed from kernel/sys.c 2005-06-20 11:47:32.000000000 +1000 +0 -0
@@ -436,12 +436,12 @@ asmlinkage long sys_reboot(int magic1, i
                machine_restart(buffer);

kernel/sys.c 2005-07-04 23:14:18.000000000 +1000 asmlinkage long sys_reboot(int magic1, i · line 444

Quoted 10 lines
kernel/sys.c 2005-07-04 23:14:18.000000000 +1000 renamed from kernel/sys.c 2005-06-20 11:47:32.000000000 +1000 +2 -3
                break;
 
-#ifdef CONFIG_SOFTWARE_SUSPEND
+#ifdef CONFIG_SUSPEND2
        case LINUX_REBOOT_CMD_SW_SUSPEND:
                {
-                       int ret = software_suspend();
+                       suspend2_try_suspend();
                        unlock_kernel();
-                       return ret;

Are both mechanisms intended to live in the kernel? If not, where's the patch to remove the old code?

#3 lore raw

Re: [PATCH] [1/48] Suspend2 2.1.9.8 for 2.6.12: submit_intro

In reply to Nigel Cunningham
Quoted 8 lines · Nigel Cunningham

diff -ruNp 300-reboot-handler-hook.patch-old/kernel/sys.c 300-reboot-handler-hook.patch-new/kernel/sys.c

kernel/sys.c +0 -1
@@ -436,12 +436,12 @@ asmlinkage long sys_reboot(int magic1, i
 		machine_restart(buffer);
 		break;
 
-#ifdef CONFIG_SOFTWARE_SUSPEND

kernel/sys.c asmlinkage long sys_reboot(int magic1, i · line 446

Quoted 10 lines
kernel/sys.c +3 -2
+#ifdef CONFIG_SUSPEND2
 	case LINUX_REBOOT_CMD_SW_SUSPEND:
 		{
-			int ret = software_suspend();
+			suspend2_try_suspend();
 			unlock_kernel();
-			return ret;
+			return 0;
 		}
 #endif

It would be nice to return meaningfull error code when something fails...

Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#4 lore raw

PATCH 2/48 Suspend2 2.1.9.8 for 2.6.12: 300-reboot-handler-hook.patch

In reply to Nigel Cunningham
drivers/acpi/sleep/proc.c +11 -0
diff -ruNp 301-proc-acpi-sleep-activate-hook.patch-old/drivers/acpi/sleep/proc.c 301-proc-acpi-sleep-activate-hook.patch-new/drivers/acpi/sleep/proc.c
@@ -68,6 +68,17 @@ acpi_system_write_sleep (
 		goto Done;
 	}
 	state = simple_strtoul(str, NULL, 0);
+#ifdef CONFIG_SUSPEND2
+	/* 
+	 * I used to put this after the CONFIG_SOFTWARE_SUSPEND
+	 * test, but people who compile in suspend2 usually want
+	 * to use it instead of swsusp.   --NC
+	 */
+	if (state == 4) {
+		suspend2_try_suspend();
+		goto Done;
+	}
+#endif
 #ifdef CONFIG_SOFTWARE_SUSPEND
 	if (state == 4) {
 		error = software_suspend();
#5 lore raw

Re: [PATCH] [2/48] Suspend2 2.1.9.8 for 2.6.12: 300-reboot-handler-hook.patch

Quoted 4 lines · Nigel Cunningham

diff -ruNp 301-proc-acpi-sleep-activate-hook.patch-old/drivers/acpi/sleep/proc.c 301-proc-acpi-sleep-activate-hook.patch-new/drivers/acpi/sleep/proc.c

drivers/acpi/sleep/proc.c 2005-07-04 23:14:18.000000000 +1000 acpi_system_write_sleep ( · line 77

Quoted 10 lines
drivers/acpi/sleep/proc.c 2005-07-04 23:14:18.000000000 +1000 renamed from drivers/acpi/sleep/proc.c 2005-06-20 11:46:50.000000000 +1000 +7 -0
@@ -68,6 +68,17 @@ acpi_system_write_sleep (
                goto Done;
        }
        state = simple_strtoul(str, NULL, 0);
+#ifdef CONFIG_SUSPEND2
+       /*
+        * I used to put this after the CONFIG_SOFTWARE_SUSPEND
+        * test, but people who compile in suspend2 usually want
+        * to use it instead of swsusp.   --NC
+        */
+       if (state == 4) {

enum for states instead of magics, please.

#6 lore raw

Re: [PATCH] [2/48] Suspend2 2.1.9.8 for 2.6.12: 300-reboot-handler-hook.patch

Hi.

Quoted 17 lines · Pekka Enberg
Quoted 4 lines · Nigel Cunningham

diff -ruNp 301-proc-acpi-sleep-activate-hook.patch-old/drivers/acpi/sleep/proc.c 301-proc-acpi-sleep-activate-hook.patch-new/drivers/acpi/sleep/proc.c

drivers/acpi/sleep/proc.c 2005-07-04 23:14:18.000000000 +1000 acpi_system_write_sleep ( · line 77

Quoted 10 lines
drivers/acpi/sleep/proc.c 2005-07-04 23:14:18.000000000 +1000 renamed from drivers/acpi/sleep/proc.c 2005-06-20 11:46:50.000000000 +1000 +7 -0
@@ -68,6 +68,17 @@ acpi_system_write_sleep (
                goto Done;
        }
        state = simple_strtoul(str, NULL, 0);
+#ifdef CONFIG_SUSPEND2
+       /*
+        * I used to put this after the CONFIG_SOFTWARE_SUSPEND
+        * test, but people who compile in suspend2 usually want
+        * to use it instead of swsusp.   --NC
+        */
+       if (state == 4) {

enum for states instead of magics, please.

Changed to ACPI_STATE_S4. Thanks!

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#7 lore raw

PATCH 3/48 Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch

In reply to Nigel Cunningham
init/do_mounts.c +25 -3
diff -ruNp 302-init-hooks.patch-old/init/do_mounts.c 302-init-hooks.patch-new/init/do_mounts.c
@@ -140,11 +140,16 @@ dev_t name_to_dev_t(char *name)
 	char s[32];
 	char *p;
 	dev_t res = 0;
-	int part;
+	int part, mount_result;
 
 #ifdef CONFIG_SYSFS
 	int mkdir_err = sys_mkdir("/sys", 0700);
-	if (sys_mount("sysfs", "/sys", "sysfs", 0, NULL) < 0)
+	/* 
+	 * When changing resume2 parameter for Software Suspend, sysfs may
+	 * already be mounted. 
+	 */
+	mount_result = sys_mount("sysfs", "/sys", "sysfs", 0, NULL);
+	if (mount_result < 0 && mount_result != -EBUSY)
 		goto out;
 #endif
 
@@ -196,7 +201,8 @@ dev_t name_to_dev_t(char *name)
 	res = try_name(s, part);
 done:
 #ifdef CONFIG_SYSFS
-	sys_umount("/sys", 0);
+	if (mount_result >= 0)
+		sys_umount("/sys", 0);
 out:
 	if (!mkdir_err)
 		sys_rmdir("/sys");
@@ -413,9 +419,25 @@ void __init prepare_namespace(void)
 
 	is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
 
+	/* Suspend2:
+	 * By this point, suspend_early_init has been called to initialise our
+	 * proc interface. If modules are built in, they have registered (all
+	 * of the above via late_initcalls).
+	 * 
+	 * We have not yet looked to see if an image exists, however. If we
+	 * have an initrd, it is expected that the user will have set it up
+	 * to echo > /proc/software_suspend/activate and thus initiate any
+	 * resume. If they don'tdo that, we do it immediately after the initrd
+	 * is finished (major issues if they mount filesystems rw from the
+	 * initrd! - they are warned. If there's no usable initrd, we do our
+	 * check next
+	 */
 	if (initrd_load())
 		goto out;
 
+	if (test_suspend_state(SUSPEND_RESUME_NOT_DONE))
+		suspend2_try_resume();
+	
 	if (is_floppy && rd_doload && rd_load_disk(0))
 		ROOT_DEV = Root_RAM0;
 
init/do_mounts_initrd.c +13 -1
diff -ruNp 302-init-hooks.patch-old/init/do_mounts_initrd.c 302-init-hooks.patch-new/init/do_mounts_initrd.c
@@ -7,6 +7,7 @@
 #include <linux/romfs_fs.h>
 #include <linux/initrd.h>
 #include <linux/sched.h>
+#include <linux/suspend.h>
 
 #include "do_mounts.h"
 
@@ -58,9 +59,20 @@ static void __init handle_initrd(void)
 
 	pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
 	if (pid > 0) {
-		while (pid != sys_wait4(-1, &i, 0, NULL))
+		while (pid != sys_wait4(-1, &i, 0, NULL)) {
 			yield();
+			try_to_freeze();
+		}
+	}
+
+	if (test_suspend_state(SUSPEND_RESUME_NOT_DONE)) {
+		if (resume2_file[0])
+			suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+				"Initrd not properly configured for resuming.");
+		else
+			printk("Suspend2: Initrd not properly configured for resuming and no resume2= specified.\n");
 	}
+	clear_suspend_state(SUSPEND_BOOT_TIME);
 
 	/* move initrd to rootfs' /old */
 	sys_fchdir(old_fd);
init/main.c +4 -1
diff -ruNp 302-init-hooks.patch-old/init/main.c 302-init-hooks.patch-new/init/main.c
@@ -47,6 +47,7 @@
 #include <linux/rmap.h>
 #include <linux/mempolicy.h>
 #include <linux/key.h>
+#include <linux/suspend.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -701,7 +702,9 @@ static int init(void * unused)
 
 	/*
 	 * check if there is an early userspace init.  If yes, let it do all
-	 * the work
+	 * the work. For suspend2, we assume that it will do the right thing
+	 * with regard to trying to resume at the right place. When that
+	 * happens, the BOOT_TIME flag will be cleared.
 	 */
 	if (sys_access((const char __user *) "/init", 0) == 0)
 		execute_command = "/init";
#8 lore raw

Re: [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch

Please add an explanation why this is nessecary. Big NACK for the patch as-is, but to find a proper solution we need to know what you're actually doing.

#9 lore raw

Re: [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch

Hi.

Quoted 2 lines · Christoph Hellwig

Please add an explanation why this is nessecary. Big NACK for the patch as-is, but to find a proper solution we need to know what you're actually doing.

When the user has an initrd or initramfs, they're supposed to include

echo > /proc/software_suspend/do_resume

at the point in their initrd where drivers needed for accessing the image, encryption keys and so on have been set up, but the root fs has not yet been mounted. If they don't do that, we should scream loudly, because mounting the root fs (even read only) will replay the journal, making the image not match what is on disk. This in turn can and probably will result in hard disk corruption if they echo to do_resume from say /etc/rc.d/rc.sysinit.

In addition, the try_to_freeze call is needed because, having loaded an image, we freeze kernel threads before doing the atomic restore.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 

A message that is not in the archive (sent off-list or not yet received): [email protected]

#11 lore raw

Re: [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch

Hi.

Quoted 8 lines · Matthew Garrett
Quoted 3 lines · Nigel Cunningham

When the user has an initrd or initramfs, they're supposed to include

echo > /proc/software_suspend/do_resume

This is a different interface to the one in swsusp, which is under /sys. Do we really need to keep multiple interfaces to the same functionality?

We already have that - the reboot handler, acpi S4 support and the sysfs interface. This should have been asked when sysfs was added :>. For the sake of backwards compatibility for current suspend2 users, it should stay for a while at least. The other thing here is that there is much more to /proc/software_suspend than do_resume.

Quoted 11 lines
Quoted 7 lines

at the point in their initrd where drivers needed for accessing the image, encryption keys and so on have been set up, but the root fs has not yet been mounted. If they don't do that, we should scream loudly, because mounting the root fs (even read only) will replay the journal, making the image not match what is on disk. This in turn can and probably will result in hard disk corruption if they echo to do_resume from say /etc/rc.d/rc.sysinit.

In general, the kernel does very little to prevent users from shooting themselves in the foot (or even chainsawing off their arms). We can do these checks in userspace rather than adding more kernel code.

Just because the kernel does very little, that doesn't mean it should. Particularly for something like suspend to disk, where it's not just a matter of an oops but of potential hard disk corruption, this is important.

If I could do it in userspace, I would. The trouble is, the userspace app may not be there to tell the user what is happening, and this might be part of the problem.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#12 lore raw

Re: [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch

Quoted 9 lines · Nigel Cunningham
Quoted 3 lines · Matthew Garrett

In general, the kernel does very little to prevent users from shooting themselves in the foot (or even chainsawing off their arms). We can do these checks in userspace rather than adding more kernel code.

Just because the kernel does very little, that doesn't mean it should. Particularly for something like suspend to disk, where it's not just a matter of an oops but of potential hard disk corruption, this is important.

The kernel isn't there to protect people. It's there to provide functionality.

Quoted 3 lines

If I could do it in userspace, I would. The trouble is, the userspace app may not be there to tell the user what is happening, and this might be part of the problem.

You're suggesting that users who are technically competent to compile their own kernel and write their own initrd scripts are unable to deal with checking whether or not a filesystem is mounted? You don't need an application to do that, it's a simple matter of shell scripting. And, in almost every case, if something is a simple matter of shell scripting it shouldn't be in the kernel.

Signature · 1 line
Matthew Garrett | [email protected]
#13 lore raw

Re: [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch

Hi.

Quoted 6 lines · Matthew Garrett
Quoted 5 lines · Nigel Cunningham
Quoted 3 lines · Matthew Garrett

In general, the kernel does very little to prevent users from shooting themselves in the foot (or even chainsawing off their arms). We can do these checks in userspace rather than adding more kernel code.

Quoted 7 lines
Quoted 4 lines

Just because the kernel does very little, that doesn't mean it should. Particularly for something like suspend to disk, where it's not just a matter of an oops but of potential hard disk corruption, this is important.

The kernel isn't there to protect people. It's there to provide functionality.

Both are true. If it only provided functionality, it wouldn't remount filesystems read only on journal errors or the like.

Quoted 10 lines
Quoted 3 lines

If I could do it in userspace, I would. The trouble is, the userspace app may not be there to tell the user what is happening, and this might be part of the problem.

You're suggesting that users who are technically competent to compile their own kernel and write their own initrd scripts are unable to deal with checking whether or not a filesystem is mounted? You don't need an application to do that, it's a simple matter of shell scripting. And, in almost every case, if something is a simple matter of shell scripting it shouldn't be in the kernel.

I'm suggesting that people make mistakes, and they don't always read the documentation or think of everything. These checks are there precisely because people have messed up in the past, and to cover the case where userspace isn't ready or able - for whatever reason - to do those checks or tell the user they've done something wrong.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#14 lore raw

PATCH 4/48 Suspend2 2.1.9.8 for 2.6.12: 302-init-hooks.patch

In reply to Nigel Cunningham
drivers/acpi/osl.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/acpi/osl.c 350-workthreads.patch-new/drivers/acpi/osl.c
@@ -95,7 +95,7 @@ acpi_os_initialize1(void)
 		return AE_NULL_ENTRY;
 	}
 #endif
-	kacpid_wq = create_singlethread_workqueue("kacpid");
+	kacpid_wq = create_singlethread_workqueue("kacpid", PF_NOFREEZE);
 	BUG_ON(!kacpid_wq);
 
 	return AE_OK;
drivers/block/ll_rw_blk.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/block/ll_rw_blk.c 350-workthreads.patch-new/drivers/block/ll_rw_blk.c
@@ -3266,7 +3266,7 @@ EXPORT_SYMBOL(kblockd_flush);
 
 int __init blk_dev_init(void)
 {
-	kblockd_workqueue = create_workqueue("kblockd");
+	kblockd_workqueue = create_workqueue("kblockd", PF_NOFREEZE);
 	if (!kblockd_workqueue)
 		panic("Failed to create kblockd\n");
 
drivers/block/pktcdvd.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/block/pktcdvd.c 350-workthreads.patch-new/drivers/block/pktcdvd.c
@@ -2373,7 +2373,7 @@ static int pkt_new_dev(struct pktcdvd_de
 	pkt_init_queue(pd);
 
 	atomic_set(&pd->cdrw.pending_bios, 0);
-	pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name);
+	pd->cdrw.thread = kthread_run(kcdrwd, pd, 0, "%s", pd->name);
 	if (IS_ERR(pd->cdrw.thread)) {
 		printk("pktcdvd: can't start kernel thread\n");
 		ret = -ENOMEM;
drivers/char/hvc_console.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/char/hvc_console.c 350-workthreads.patch-new/drivers/char/hvc_console.c
@@ -709,7 +709,7 @@ int __init hvc_init(void)
 
 	/* Always start the kthread because there can be hotplug vty adapters
 	 * added later. */
-	hvc_task = kthread_run(khvcd, NULL, "khvcd");
+	hvc_task = kthread_run(khvcd, NULL, PF_NOFREEZE, "khvcd");
 	if (IS_ERR(hvc_task)) {
 		panic("Couldn't create kthread for console.\n");
 		put_tty_driver(hvc_driver);
drivers/char/hvcs.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/char/hvcs.c 350-workthreads.patch-new/drivers/char/hvcs.c
@@ -1403,7 +1403,7 @@ static int __init hvcs_module_init(void)
 		return -ENOMEM;
 	}
 
-	hvcs_task = kthread_run(khvcsd, NULL, "khvcsd");
+	hvcs_task = kthread_run(khvcsd, NULL, PF_NOFREEZE, "khvcsd");
 	if (IS_ERR(hvcs_task)) {
 		printk(KERN_ERR "HVCS: khvcsd creation failed.  Driver not loaded.\n");
 		kfree(hvcs_pi_buff);
drivers/infiniband/core/fmr_pool.c +1 -0
diff -ruNp 350-workthreads.patch-old/drivers/infiniband/core/fmr_pool.c 350-workthreads.patch-new/drivers/infiniband/core/fmr_pool.c
@@ -266,6 +266,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(s
 
 	pool->thread = kthread_create(ib_fmr_cleanup_thread,
 				      pool,
+				      0,
 				      "ib_fmr(%s)",
 				      device->name);
 	if (IS_ERR(pool->thread)) {
drivers/infiniband/core/mad.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/infiniband/core/mad.c 350-workthreads.patch-new/drivers/infiniband/core/mad.c
@@ -2502,7 +2502,7 @@ static int ib_mad_port_open(struct ib_de
 		goto error7;
 
 	snprintf(name, sizeof name, "ib_mad%d", port_num);
-	port_priv->wq = create_singlethread_workqueue(name);
+	port_priv->wq = create_singlethread_workqueue(name, 0);
 	if (!port_priv->wq) {
 		ret = -ENOMEM;
 		goto error8;
drivers/infiniband/ulp/ipoib/ipoib_main.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/infiniband/ulp/ipoib/ipoib_main.c 350-workthreads.patch-new/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1070,7 +1070,7 @@ static int __init ipoib_init_module(void
 	 * so flush_scheduled_work() can deadlock during device
 	 * removal.
 	 */
-	ipoib_workqueue = create_singlethread_workqueue("ipoib");
+	ipoib_workqueue = create_singlethread_workqueue("ipoib", 0);
 	if (!ipoib_workqueue) {
 		ret = -ENOMEM;
 		goto err_fs;
drivers/macintosh/therm_adt746x.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/macintosh/therm_adt746x.c 350-workthreads.patch-new/drivers/macintosh/therm_adt746x.c
@@ -437,7 +437,7 @@ static int attach_one_thermostat(struct 
 		write_both_fan_speed(th, -1);
 	}
 	
-	thread_therm = kthread_run(monitor_task, th, "kfand");
+	thread_therm = kthread_run(monitor_task, th, 0, "kfand");
 
 	if (thread_therm == ERR_PTR(-ENOMEM)) {
 		printk(KERN_INFO "adt746x: Kthread creation failed\n");
drivers/md/dm-crypt.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/md/dm-crypt.c 350-workthreads.patch-new/drivers/md/dm-crypt.c
@@ -927,7 +927,7 @@ static int __init dm_crypt_init(void)
 	if (!_crypt_io_pool)
 		return -ENOMEM;
 
-	_kcryptd_workqueue = create_workqueue("kcryptd");
+	_kcryptd_workqueue = create_workqueue("kcryptd", PF_NOFREEZE);
 	if (!_kcryptd_workqueue) {
 		r = -ENOMEM;
 		DMERR(PFX "couldn't create kcryptd");
drivers/md/dm-mpath.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/md/dm-mpath.c 350-workthreads.patch-new/drivers/md/dm-mpath.c
@@ -1278,7 +1278,7 @@ static int __init dm_multipath_init(void
 		return -EINVAL;
 	}
 
-	kmultipathd = create_workqueue("kmpathd");
+	kmultipathd = create_workqueue("kmpathd", 0);
 	if (!kmultipathd) {
 		DMERR("%s: failed to create workqueue kmpathd",
 				multipath_target.name);
drivers/md/dm-raid1.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/md/dm-raid1.c 350-workthreads.patch-new/drivers/md/dm-raid1.c
@@ -1229,7 +1229,7 @@ static int __init dm_mirror_init(void)
 	if (r)
 		return r;
 
-	_kmirrord_wq = create_workqueue("kmirrord");
+	_kmirrord_wq = create_workqueue("kmirrord", PF_SYNCTHREAD);
 	if (!_kmirrord_wq) {
 		DMERR("couldn't start kmirrord");
 		dm_dirty_log_exit();
drivers/md/kcopyd.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/md/kcopyd.c 350-workthreads.patch-new/drivers/md/kcopyd.c
@@ -609,7 +609,7 @@ static int kcopyd_init(void)
 		return r;
 	}
 
-	_kcopyd_wq = create_singlethread_workqueue("kcopyd");
+	_kcopyd_wq = create_singlethread_workqueue("kcopyd", PF_SYNCTHREAD);
 	if (!_kcopyd_wq) {
 		jobs_exit();
 		up(&kcopyd_init_lock);
drivers/media/video/cx88/cx88-video.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/media/video/cx88/cx88-video.c 350-workthreads.patch-new/drivers/media/video/cx88/cx88-video.c
@@ -2121,7 +2121,7 @@ static int __devinit cx8800_initdev(stru
 
 	/* start tvaudio thread */
 	if (core->tuner_type != TUNER_ABSENT)
-		core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
+		core->kthread = kthread_run(cx88_audio_thread, core, 0, "cx88 tvaudio");
 	return 0;
 
 fail_unreg:
drivers/media/video/msp3400.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/media/video/msp3400.c 350-workthreads.patch-new/drivers/media/video/msp3400.c
@@ -1563,7 +1563,7 @@ static int msp_attach(struct i2c_adapter
 
 	/* startup control thread if needed */
 	if (thread_func) {
-		msp->kthread = kthread_run(thread_func, c, "msp34xx");
+		msp->kthread = kthread_run(thread_func, c, 0, "msp34xx");
 		if (NULL == msp->kthread)
 			printk(KERN_WARNING "msp34xx: kernel_thread() failed\n");
 		msp_wake_thread(c);
drivers/media/video/video-buf-dvb.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/media/video/video-buf-dvb.c 350-workthreads.patch-new/drivers/media/video/video-buf-dvb.c
@@ -103,7 +103,7 @@ static int videobuf_dvb_start_feed(struc
 	if (NULL != dvb->thread)
 		goto out;
 	dvb->thread = kthread_run(videobuf_dvb_thread,
-				  dvb, "%s dvb", dvb->name);
+				  dvb, 0, "%s dvb", dvb->name);
 	if (IS_ERR(dvb->thread)) {
 		rc = PTR_ERR(dvb->thread);
 		dvb->thread = NULL;
drivers/message/i2o/driver.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/message/i2o/driver.c 350-workthreads.patch-new/drivers/message/i2o/driver.c
@@ -79,7 +79,7 @@ int i2o_driver_register(struct i2o_drive
 	pr_debug("i2o: Register driver %s\n", drv->name);
 
 	if (drv->event) {
-		drv->event_queue = create_workqueue(drv->name);
+		drv->event_queue = create_workqueue(drv->name, 0);
 		if (!drv->event_queue) {
 			printk(KERN_ERR "i2o: Could not initialize event queue "
 			       "for driver %s\n", drv->name);
drivers/net/wan/sdlamain.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/net/wan/sdlamain.c 350-workthreads.patch-new/drivers/net/wan/sdlamain.c
@@ -240,7 +240,7 @@ static int __init wanpipe_init(void)
 	printk(KERN_INFO "%s v%u.%u %s\n",
 		fullname, DRV_VERSION, DRV_RELEASE, copyright);
 
-	wanpipe_wq = create_workqueue("wanpipe_wq");
+	wanpipe_wq = create_workqueue("wanpipe_wq", 0);
 	if (!wanpipe_wq)
 		return -ENOMEM;
 
drivers/s390/cio/device.c +4 -3
diff -ruNp 350-workthreads.patch-old/drivers/s390/cio/device.c 350-workthreads.patch-new/drivers/s390/cio/device.c
@@ -148,15 +148,16 @@ init_ccw_bus_type (void)
 	init_waitqueue_head(&ccw_device_init_wq);
 	atomic_set(&ccw_device_init_count, 0);
 
-	ccw_device_work = create_singlethread_workqueue("cio");
+	ccw_device_work = create_singlethread_workqueue("cio", 0);
 	if (!ccw_device_work)
 		return -ENOMEM; /* FIXME: better errno ? */
-	ccw_device_notify_work = create_singlethread_workqueue("cio_notify");
+	ccw_device_notify_work = create_singlethread_workqueue("cio_notify",
+			0);
 	if (!ccw_device_notify_work) {
 		ret = -ENOMEM; /* FIXME: better errno ? */
 		goto out_err;
 	}
-	slow_path_wq = create_singlethread_workqueue("kslowcrw");
+	slow_path_wq = create_singlethread_workqueue("kslowcrw", 0);
 	if (!slow_path_wq) {
 		ret = -ENOMEM; /* FIXME: better errno ? */
 		goto out_err;
drivers/scsi/hosts.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/scsi/hosts.c 350-workthreads.patch-new/drivers/scsi/hosts.c
@@ -133,7 +133,7 @@ int scsi_add_host(struct Scsi_Host *shos
 		snprintf(shost->work_q_name, KOBJ_NAME_LEN, "scsi_wq_%d",
 			shost->host_no);
 		shost->work_q = create_singlethread_workqueue(
-					shost->work_q_name);
+					shost->work_q_name, PF_NOFREEZE);
 		if (!shost->work_q)
 			goto out_free_shost_data;
 	}
drivers/scsi/libata-core.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/scsi/libata-core.c 350-workthreads.patch-new/drivers/scsi/libata-core.c
@@ -4342,7 +4342,7 @@ int pci_test_config_bits(struct pci_dev 
 
 static int __init ata_init(void)
 {
-	ata_wq = create_workqueue("ata");
+	ata_wq = create_workqueue("ata", 0);
 	if (!ata_wq)
 		return -ENOMEM;
 
drivers/usb/net/pegasus.c +1 -1
diff -ruNp 350-workthreads.patch-old/drivers/usb/net/pegasus.c 350-workthreads.patch-new/drivers/usb/net/pegasus.c
@@ -1412,7 +1412,7 @@ static struct usb_driver pegasus_driver 
 static int __init pegasus_init(void)
 {
 	pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION);
-	pegasus_workqueue = create_singlethread_workqueue("pegasus");
+	pegasus_workqueue = create_singlethread_workqueue("pegasus", PF_NOFREEZE);
 	if (!pegasus_workqueue)
 		return -ENOMEM;
 	return usb_register(&pegasus_driver);
fs/aio.c +1 -1
diff -ruNp 350-workthreads.patch-old/fs/aio.c 350-workthreads.patch-new/fs/aio.c
@@ -70,7 +70,7 @@ static int __init aio_setup(void)
 	kioctx_cachep = kmem_cache_create("kioctx", sizeof(struct kioctx),
 				0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
 
-	aio_wq = create_workqueue("aio");
+	aio_wq = create_workqueue("aio", 0);
 
 	pr_debug("aio_setup: sizeof(struct page) = %d\n", (int)sizeof(struct page));
 
fs/nfsd/nfs4state.c +1 -1
diff -ruNp 350-workthreads.patch-old/fs/nfsd/nfs4state.c 350-workthreads.patch-new/fs/nfsd/nfs4state.c
@@ -1356,7 +1356,7 @@ void nfsd_break_deleg_cb(struct file_loc
 	/* XXX need to merge NFSD_LEASE_TIME with fs/locks.c:lease_break_time */
 	fl->fl_break_time = jiffies + NFSD_LEASE_TIME * HZ;
 
-	t = kthread_run(do_recall, dp, "%s", "nfs4_cb_recall");
+	t = kthread_run(do_recall, dp, 0, "%s", "nfs4_cb_recall");
 	if (IS_ERR(t)) {
 		struct nfs4_client *clp = dp->dl_client;
 
fs/reiserfs/journal.c +1 -1
diff -ruNp 350-workthreads.patch-old/fs/reiserfs/journal.c 350-workthreads.patch-new/fs/reiserfs/journal.c
@@ -2510,7 +2510,7 @@ int journal_init(struct super_block *p_s
 
   reiserfs_mounted_fs_count++ ;
   if (reiserfs_mounted_fs_count <= 1)
-    commit_wq = create_workqueue("reiserfs");
+    commit_wq = create_workqueue("reiserfs", PF_SYNCTHREAD);
 
   INIT_WORK(&journal->j_work, flush_async_commits, p_s_sb);
   return 0 ;
fs/xfs/linux-2.6/xfs_buf.c +2 -2
diff -ruNp 350-workthreads.patch-old/fs/xfs/linux-2.6/xfs_buf.c 350-workthreads.patch-new/fs/xfs/linux-2.6/xfs_buf.c
@@ -1902,11 +1902,11 @@ pagebuf_daemon_start(void)
 {
 	int		rval;
 
-	pagebuf_logio_workqueue = create_workqueue("xfslogd");
+	pagebuf_logio_workqueue = create_workqueue("xfslogd", PF_SYNCTHREAD);
 	if (!pagebuf_logio_workqueue)
 		return -ENOMEM;
 
-	pagebuf_dataio_workqueue = create_workqueue("xfsdatad");
+	pagebuf_dataio_workqueue = create_workqueue("xfsdatad", PF_SYNCTHREAD);
 	if (!pagebuf_dataio_workqueue) {
 		destroy_workqueue(pagebuf_logio_workqueue);
 		return -ENOMEM;
include/linux/kthread.h +8 -2
diff -ruNp 350-workthreads.patch-old/include/linux/kthread.h 350-workthreads.patch-new/include/linux/kthread.h
@@ -25,20 +25,26 @@
  */
 struct task_struct *kthread_create(int (*threadfn)(void *data),
 				   void *data,
+				   unsigned long freezer_flags,
 				   const char namefmt[], ...);
 
 /**
  * kthread_run: create and wake a thread.
  * @threadfn: the function to run until signal_pending(current).
  * @data: data ptr for @threadfn.
+ * @freezer_flags: process flags that should be used for freezing.
+ * 	PF_SYNCTHREAD if needed for syncing data to disk.
+ * 	PF_NOFREEZE if also needed for writing the image.
+ * 	0 otherwise.
  * @namefmt: printf-style name for the thread.
  *
  * Description: Convenient wrapper for kthread_create() followed by
  * wake_up_process().  Returns the kthread, or ERR_PTR(-ENOMEM). */
-#define kthread_run(threadfn, data, namefmt, ...)			   \
+#define kthread_run(threadfn, data, freezer_flags, namefmt, ...)	   \
 ({									   \
 	struct task_struct *__k						   \
-		= kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
+		= kthread_create(threadfn, data, freezer_flags, 	   \
+			namefmt, ## __VA_ARGS__);			   \
 	if (!IS_ERR(__k))						   \
 		wake_up_process(__k);					   \
 	__k;								   \
include/linux/workqueue.h +4 -3
diff -ruNp 350-workthreads.patch-old/include/linux/workqueue.h 350-workthreads.patch-new/include/linux/workqueue.h
@@ -51,9 +51,10 @@ struct work_struct {
 	} while (0)
 
 extern struct workqueue_struct *__create_workqueue(const char *name,
-						    int singlethread);
-#define create_workqueue(name) __create_workqueue((name), 0)
-#define create_singlethread_workqueue(name) __create_workqueue((name), 1)
+						    int singlethread,
+						    unsigned long freezer_flag);
+#define create_workqueue(name, flags) __create_workqueue((name), 0, flags)
+#define create_singlethread_workqueue(name, flags) __create_workqueue((name), 1, flags)
 
 extern void destroy_workqueue(struct workqueue_struct *wq);
 
kernel/kmod.c +5 -1
diff -ruNp 350-workthreads.patch-old/kernel/kmod.c 350-workthreads.patch-new/kernel/kmod.c
@@ -36,6 +36,7 @@
 #include <linux/mount.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/suspend.h>
 #include <asm/uaccess.h>
 
 extern int max_threads;
@@ -240,6 +241,9 @@ int call_usermodehelper(char *path, char
 	if (!khelper_wq)
 		return -EBUSY;
 
+	if (test_suspend_state(SUSPEND_FREEZER_ON))
+		return -EBUSY;
+
 	if (path[0] == '\0')
 		return 0;
 
@@ -251,6 +255,6 @@ EXPORT_SYMBOL(call_usermodehelper);
 
 void __init usermodehelper_init(void)
 {
-	khelper_wq = create_singlethread_workqueue("khelper");
+	khelper_wq = create_singlethread_workqueue("khelper", 0);
 	BUG_ON(!khelper_wq);
 }
kernel/kthread.c +8 -1
diff -ruNp 350-workthreads.patch-old/kernel/kthread.c 350-workthreads.patch-new/kernel/kthread.c
@@ -25,6 +25,7 @@ struct kthread_create_info
 	/* Information passed to kthread() from keventd. */
 	int (*threadfn)(void *data);
 	void *data;
+	unsigned long freezer_flags;
 	struct completion started;
 
 	/* Result passed back to kthread_create() from keventd. */
@@ -93,6 +94,10 @@ static int kthread(void *_create)
 	current->flags |= flags_used;
 	atomic_set(&(current->freeze_status), 0);
 
+	/* Set our freezer flags */
+	current->flags &= ~(PF_SYNCTHREAD | PF_NOFREEZE);
+	current->flags |= create->freezer_flags;
+
 	/* OK, tell user we're spawned, wait for stop or wakeup */
 	__set_current_state(TASK_INTERRUPTIBLE);
 	complete(&create->started);
@@ -128,6 +133,7 @@ static void keventd_create_kthread(void 
 
 struct task_struct *kthread_create(int (*threadfn)(void *data),
 				   void *data,
+				   unsigned long freezer_flags,
 				   const char namefmt[],
 				   ...)
 {
@@ -136,6 +142,7 @@ struct task_struct *kthread_create(int (
 
 	create.threadfn = threadfn;
 	create.data = data;
+	create.freezer_flags = freezer_flags;
 	init_completion(&create.started);
 	init_completion(&create.done);
 
@@ -200,7 +207,7 @@ EXPORT_SYMBOL(kthread_stop);
 
 static __init int helper_init(void)
 {
-	helper_wq = create_singlethread_workqueue("kthread");
+	helper_wq = create_singlethread_workqueue("kthread", 0);
 	BUG_ON(!helper_wq);
 
 	return 0;
kernel/sched.c +2 -2
diff -ruNp 350-workthreads.patch-old/kernel/sched.c 350-workthreads.patch-new/kernel/sched.c
@@ -4420,10 +4420,10 @@ static int migration_call(struct notifie
 
 	switch (action) {
 	case CPU_UP_PREPARE:
-		p = kthread_create(migration_thread, hcpu, "migration/%d",cpu);
+		p = kthread_create(migration_thread, hcpu, 0,
+				"migration/%d",cpu);
 		if (IS_ERR(p))
 			return NOTIFY_BAD;
-		p->flags |= PF_NOFREEZE;
 		kthread_bind(p, cpu);
 		/* Must be high prio: stop_machine expects to yield to it. */
 		rq = task_rq_lock(p, &flags);
kernel/softirq.c +1 -2
diff -ruNp 350-workthreads.patch-old/kernel/softirq.c 350-workthreads.patch-new/kernel/softirq.c
@@ -350,7 +350,6 @@ void __init softirq_init(void)
 static int ksoftirqd(void * __bind_cpu)
 {
 	set_user_nice(current, 19);
-	current->flags |= PF_NOFREEZE;
 
 	set_current_state(TASK_INTERRUPTIBLE);
 
@@ -456,7 +455,7 @@ static int __devinit cpu_callback(struct
 	case CPU_UP_PREPARE:
 		BUG_ON(per_cpu(tasklet_vec, hotcpu).list);
 		BUG_ON(per_cpu(tasklet_hi_vec, hotcpu).list);
-		p = kthread_create(ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu);
+		p = kthread_create(ksoftirqd, hcpu, PF_NOFREEZE, "ksoftirqd/%d", hotcpu);
 		if (IS_ERR(p)) {
 			printk("ksoftirqd for %i failed\n", hotcpu);
 			return NOTIFY_BAD;
kernel/stop_machine.c +1 -1
diff -ruNp 350-workthreads.patch-old/kernel/stop_machine.c 350-workthreads.patch-new/kernel/stop_machine.c
@@ -184,7 +184,7 @@ struct task_struct *__stop_machine_run(i
 	if (cpu == NR_CPUS)
 		cpu = _smp_processor_id();
 
-	p = kthread_create(do_stop, &smdata, "kstopmachine");
+	p = kthread_create(do_stop, &smdata, 0, "kstopmachine");
 	if (!IS_ERR(p)) {
 		kthread_bind(p, cpu);
 		wake_up_process(p);
kernel/workqueue.c +12 -9
diff -ruNp 350-workthreads.patch-old/kernel/workqueue.c 350-workthreads.patch-new/kernel/workqueue.c
@@ -186,8 +186,6 @@ static int worker_thread(void *__cwq)
 	struct k_sigaction sa;
 	sigset_t blocked;
 
-	current->flags |= PF_NOFREEZE;
-
 	set_user_nice(current, -5);
 
 	/* Block and flush all signals */
@@ -208,6 +206,7 @@ static int worker_thread(void *__cwq)
 			schedule();
 		else
 			__set_current_state(TASK_RUNNING);
+		try_to_freeze();
 		remove_wait_queue(&cwq->more_work, &wait);
 
 		if (!list_empty(&cwq->worklist))
@@ -277,7 +276,8 @@ void fastcall flush_workqueue(struct wor
 }
 
 static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq,
-						   int cpu)
+						   int cpu,
+						   unsigned long freezer_flags)
 {
 	struct cpu_workqueue_struct *cwq = wq->cpu_wq + cpu;
 	struct task_struct *p;
@@ -292,9 +292,11 @@ static struct task_struct *create_workqu
 	init_waitqueue_head(&cwq->work_done);
 
 	if (is_single_threaded(wq))
-		p = kthread_create(worker_thread, cwq, "%s", wq->name);
+		p = kthread_create(worker_thread, cwq, freezer_flags, 
+				"%s", wq->name);
 	else
-		p = kthread_create(worker_thread, cwq, "%s/%d", wq->name, cpu);
+		p = kthread_create(worker_thread, cwq, freezer_flags,
+				"%s/%d", wq->name, cpu);
 	if (IS_ERR(p))
 		return NULL;
 	cwq->thread = p;
@@ -302,7 +304,8 @@ static struct task_struct *create_workqu
 }
 
 struct workqueue_struct *__create_workqueue(const char *name,
-					    int singlethread)
+					    int singlethread,
+					    unsigned long freezer_flags)
 {
 	int cpu, destroy = 0;
 	struct workqueue_struct *wq;
@@ -320,7 +323,7 @@ struct workqueue_struct *__create_workqu
 	lock_cpu_hotplug();
 	if (singlethread) {
 		INIT_LIST_HEAD(&wq->list);
-		p = create_workqueue_thread(wq, 0);
+		p = create_workqueue_thread(wq, 0, freezer_flags);
 		if (!p)
 			destroy = 1;
 		else
@@ -330,7 +333,7 @@ struct workqueue_struct *__create_workqu
 		list_add(&wq->list, &workqueues);
 		spin_unlock(&workqueue_lock);
 		for_each_online_cpu(cpu) {
-			p = create_workqueue_thread(wq, cpu);
+			p = create_workqueue_thread(wq, cpu, freezer_flags);
 			if (p) {
 				kthread_bind(p, cpu);
 				wake_up_process(p);
@@ -540,7 +543,7 @@ static int __devinit workqueue_cpu_callb
 void init_workqueues(void)
 {
 	hotcpu_notifier(workqueue_cpu_callback, 0);
-	keventd_wq = create_workqueue("events");
+	keventd_wq = create_workqueue("events", PF_NOFREEZE);
 	BUG_ON(!keventd_wq);
 }
 
mm/pdflush.c +1 -1
diff -ruNp 350-workthreads.patch-old/mm/pdflush.c 350-workthreads.patch-new/mm/pdflush.c
@@ -213,7 +213,7 @@ int pdflush_operation(void (*fn)(unsigne
 
 static void start_one_pdflush_thread(void)
 {
-	kthread_run(pdflush, NULL, "pdflush");
+	kthread_run(pdflush, NULL, PF_SYNCTHREAD, "pdflush");
 }
 
 static int __init pdflush_init(void)
net/sunrpc/sched.c +1 -1
diff -ruNp 350-workthreads.patch-old/net/sunrpc/sched.c 350-workthreads.patch-new/net/sunrpc/sched.c
@@ -1007,7 +1007,7 @@ rpciod_up(void)
 	 * Create the rpciod thread and wait for it to start.
 	 */
 	error = -ENOMEM;
-	wq = create_workqueue("rpciod");
+	wq = create_workqueue("rpciod", PF_SYNCTHREAD);
 	if (wq == NULL) {
 		printk(KERN_WARNING "rpciod_up: create workqueue failed, error=%d\n", error);
 		rpciod_users--;
sound/i2c/other/ak4114.c +1 -1
diff -ruNp 350-workthreads.patch-old/sound/i2c/other/ak4114.c 350-workthreads.patch-new/sound/i2c/other/ak4114.c
@@ -106,7 +106,7 @@ int snd_ak4114_create(snd_card_t *card,
 	for (reg = 0; reg < 5; reg++)
 		chip->txcsb[reg] = txcsb[reg];
 
-	chip->workqueue = create_workqueue("snd-ak4114");
+	chip->workqueue = create_workqueue("snd-ak4114", 0);
 	if (chip->workqueue == NULL) {
 		kfree(chip);
 		return -ENOMEM;
sound/pci/hda/hda_codec.c +1 -1
diff -ruNp 350-workthreads.patch-old/sound/pci/hda/hda_codec.c 350-workthreads.patch-new/sound/pci/hda/hda_codec.c
@@ -291,7 +291,7 @@ static int init_unsol_queue(struct hda_b
 		snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n");
 		return -ENOMEM;
 	}
-	unsol->workq = create_workqueue("hda_codec");
+	unsol->workq = create_workqueue("hda_codec", 0);
 	if (! unsol->workq) {
 		snd_printk(KERN_ERR "hda_codec: can't create workqueue\n");
 		kfree(unsol);
#15 lore raw

Re: [PATCH] [4/48] Suspend2 2.1.9.8 for 2.6.12: 302-init-hooks.patch

drivers/acpi/osl.c acpi_os_initialize1(void) · line 99

Quoted 10 lines · Nigel Cunningham

diff -ruNp 350-workthreads.patch-old/drivers/acpi/osl.c 350-workthreads.patch-new/drivers/acpi/osl.c

drivers/acpi/osl.c +1 -1
@@ -95,7 +95,7 @@ acpi_os_initialize1(void)
 		return AE_NULL_ENTRY;
 	}
 #endif
-	kacpid_wq = create_singlethread_workqueue("kacpid");
+	kacpid_wq = create_singlethread_workqueue("kacpid", PF_NOFREEZE);
 	BUG_ON(!kacpid_wq);

I'm not sure but kacpid can run any kind of code (depends on BIOS, it might touch some devices), is this safe?

Thanks,
Shaohua

#16 lore raw

Re: [PATCH] [4/48] Suspend2 2.1.9.8 for 2.6.12: 302-init-hooks.patch

Hi.

Quoted 13 lines · Shaohua Li

drivers/acpi/osl.c acpi_os_initialize1(void) · line 99

Quoted 10 lines · Nigel Cunningham

diff -ruNp 350-workthreads.patch-old/drivers/acpi/osl.c 350-workthreads.patch-new/drivers/acpi/osl.c

drivers/acpi/osl.c +1 -1
@@ -95,7 +95,7 @@ acpi_os_initialize1(void)
 		return AE_NULL_ENTRY;
 	}
 #endif
-	kacpid_wq = create_singlethread_workqueue("kacpid");
+	kacpid_wq = create_singlethread_workqueue("kacpid", PF_NOFREEZE);
 	BUG_ON(!kacpid_wq);

I'm not sure but kacpid can run any kind of code (depends on BIOS, it might touch some devices), is this safe?

If it's not, then we definitely want this patch as all workqueues are NOFREEZE at the moment.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#17 lore raw

Re: [PATCH] [4/48] Suspend2 2.1.9.8 for 2.6.12: 302-init-hooks.patch

In reply to Shaohua Li
Quoted 14 lines · Shaohua Li

drivers/acpi/osl.c acpi_os_initialize1(void) · line 99

Quoted 10 lines · Nigel Cunningham

diff -ruNp 350-workthreads.patch-old/drivers/acpi/osl.c 350-workthreads.patch-new/drivers/acpi/osl.c

drivers/acpi/osl.c +1 -1
@@ -95,7 +95,7 @@ acpi_os_initialize1(void)
 		return AE_NULL_ENTRY;
 	}
 #endif
-	kacpid_wq = create_singlethread_workqueue("kacpid");
+	kacpid_wq = create_singlethread_workqueue("kacpid", PF_NOFREEZE);
 	BUG_ON(!kacpid_wq);

I'm not sure but kacpid can run any kind of code (depends on BIOS, it might touch some devices), is this safe?

FYI, the reason it's there is to do something about acpi events whilst resuming. If kacpid is not running the following bug occurs:

- during suspend, prior to the atomic copy, a GPE fires (eg, a battery notification)
- the GPE is disabled until it is serviced by kacpid, but as kacpid is not running, it isn't serviced - only disabled.
- the disabled state of the GPE is recorded in the atomic copy, and written to disk
- poweroff/S4
- on resume, ACPI initialises the GPEs and enables them all.
- after the restoring the atomic copy, the GPE may fire. However, the kernel thinks it is already disabled and so refuses to disable it again.
- this sends the machine into an interrupt-induced death as the GPE fires over and over and over ...

I prepared a patch a while ago that simply omitted the check and disabled the GPE unconditionally (which was how things were before the big ACPI merge of 2.6.9), but this made the battery status unreadable for at least one user. I never followed that up, but instead some more general GPE suspend/resume handling was discussed, making GPEs system devices that were suspended and resumed accordingly. I don't think any code eventuated from this discussion though ...

Letting kacpid run during suspend appeared to be a good compromise (but still racy if GPEs were to occur at exactly the right instant
- just before the atomic copy). Implementing suspend/resume support for GPEs would be the more ideal solution.

Bernard.

Signature · 1 line
 Bernard Blackham <bernard at blackham dot com dot au>
#18 lore raw

PATCH 5/48 Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch

In reply to Nigel Cunningham
fs/buffer.c +48 -2
diff -ruNp 351-syncthreads.patch-old/fs/buffer.c 351-syncthreads.patch-new/fs/buffer.c
@@ -173,6 +173,15 @@ EXPORT_SYMBOL(sync_blockdev);
  */
 int fsync_super(struct super_block *sb)
 {
+	int ret;
+
+	/* A safety net. During suspend, we might overwrite
+	 * memory containing filesystem info. We don't then
+	 * want to sync it to disk. */
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+	
+	current->flags |= PF_SYNCTHREAD;
+
 	sync_inodes_sb(sb, 0);
 	DQUOT_SYNC(sb);
 	lock_super(sb);
@@ -184,7 +193,10 @@ int fsync_super(struct super_block *sb)
 	sync_blockdev(sb->s_bdev);
 	sync_inodes_sb(sb, 1);
 
-	return sync_blockdev(sb->s_bdev);
+	ret = sync_blockdev(sb->s_bdev);
+
+	current->flags &= ~PF_SYNCTHREAD;
+	return ret;
 }
 
 /*
@@ -195,12 +207,21 @@ int fsync_super(struct super_block *sb)
 int fsync_bdev(struct block_device *bdev)
 {
 	struct super_block *sb = get_super(bdev);
+	int ret;
+
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+
+	current->flags |= PF_SYNCTHREAD;
+
 	if (sb) {
 		int res = fsync_super(sb);
 		drop_super(sb);
+		current->flags &= ~PF_SYNCTHREAD;
 		return res;
 	}
-	return sync_blockdev(bdev);
+	ret = sync_blockdev(bdev);
+	current->flags &= ~PF_SYNCTHREAD;
+	return ret;
 }
 
 /**
@@ -280,6 +301,13 @@ EXPORT_SYMBOL(thaw_bdev);
  */
 static void do_sync(unsigned long wait)
 {
+	/* A safety net. During suspend, we might overwrite
+	 * memory containing filesystem info. We don't then
+	 * want to sync it to disk. */
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+
+	current->flags |= PF_SYNCTHREAD;
+
 	wakeup_bdflush(0);
 	sync_inodes(0);		/* All mappings, inodes and their blockdevs */
 	DQUOT_SYNC(NULL);
@@ -291,6 +319,8 @@ static void do_sync(unsigned long wait)
 		printk("Emergency Sync complete\n");
 	if (unlikely(laptop_mode))
 		laptop_sync_completion();
+
+	current->flags &= ~PF_SYNCTHREAD;
 }
 
 asmlinkage long sys_sync(void)
@@ -316,6 +346,10 @@ int file_fsync(struct file *filp, struct
 	struct super_block * sb;
 	int ret, err;
 
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+
+	current->flags |= PF_SYNCTHREAD;
+
 	/* sync the inode to buffers */
 	ret = write_inode_now(inode, 0);
 
@@ -330,6 +364,8 @@ int file_fsync(struct file *filp, struct
 	err = sync_blockdev(sb->s_bdev);
 	if (!ret)
 		ret = err;
+
+	current->flags &= ~PF_SYNCTHREAD;
 	return ret;
 }
 
@@ -339,6 +375,10 @@ asmlinkage long sys_fsync(unsigned int f
 	struct address_space *mapping;
 	int ret, err;
 
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+
+	current->flags |= PF_SYNCTHREAD;
+
 	ret = -EBADF;
 	file = fget(fd);
 	if (!file)
@@ -372,6 +412,7 @@ asmlinkage long sys_fsync(unsigned int f
 out_putf:
 	fput(file);
 out:
+	current->flags &= ~PF_SYNCTHREAD;
 	return ret;
 }
 
@@ -381,6 +422,10 @@ asmlinkage long sys_fdatasync(unsigned i
 	struct address_space *mapping;
 	int ret, err;
 
+	BUG_ON(test_suspend_state(SUSPEND_DISABLE_SYNCING));
+
+	current->flags |= PF_SYNCTHREAD;
+
 	ret = -EBADF;
 	file = fget(fd);
 	if (!file)
@@ -407,6 +452,7 @@ asmlinkage long sys_fdatasync(unsigned i
 out_putf:
 	fput(file);
 out:
+	current->flags &= ~PF_SYNCTHREAD;
 	return ret;
 }
 
fs/jbd/journal.c +1 -0
diff -ruNp 351-syncthreads.patch-old/fs/jbd/journal.c 351-syncthreads.patch-new/fs/jbd/journal.c
@@ -130,6 +130,7 @@ int kjournald(void *arg)
 	current_journal = journal;
 
 	daemonize("kjournald");
+	current->flags |= PF_SYNCTHREAD;
 
 	/* Set up an interval timer which can be used to trigger a
            commit wakeup after the commit interval expires */
fs/jffs/intrep.c +1 -0
diff -ruNp 351-syncthreads.patch-old/fs/jffs/intrep.c 351-syncthreads.patch-new/fs/jffs/intrep.c
@@ -3364,6 +3364,7 @@ jffs_garbage_collect_thread(void *ptr)
 	D1(int i = 1);
 
 	daemonize("jffs_gcd");
+	current->flags |= PF_SYNCTHREAD;
 
 	c->gc_task = current;
 
fs/jfs/jfs_logmgr.c +1 -0
diff -ruNp 351-syncthreads.patch-old/fs/jfs/jfs_logmgr.c 351-syncthreads.patch-new/fs/jfs/jfs_logmgr.c
@@ -2351,6 +2351,7 @@ int jfsIOWait(void *arg)
 	struct lbuf *bp;
 
 	daemonize("jfsIO");
+	current->flags |= PF_SYNCTHREAD;
 
 	complete(&jfsIOwait);
 
fs/jfs/jfs_txnmgr.c +1 -1
diff -ruNp 351-syncthreads.patch-old/fs/jfs/jfs_txnmgr.c 351-syncthreads.patch-new/fs/jfs/jfs_txnmgr.c
@@ -47,7 +47,6 @@
 #include <linux/vmalloc.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
-#include <linux/suspend.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include "jfs_incore.h"
@@ -2777,6 +2776,7 @@ int jfs_lazycommit(void *arg)
 	struct jfs_sb_info *sbi;
 
 	daemonize("jfsCommit");
+	current->flags |= PF_SYNCTHREAD;
 
 	complete(&jfsIOwait);
 
fs/lockd/clntlock.c +1 -0
diff -ruNp 351-syncthreads.patch-old/fs/lockd/clntlock.c 351-syncthreads.patch-new/fs/lockd/clntlock.c
@@ -200,6 +200,7 @@ reclaimer(void *ptr)
 	struct inode *inode;
 
 	daemonize("%s-reclaim", host->h_name);
+	current->flags |= PF_SYNCTHREAD;
 	allow_signal(SIGKILL);
 
 	/* This one ensures that our parent doesn't terminate while the
fs/lockd/svc.c +3 -0
diff -ruNp 351-syncthreads.patch-old/fs/lockd/svc.c 351-syncthreads.patch-new/fs/lockd/svc.c
@@ -115,6 +115,7 @@ lockd(struct svc_rqst *rqstp)
 	up(&lockd_start);
 
 	daemonize("lockd");
+	current->flags |= PF_SYNCTHREAD;
 
 	/* Process request with signals blocked, but allow SIGKILL.  */
 	allow_signal(SIGKILL);
@@ -138,6 +139,8 @@ lockd(struct svc_rqst *rqstp)
 	while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) {
 		long timeout = MAX_SCHEDULE_TIMEOUT;
 
+		try_to_freeze();
+
 		if (signalled()) {
 			flush_signals(current);
 			if (nlmsvc_ops) {
fs/nfsd/nfssvc.c +1 -0
diff -ruNp 351-syncthreads.patch-old/fs/nfsd/nfssvc.c 351-syncthreads.patch-new/fs/nfsd/nfssvc.c
@@ -182,6 +182,7 @@ nfsd(struct svc_rqst *rqstp)
 	/* Lock module and set up kernel thread */
 	lock_kernel();
 	daemonize("nfsd");
+	current->flags |= PF_SYNCTHREAD;
 
 	/* After daemonize() this kernel thread shares current->fs
 	 * with the init process. We need to create files with a
fs/xfs/linux-2.6/xfs_buf.c +1 -1
diff -ruNp 351-syncthreads.patch-old/fs/xfs/linux-2.6/xfs_buf.c 351-syncthreads.patch-new/fs/xfs/linux-2.6/xfs_buf.c
@@ -1772,7 +1772,7 @@ pagebuf_daemon(
 
 	/*  Set up the thread  */
 	daemonize("xfsbufd");
-	current->flags |= PF_MEMALLOC;
+	current->flags |= PF_MEMALLOC | PF_SYNCTHREAD;
 
 	pagebuf_daemon_task = current;
 	pagebuf_daemon_active = 1;
fs/xfs/linux-2.6/xfs_super.c +1 -0
diff -ruNp 351-syncthreads.patch-old/fs/xfs/linux-2.6/xfs_super.c 351-syncthreads.patch-new/fs/xfs/linux-2.6/xfs_super.c
@@ -470,6 +470,7 @@ xfssyncd(
 	struct vfs_sync_work	*work, *n;
 
 	daemonize("xfssyncd");
+	current->flags |= PF_SYNCTHREAD;
 
 	vfsp->vfs_sync_work.w_vfs = vfsp;
 	vfsp->vfs_sync_work.w_syncer = vfs_sync_worker;
include/linux/sched.h +2 -0
diff -ruNp 351-syncthreads.patch-old/include/linux/sched.h 351-syncthreads.patch-new/include/linux/sched.h
@@ -798,6 +798,8 @@ do { if (atomic_dec_and_test(&(tsk)->usa
 #define PF_SYNCWRITE	0x00200000	/* I am doing a sync write */
 #define PF_BORROWED_MM	0x00400000	/* I am a kthread doing use_mm */
 #define PF_RANDOMIZE	0x00800000	/* randomize virtual address space */
+#define PF_SYNCTHREAD	0x01000000	/* this thread can start activity during the 
++ 					   early part of freezing processes */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
mm/pdflush.c +1 -1
diff -ruNp 351-syncthreads.patch-old/mm/pdflush.c 351-syncthreads.patch-new/mm/pdflush.c
@@ -89,7 +89,7 @@ struct pdflush_work {
 
 static int __pdflush(struct pdflush_work *my_work)
 {
-	current->flags |= PF_FLUSHER;
+	current->flags |= (PF_FLUSHER | PF_SYNCTHREAD);
 	my_work->fn = NULL;
 	my_work->who = current;
 	INIT_LIST_HEAD(&my_work->list);
#19 lore raw

Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch

Again, why do you think you need this?

#20 lore raw

Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch

Hi.

Quoted 1 line · Christoph Hellwig

Again, why do you think you need this?

1. If something should be wrong with the freezer, it forms part of a safety net that stops your data on disk being trashed.
2. Separating out threads doing syncing from threads submitting I/O makes the refrigerator much more reliable, even under extreme load.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#21 lore raw

Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch

Hi!

Quoted 7 lines
Quoted 1 line

Again, why do you think you need this?

1. If something should be wrong with the freezer, it forms part of a safety net that stops your data on disk being trashed.

2. Separating out threads doing syncing from threads submitting I/O makes the refrigerator much more reliable, even under extreme load.

This seems to be red herring. Sometimes sync took way too long (like hours) with older kernels and reiserfs, but I believe that has been fixed. If not, we need to fix it, anyway; no need to work around it in suspend2.
Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#22 lore raw

Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch

Hi.

Quoted 7 lines · Pavel Machek

Hi!

Quoted 4 lines
Quoted 1 line

Again, why do you think you need this?

1. If something should be wrong with the freezer, it forms part of a safety net that stops your data on disk being trashed.

Quoted 7 lines
Quoted 2 lines

2. Separating out threads doing syncing from threads submitting I/O makes the refrigerator much more reliable, even under extreme load.

This seems to be red herring. Sometimes sync took way too long (like hours) with older kernels and reiserfs, but I believe that has been fixed. If not, we need to fix it, anyway; no need to work around it in suspend2.

Are you considering races such as the case where one process is submitting I/O (say dd) while another is trying to sync? Even if sync does return sooner (presumably because it only syncs writes submitted before the sync), there will still be dirty data after the sync completes. And if we start another sync thread, it will suffer the same problem. The only solution is to stop I/O being submitted, then sync. But having stopped I/O being submitted, we need to still have the threads the process the I/O (possibly userspace ones) unfrozen. Hence we need to differentiate 'syncthreads'.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#23 lore raw

Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch

Hi!

Quoted 13 lines
Quoted 5 lines
Quoted 4 lines
Quoted 1 line

Again, why do you think you need this?

1. If something should be wrong with the freezer, it forms part of a safety net that stops your data on disk being trashed.

Quoted 7 lines
Quoted 2 lines

2. Separating out threads doing syncing from threads submitting I/O makes the refrigerator much more reliable, even under extreme load.

This seems to be red herring. Sometimes sync took way too long (like hours) with older kernels and reiserfs, but I believe that has been fixed. If not, we need to fix it, anyway; no need to work around it in suspend2.

Quoted 9 lines

Are you considering races such as the case where one process is submitting I/O (say dd) while another is trying to sync? Even if sync does return sooner (presumably because it only syncs writes submitted before the sync), there will still be dirty data after the sync completes. And if we start another sync thread, it will suffer the same problem. The only solution is to stop I/O being submitted, then sync. But having stopped I/O being submitted, we need to still have the threads the process the I/O (possibly userspace ones) unfrozen. Hence we need to differentiate 'syncthreads'.

OTOH: this is only critical for "niceness", not for correctness. Calling sync() before suspend is simply nice thing to do, but it is not required in any way. If someone is doing long dd, tough, they are going to loose some data if wakeup fails. It is no worse than sudden poweroff.
Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#24 lore raw

Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch

Hi.

Quoted 25 lines · Pavel Machek

Hi!

Quoted 13 lines
Quoted 5 lines
Quoted 4 lines
Quoted 1 line

Again, why do you think you need this?

1. If something should be wrong with the freezer, it forms part of a safety net that stops your data on disk being trashed.

Quoted 7 lines
Quoted 2 lines

2. Separating out threads doing syncing from threads submitting I/O makes the refrigerator much more reliable, even under extreme load.

This seems to be red herring. Sometimes sync took way too long (like hours) with older kernels and reiserfs, but I believe that has been fixed. If not, we need to fix it, anyway; no need to work around it in suspend2.

Quoted 9 lines

Are you considering races such as the case where one process is submitting I/O (say dd) while another is trying to sync? Even if sync does return sooner (presumably because it only syncs writes submitted before the sync), there will still be dirty data after the sync completes. And if we start another sync thread, it will suffer the same problem. The only solution is to stop I/O being submitted, then sync. But having stopped I/O being submitted, we need to still have the threads the process the I/O (possibly userspace ones) unfrozen. Hence we need to differentiate 'syncthreads'.

Quoted 5 lines

OTOH: this is only critical for "niceness", not for correctness. Calling sync() before suspend is simply nice thing to do, but it is not required in any way. If someone is doing long dd, tough, they are going to loose some data if wakeup fails. It is no worse than sudden poweroff.

How can you say it's only required for niceness one minute, then admit it might result in data loss the next?

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#25 lore raw

Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch

Hi!

Quoted 23 lines
Quoted 23 lines
Quoted 22 lines
Quoted 5 lines
Quoted 4 lines
Quoted 1 line

Again, why do you think you need this?

1. If something should be wrong with the freezer, it forms part of a safety net that stops your data on disk being trashed.

Quoted 7 lines
Quoted 2 lines

2. Separating out threads doing syncing from threads submitting I/O makes the refrigerator much more reliable, even under extreme load.

This seems to be red herring. Sometimes sync took way too long (like hours) with older kernels and reiserfs, but I believe that has been fixed. If not, we need to fix it, anyway; no need to work around it in suspend2.

Are you considering races such as the case where one process is submitting I/O (say dd) while another is trying to sync? Even if sync does return sooner (presumably because it only syncs writes submitted before the sync), there will still be dirty data after the sync completes. And if we start another sync thread, it will suffer the same problem. The only solution is to stop I/O being submitted, then sync. But having stopped I/O being submitted, we need to still have the threads the process the I/O (possibly userspace ones) unfrozen. Hence we need to differentiate 'syncthreads'.

Quoted 8 lines
Quoted 5 lines

OTOH: this is only critical for "niceness", not for correctness. Calling sync() before suspend is simply nice thing to do, but it is not required in any way. If someone is doing long dd, tough, they are going to loose some data if wakeup fails. It is no worse than sudden poweroff.

How can you say it's only required for niceness one minute, then admit it might result in data loss the next?

It will result in data loss *if resume fails*. But failing resume *always* causes data in running programs to be lost, so I do not see that as a problem.
Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#26 lore raw

Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch

Hi.

Quoted 6 lines · Pavel Machek
Quoted 6 lines
Quoted 5 lines

OTOH: this is only critical for "niceness", not for correctness. Calling sync() before suspend is simply nice thing to do, but it is not required in any way. If someone is doing long dd, tough, they are going to loose some data if wakeup fails. It is no worse than sudden poweroff.

Quoted 6 lines
Quoted 2 lines

How can you say it's only required for niceness one minute, then admit it might result in data loss the next?

It will result in data loss *if resume fails*. But failing resume *always* causes data in running programs to be lost, so I do not see that as a problem.

It does for you :>

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#27 lore raw

PATCH 6/48 Suspend2 2.1.9.8 for 2.6.12: 351-syncthreads.patch

In reply to Nigel Cunningham
mm/page-writeback.c +9 -0
diff -ruNp 352-disable-pdflush-during-suspend.patch-old/mm/page-writeback.c 352-disable-pdflush-during-suspend.patch-new/mm/page-writeback.c
@@ -29,6 +29,7 @@
 #include <linux/sysctl.h>
 #include <linux/cpu.h>
 #include <linux/syscalls.h>
+#include <linux/suspend.h>
 
 /*
  * The maximum number of pages to writeout in a single bdflush/kupdate
@@ -404,6 +405,12 @@ static void wb_kupdate(unsigned long arg
 		.for_kupdate	= 1,
 	};
 
+	if (test_suspend_state(SUSPEND_DISABLE_SYNCING)) {
+		start_jif = jiffies;
+		next_jif = start_jif + (dirty_writeback_centisecs * HZ) / 100;
+		goto out;
+	}
+
 	sync_supers();
 
 	get_writeback_state(&wbs);
@@ -424,6 +431,8 @@ static void wb_kupdate(unsigned long arg
 		}
 		nr_to_write -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
 	}
+
+out:
 	if (time_before(next_jif, jiffies + HZ))
 		next_jif = jiffies + HZ;
 	if (dirty_writeback_centisecs)
#28 lore raw

PATCH 7/48 Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch

In reply to Nigel Cunningham
mm/highmem.c +5 -1
diff -ruNp 353-disable-highmem-tlb-flush-for-copyback.patch-old/mm/highmem.c 353-disable-highmem-tlb-flush-for-copyback.patch-new/mm/highmem.c
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
+#include <linux/suspend.h>
 #include <asm/tlbflush.h>
 
 static mempool_t *page_pool, *isa_page_pool;
@@ -95,7 +96,10 @@ static void flush_all_zero_pkmaps(void)
 
 		set_page_address(page, NULL);
 	}
-	flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
+	if (test_suspend_state(SUSPEND_FREEZE_SMP))
+		__flush_tlb();
+	else
+		flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
 }
 
 static inline unsigned long map_new_virtual(struct page *page)
#29 lore raw

Re: [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch

Quoted 13 lines · Nigel Cunningham

diff -ruNp 353-disable-highmem-tlb-flush-for-copyback.patch-old/mm/highmem.c 353-disable-highmem-tlb-flush-for-copyback.patch-new/mm/highmem.c

mm/highmem.c +1 -0
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
+#include <linux/suspend.h>
 #include <asm/tlbflush.h>
 
 static mempool_t *page_pool, *isa_page_pool;
@@ -95,7 +96,10 @@ static void flush_all_zero_pkmaps(void)
 

mm/highmem.c static void flush_all_zero_pkmaps(void) · line 105

Quoted 10 lines
mm/highmem.c +4 -1
 		set_page_address(page, NULL);
 	}
-	flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
+	if (test_suspend_state(SUSPEND_FREEZE_SMP))
+		__flush_tlb();
+	else
+		flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
 }
 
 static inline unsigned long map_new_virtual(struct page *page)

What state are the other processors in when you hit this path?

#30 lore raw

Re: [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch

Hi.

Quoted 24 lines · Zwane Mwaikambo
Quoted 22 lines · Nigel Cunningham

diff -ruNp 353-disable-highmem-tlb-flush-for-copyback.patch-old/mm/highmem.c 353-disable-highmem-tlb-flush-for-copyback.patch-new/mm/highmem.c

mm/highmem.c +5 -1
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
+#include <linux/suspend.h>
 #include <asm/tlbflush.h>
 
 static mempool_t *page_pool, *isa_page_pool;
@@ -95,7 +96,10 @@ static void flush_all_zero_pkmaps(void)
 
 		set_page_address(page, NULL);
 	}
-	flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
+	if (test_suspend_state(SUSPEND_FREEZE_SMP))
+		__flush_tlb();
+	else
+		flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
 }
 
Quoted 3 lines

mm/highmem.c static void flush_all_zero_pkmaps(void) · line 105

Quoted 1 line
mm/highmem.c +0 -0
 static inline unsigned long map_new_virtual(struct page *page)

What state are the other processors in when you hit this path?

Looping in arch specific code, waiting for an atomic_t to tell them it's time to restore state and carry on. They're there the whole time CPU0 is restoring the image and highmem.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#31 lore raw

Re: [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch

Quoted 25 lines · Nigel Cunningham
Quoted 24 lines · Zwane Mwaikambo
Quoted 22 lines · Nigel Cunningham

diff -ruNp 353-disable-highmem-tlb-flush-for-copyback.patch-old/mm/highmem.c 353-disable-highmem-tlb-flush-for-copyback.patch-new/mm/highmem.c

mm/highmem.c +5 -1
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
+#include <linux/suspend.h>
 #include <asm/tlbflush.h>
 
 static mempool_t *page_pool, *isa_page_pool;
@@ -95,7 +96,10 @@ static void flush_all_zero_pkmaps(void)
 
 		set_page_address(page, NULL);
 	}
-	flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
+	if (test_suspend_state(SUSPEND_FREEZE_SMP))
+		__flush_tlb();
+	else
+		flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
 }
 
Quoted 7 lines
Quoted 3 lines

mm/highmem.c static void flush_all_zero_pkmaps(void) · line 105

Quoted 1 line
mm/highmem.c +0 -0
 static inline unsigned long map_new_virtual(struct page *page)

What state are the other processors in when you hit this path?

Looping in arch specific code, waiting for an atomic_t to tell them it's time to restore state and carry on. They're there the whole time CPU0 is restoring the image and highmem.

Oh ok, so they wouldn't have TLB entries for the above.

Thanks,
Zwane

#32 lore raw

Re: [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch

In reply to Nigel Cunningham

Hi!

Quoted 13 lines

diff -ruNp 353-disable-highmem-tlb-flush-for-copyback.patch-old/mm/highmem.c 353-disable-highmem-tlb-flush-for-copyback.patch-new/mm/highmem.c

mm/highmem.c +1 -0
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
+#include <linux/suspend.h>
 #include <asm/tlbflush.h>
 
 static mempool_t *page_pool, *isa_page_pool;
@@ -95,7 +96,10 @@ static void flush_all_zero_pkmaps(void)
 

mm/highmem.c static void flush_all_zero_pkmaps(void) · line 105

Quoted 10 lines
mm/highmem.c +4 -1
 		set_page_address(page, NULL);
 	}
-	flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
+	if (test_suspend_state(SUSPEND_FREEZE_SMP))
+		__flush_tlb();
+	else
+		flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
 }
 
 static inline unsigned long map_new_virtual(struct page *page)

Take a look at cpu hotplug system, it is cleaner way of doing this...

Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#33 lore raw

Re: [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch

In reply to Nigel Cunningham
Quoted 12 lines · Nigel Cunningham

diff -ruNp 353-disable-highmem-tlb-flush-for-copyback.patch-old/mm/highmem.c 353-disable-highmem-tlb-flush-for-copyback.patch-new/mm/highmem.c

mm/highmem.c +1 -0
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
+#include <linux/suspend.h>
 #include <asm/tlbflush.h>
 
 static mempool_t *page_pool, *isa_page_pool;

mm/highmem.c static void flush_all_zero_pkmaps(void) · line 100

Quoted 6 lines
mm/highmem.c +2 -1
@@ -95,7 +96,10 @@ static void flush_all_zero_pkmaps(void)
 
 		set_page_address(page, NULL);
 	}
-	flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
+	if (test_suspend_state(SUSPEND_FREEZE_SMP))
+		__flush_tlb();

On ARM SMP, if you want the "local" version, the flush functions are prefixed by "local_", though I guess we can also define a __flush_tlb() for compatibility if someone wants to use swsusp with ARM SMP.

Signature · 3 lines
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core
#35 lore raw

PATCH 8/48 Suspend2 2.1.9.8 for 2.6.12: 353-disable-highmem-tlb-flush-for-copyback.patch

In reply to Nigel Cunningham
arch/i386/kernel/cpu/mcheck/non-fatal.c +3 -1
diff -ruNp 354-disable-mce-checking-during-suspend-avoid-smp-deadlock.patch-old/arch/i386/kernel/cpu/mcheck/non-fatal.c 354-disable-mce-checking-during-suspend-avoid-smp-deadlock.patch-new/arch/i386/kernel/cpu/mcheck/non-fatal.c
@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/smp.h>
 #include <linux/module.h>
+#include <linux/suspend.h>
 
 #include <asm/processor.h> 
 #include <asm/system.h>
@@ -58,7 +59,8 @@ static DECLARE_WORK(mce_work, mce_work_f
 
 static void mce_work_fn(void *data)
 { 
-	on_each_cpu(mce_checkregs, NULL, 1, 1);
+	if (!test_suspend_state(SUSPEND_RUNNING))
+		on_each_cpu(mce_checkregs, NULL, 1, 1);
 	schedule_delayed_work(&mce_work, MCE_RATE);
 } 
 
#36 lore raw

PATCH 9/48 Suspend2 2.1.9.8 for 2.6.12: 354-disable-mce-checking-during-suspend-avoid-smp-deadlock.patch

In reply to Nigel Cunningham
mm/vmscan.c +4 -2
diff -ruNp 360-reset-kswapd-max-order-after-resume.patch-old/mm/vmscan.c 360-reset-kswapd-max-order-after-resume.patch-new/mm/vmscan.c
@@ -1228,8 +1228,10 @@ static int kswapd(void *p)
 	order = 0;
 	for ( ; ; ) {
 		unsigned long new_order;
-
-		try_to_freeze();
+		if (freezing(current)) {
+			try_to_freeze();
+			pgdat->kswapd_max_order = 0;
+		}
 
 		prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
 		new_order = pgdat->kswapd_max_order;
#37 lore raw

Re: [PATCH] [9/48] Suspend2 2.1.9.8 for 2.6.12: 354-disable-mce-checking-during-suspend-avoid-smp-deadlock.patch

Hi!

mm/vmscan.c static int kswapd(void *p) · line 1234

Quoted 13 lines

diff -ruNp 360-reset-kswapd-max-order-after-resume.patch-old/mm/vmscan.c 360-reset-kswapd-max-order-after-resume.patch-new/mm/vmscan.c

mm/vmscan.c +4 -2
@@ -1228,8 +1228,10 @@ static int kswapd(void *p)
 	order = 0;
 	for ( ; ; ) {
 		unsigned long new_order;
-
-		try_to_freeze();
+		if (freezing(current)) {
+			try_to_freeze();
+			pgdat->kswapd_max_order = 0;
+		}

Why not

	if (try_to_freeze())
		pgdat->... = 0;

?
Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#38 lore raw

Re: [PATCH] [9/48] Suspend2 2.1.9.8 for 2.6.12: 354-disable-mce-checking-during-suspend-avoid-smp-deadlock.patch

Hi.

Quoted 17 lines · Pavel Machek

Hi!

mm/vmscan.c static int kswapd(void *p) · line 1234

Quoted 13 lines

diff -ruNp 360-reset-kswapd-max-order-after-resume.patch-old/mm/vmscan.c 360-reset-kswapd-max-order-after-resume.patch-new/mm/vmscan.c

mm/vmscan.c +4 -2
@@ -1228,8 +1228,10 @@ static int kswapd(void *p)
 	order = 0;
 	for ( ; ; ) {
 		unsigned long new_order;
-
-		try_to_freeze();
+		if (freezing(current)) {
+			try_to_freeze();
+			pgdat->kswapd_max_order = 0;
+		}

Why not

Quoted 4 lines
	if (try_to_freeze())
		pgdat->... = 0;

?

I have no idea. Fixed. Thanks!

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#39 lore raw

PATCH 10/48 Suspend2 2.1.9.8 for 2.6.12: 360-reset-kswapd-max-order-after-resume.patch

In reply to Nigel Cunningham
arch/i386/mm/init.c +28 -8
diff -ruNp 401-e820-table-support.patch-old/arch/i386/mm/init.c 401-e820-table-support.patch-new/arch/i386/mm/init.c
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
 #include <linux/efi.h>
+#include <linux/suspend.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -269,12 +270,15 @@ void __init one_highpage_init(struct pag
 {
 	if (page_is_ram(pfn) && !(bad_ppro && page_kills_ppro(pfn))) {
 		ClearPageReserved(page);
+		ClearPageNosave(page);
 		set_bit(PG_highmem, &page->flags);
 		set_page_count(page, 1);
 		__free_page(page);
 		totalhigh_pages++;
-	} else
+	} else {
 		SetPageReserved(page);
+		SetPageNosave(page);
+	}
 }
 
 #ifndef CONFIG_DISCONTIGMEM
@@ -352,7 +356,7 @@ static void __init pagetable_init (void)
 #endif
 }
 
-#if defined(CONFIG_PM_DISK) || defined(CONFIG_SOFTWARE_SUSPEND)
+#ifdef CONFIG_PM
 /*
  * Swap suspend & friends need this for resume because things like the intel-agp
  * driver might have split up a kernel 4MB mapping.
@@ -539,6 +543,7 @@ void __init mem_init(void)
 	int codesize, reservedpages, datasize, initsize;
 	int tmp;
 	int bad_ppro;
+	void * addr;
 
 #ifndef CONFIG_DISCONTIGMEM
 	if (!mem_map)
@@ -569,12 +574,25 @@ void __init mem_init(void)
 	totalram_pages += free_all_bootmem();
 
 	reservedpages = 0;
-	for (tmp = 0; tmp < max_low_pfn; tmp++)
-		/*
-		 * Only count reserved RAM pages
-		 */
-		if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp)))
-			reservedpages++;
+	addr = __va(0);
+	for (tmp = 0; tmp < max_low_pfn; tmp++, addr += PAGE_SIZE) {
+		if (page_is_ram(tmp)) {
+			/*
+			 * Only count reserved RAM pages
+			 */
+			if (PageReserved(mem_map+tmp))
+				reservedpages++;
+			/*
+			 * Mark nosave pages
+			 */
+			if (addr >= (void *)&__nosave_begin && addr < (void *)&__nosave_end)
+				SetPageNosave(mem_map+tmp);
+		} else
+			/*
+			 * Non-RAM pages are always nosave
+			 */
+			SetPageNosave(mem_map+tmp);
+	}
 
 	set_highmem_pages_init(bad_ppro);
 
@@ -673,6 +691,7 @@ void free_initmem(void)
 	addr = (unsigned long)(&__init_begin);
 	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
 		ClearPageReserved(virt_to_page(addr));
+		ClearPageNosave(virt_to_page(addr));
 		set_page_count(virt_to_page(addr), 1);
 		memset((void *)addr, 0xcc, PAGE_SIZE);
 		free_page(addr);
@@ -688,6 +707,7 @@ void free_initrd_mem(unsigned long start
 		printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
 	for (; start < end; start += PAGE_SIZE) {
 		ClearPageReserved(virt_to_page(start));
+		ClearPageNosave(virt_to_page(start));
 		set_page_count(virt_to_page(start), 1);
 		free_page(start);
 		totalram_pages++;
mm/bootmem.c +4 -0
diff -ruNp 401-e820-table-support.patch-old/mm/bootmem.c 401-e820-table-support.patch-new/mm/bootmem.c
@@ -280,12 +280,14 @@ static unsigned long __init free_all_boo
 
 			count += BITS_PER_LONG;
 			__ClearPageReserved(page);
+			ClearPageNosave(page);
 			order = ffs(BITS_PER_LONG) - 1;
 			set_page_refs(page, order);
 			for (j = 1; j < BITS_PER_LONG; j++) {
 				if (j + 16 < BITS_PER_LONG)
 					prefetchw(page + j + 16);
 				__ClearPageReserved(page + j);
+				ClearPageNosave(page + j);
 			}
 			__free_pages(page, order);
 			i += BITS_PER_LONG;
@@ -296,6 +298,7 @@ static unsigned long __init free_all_boo
 				if (v & m) {
 					count++;
 					__ClearPageReserved(page);
+					ClearPageNosave(page);
 					set_page_refs(page, 0);
 					__free_page(page);
 				}
@@ -316,6 +319,7 @@ static unsigned long __init free_all_boo
 	for (i = 0; i < ((bdata->node_low_pfn-(bdata->node_boot_start >> PAGE_SHIFT))/8 + PAGE_SIZE-1)/PAGE_SIZE; i++,page++) {
 		count++;
 		__ClearPageReserved(page);
+		ClearPageNosave(page);
 		set_page_count(page, 1);
 		__free_page(page);
 	}
#40 lore raw

Re: [PATCH] [10/48] Suspend2 2.1.9.8 for 2.6.12: 360-reset-kswapd-max-order-after-resume.patch

So what is this doing, and is it breaking swsusp support?

#41 lore raw

Re: [PATCH] [10/48] Suspend2 2.1.9.8 for 2.6.12: 360-reset-kswapd-max-order-after-resume.patch

Quoted 1 line · Christoph Hellwig

So what is this doing, and is it breaking swsusp support?

Marking at boot time pages that shouldn't be saved. I'm not sure why Pavel doesn't seem to need it. None of these changes break Pavel's code.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#42 lore raw

PATCH 11/48 Suspend2 2.1.9.8 for 2.6.12: 401-e820-table-support.patch

In reply to Nigel Cunningham
arch/i386/kernel/cpu/mtrr/main.c +11 -14
diff -ruNp 402-mtrr-remove-sysdev.patch-old/arch/i386/kernel/cpu/mtrr/main.c 402-mtrr-remove-sysdev.patch-new/arch/i386/kernel/cpu/mtrr/main.c
@@ -166,7 +166,6 @@ static void ipi_handler(void *info)
 	atomic_dec(&data->count);
 	local_irq_restore(flags);
 }
-
 #endif
 
 /**
@@ -560,7 +559,7 @@ struct mtrr_value {
 
 static struct mtrr_value * mtrr_state;
 
-static int mtrr_save(struct sys_device * sysdev, u32 state)
+int mtrr_save(void)
 {
 	int i;
 	int size = num_var_ranges * sizeof(struct mtrr_value);
@@ -580,28 +579,27 @@ static int mtrr_save(struct sys_device *
 	return 0;
 }
 
-static int mtrr_restore(struct sys_device * sysdev)
+/* Restore mtrrs on this CPU only.
+ * Done with interrupts disabled via __smp_lowlevel_suspend
+ */
+int mtrr_restore_one_cpu(void)
 {
 	int i;
 
 	for (i = 0; i < num_var_ranges; i++) {
 		if (mtrr_state[i].lsize) 
-			set_mtrr(i,
+			mtrr_if->set(i,
 				 mtrr_state[i].lbase,
 				 mtrr_state[i].lsize,
 				 mtrr_state[i].ltype);
 	}
-	kfree(mtrr_state);
 	return 0;
 }
 
-
-
-static struct sysdev_driver mtrr_sysdev_driver = {
-	.suspend	= mtrr_save,
-	.resume		= mtrr_restore,
-};
-
+void mtrr_restore_finish(void)
+{
+	kfree(mtrr_state);
+}
 
 /**
  * mtrr_init - initialize mtrrs on the boot CPU
@@ -669,8 +667,7 @@ static int __init mtrr_init(void)
 		init_table();
 		init_other_cpus();
 
-		return sysdev_driver_register(&cpu_sysdev_class,
-					      &mtrr_sysdev_driver);
+		return 0;
 	}
 	return -ENXIO;
 }
#43 lore raw

Re: [PATCH] [11/48] Suspend2 2.1.9.8 for 2.6.12: 401-e820-table-support.patch

Quoted 21 lines · Nigel Cunningham

diff -ruNp 402-mtrr-remove-sysdev.patch-old/arch/i386/kernel/cpu/mtrr/main.c 402-mtrr-remove-sysdev.patch-new/arch/i386/kernel/cpu/mtrr/main.c

arch/i386/kernel/cpu/mtrr/main.c +1 -2
@@ -166,7 +166,6 @@ static void ipi_handler(void *info)
 	atomic_dec(&data->count);
 	local_irq_restore(flags);
 }
-
 #endif
 
 /**
@@ -560,7 +559,7 @@ struct mtrr_value {
 
 static struct mtrr_value * mtrr_state;
 
-static int mtrr_save(struct sys_device * sysdev, u32 state)
+int mtrr_save(void)
 {
 	int i;
 	int size = num_var_ranges * sizeof(struct mtrr_value);

arch/i386/kernel/cpu/mtrr/main.c static int mtrr_save(struct sys_device * · line 580

Quoted 2 lines
arch/i386/kernel/cpu/mtrr/main.c +0 -0
@@ -580,28 +579,27 @@ static int mtrr_save(struct sys_device *
 	return 0;
 }

Isn't this covered by Shaohua Li's patch?

#44 lore raw

Re: [PATCH] [11/48] Suspend2 2.1.9.8 for 2.6.12: 401-e820-table-support.patch

Hi.

Quoted 17 lines · Zwane Mwaikambo
Quoted 15 lines · Nigel Cunningham

diff -ruNp 402-mtrr-remove-sysdev.patch-old/arch/i386/kernel/cpu/mtrr/main.c 402-mtrr-remove-sysdev.patch-new/arch/i386/kernel/cpu/mtrr/main.c

arch/i386/kernel/cpu/mtrr/main.c +0 -1
@@ -166,7 +166,6 @@ static void ipi_handler(void *info)
 	atomic_dec(&data->count);
 	local_irq_restore(flags);
 }
-
 #endif
 
 /**
@@ -560,7 +559,7 @@ struct mtrr_value {
 
 static struct mtrr_value * mtrr_state;
 
Quoted 10 lines

arch/i386/kernel/cpu/mtrr/main.c static int mtrr_save(struct sys_device * · line 580

Quoted 8 lines
arch/i386/kernel/cpu/mtrr/main.c +1 -1
-static int mtrr_save(struct sys_device * sysdev, u32 state)
+int mtrr_save(void)
 {
 	int i;
 	int size = num_var_ranges * sizeof(struct mtrr_value);
@@ -580,28 +579,27 @@ static int mtrr_save(struct sys_device *
 	return 0;
 }

Isn't this covered by Shaohua Li's patch?

I believe so, but Shaohua Li's patch isn't merged in 2.6.12 (is it yet at all). This is the solution I've been using for... can't remember how long.

Thanks for the feedback.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#45 lore raw

Re: [PATCH] [11/48] Suspend2 2.1.9.8 for 2.6.12: 401-e820-table-support.patch

Hi!

Quoted 15 lines
Quoted 4 lines
Quoted 4 lines
arch/i386/kernel/cpu/mtrr/main.c +0 -0
@@ -560,7 +559,7 @@ struct mtrr_value {
 
 static struct mtrr_value * mtrr_state;
 
Quoted 10 lines

arch/i386/kernel/cpu/mtrr/main.c static int mtrr_save(struct sys_device * · line 580

Quoted 8 lines
arch/i386/kernel/cpu/mtrr/main.c +1 -1
-static int mtrr_save(struct sys_device * sysdev, u32 state)
+int mtrr_save(void)
 {
 	int i;
 	int size = num_var_ranges * sizeof(struct mtrr_value);
@@ -580,28 +579,27 @@ static int mtrr_save(struct sys_device *
 	return 0;
 }

Isn't this covered by Shaohua Li's patch?

Quoted 3 lines

I believe so, but Shaohua Li's patch isn't merged in 2.6.12 (is it yet at all). This is the solution I've been using for... can't remember how long.

I *think* it is in -mm already.
Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#46 lore raw

Re: [PATCH] [11/48] Suspend2 2.1.9.8 for 2.6.12: 401-e820-table-support.patch

In reply to Nigel Cunningham
Quoted 9 lines · Nigel Cunningham
Quoted 2 lines · Zwane Mwaikambo

Isn't this covered by Shaohua Li's patch?

I believe so, but Shaohua Li's patch isn't merged in 2.6.12 (is it yet at all). This is the solution I've been using for... can't remember how long.

Thanks for the feedback.

That's fine, i just want to make sure i know which parts can be used by your project too.

Thanks Nigel,
Zwane

#47 lore raw

PATCH 12/48 Suspend2 2.1.9.8 for 2.6.12: 402-mtrr-remove-sysdev.patch

In reply to Nigel Cunningham
arch/i386/mm/pageattr.c +41 -0
diff -ruNp 403-debug-pagealloc-support.patch-old/arch/i386/mm/pageattr.c 403-debug-pagealloc-support.patch-new/arch/i386/mm/pageattr.c
@@ -217,5 +217,46 @@ void kernel_map_pages(struct page *page,
 }
 #endif
 
+#ifdef CONFIG_SUSPEND2
+#ifdef CONFIG_DEBUG_PAGEALLOC
+static int page_is_kernel_mapped(struct page * page)
+{
+	pte_t *kpte; 
+	unsigned long address;
+
+	if (PageHighMem(page))
+		return 0;
+
+	address = (unsigned long)page_address(page);
+	
+	kpte = lookup_address(address);
+	if (!kpte)
+		return 0;
+
+	if (pte_same(*kpte, mk_pte(page, PAGE_KERNEL)))
+		return 1;
+
+	return 0;
+}
+
+int suspend_map_kernel_page(struct page * page, int enable)
+{
+	int is_already_mapped = page_is_kernel_mapped(page);
+
+	if (enable == is_already_mapped)
+		return 1;
+
+	kernel_map_pages(page, 1, enable);
+
+	return 0;
+}
+#else
+int suspend_map_kernel_page(struct page * page, int enable)
+{
+	return (enable == 1);
+}
+#endif
+#endif
+
 EXPORT_SYMBOL(change_page_attr);
 EXPORT_SYMBOL(global_flush_tlb);
#48 lore raw

Re: [PATCH] [12/48] Suspend2 2.1.9.8 for 2.6.12: 402-mtrr-remove-sysdev.patch

So what's this deep magic doing? And why do you add such crude function for debug pagealloc builds only?

#49 lore raw

Re: [PATCH] [12/48] Suspend2 2.1.9.8 for 2.6.12: 402-mtrr-remove-sysdev.patch

Hi.

Quoted 2 lines · Christoph Hellwig

So what's this deep magic doing? And why do you add such crude function for debug pagealloc builds only?

For debug_pagealloc, the pages we want to save and restore need to be mapped for the the atomic copy, and unmapped afterwards. This function achieves that.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#50 lore raw

PATCH 13/48 Suspend2 2.1.9.8 for 2.6.12: 403-debug-pagealloc-support.patch

In reply to Nigel Cunningham
drivers/usb/core/inode.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/drivers/usb/core/inode.c 404-check-mounts-support.patch-new/drivers/usb/core/inode.c
@@ -569,6 +569,7 @@ static struct file_system_type usb_fs_ty
 	.name =		"usbfs",
 	.get_sb =	usb_get_sb,
 	.kill_sb =	kill_litter_super,
+	.fs_flags =	FS_RW_S4_RESUME_SAFE,
 };
 
 /* --------------------------------------------------------------------- */
fs/block_dev.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/fs/block_dev.c 404-check-mounts-support.patch-new/fs/block_dev.c
@@ -310,6 +310,7 @@ static struct file_system_type bd_type =
 	.name		= "bdev",
 	.get_sb		= bd_get_sb,
 	.kill_sb	= kill_anon_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 
 static struct vfsmount *bd_mnt;
fs/debugfs/inode.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/fs/debugfs/inode.c 404-check-mounts-support.patch-new/fs/debugfs/inode.c
@@ -132,6 +132,7 @@ static struct file_system_type debug_fs_
 	.name =		"debugfs",
 	.get_sb =	debug_get_sb,
 	.kill_sb =	kill_litter_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 
 static int debugfs_create_by_name(const char *name, mode_t mode,
fs/devfs/base.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/fs/devfs/base.c 404-check-mounts-support.patch-new/fs/devfs/base.c
@@ -2560,6 +2560,7 @@ static struct file_system_type devfs_fs_
 	.name = DEVFS_NAME,
 	.get_sb = devfs_get_sb,
 	.kill_sb = kill_anon_super,
+	.fs_flags = FS_RW_S4_RESUME_SAFE,
 };
 
 /*  File operations for devfsd follow  */
fs/devpts/inode.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/fs/devpts/inode.c 404-check-mounts-support.patch-new/fs/devpts/inode.c
@@ -139,6 +139,7 @@ static struct file_system_type devpts_fs
 	.name		= "devpts",
 	.get_sb		= devpts_get_sb,
 	.kill_sb	= kill_anon_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 
 /*
fs/eventpoll.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/fs/eventpoll.c 404-check-mounts-support.patch-new/fs/eventpoll.c
@@ -348,6 +348,7 @@ static struct file_system_type eventpoll
 	.name		= "eventpollfs",
 	.get_sb		= eventpollfs_get_sb,
 	.kill_sb	= kill_anon_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 
 /* Very basic directory entry operations for the eventpoll virtual file system */
fs/hugetlbfs/inode.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/fs/hugetlbfs/inode.c 404-check-mounts-support.patch-new/fs/hugetlbfs/inode.c
@@ -728,6 +728,7 @@ static struct file_system_type hugetlbfs
 	.name		= "hugetlbfs",
 	.get_sb		= hugetlbfs_get_sb,
 	.kill_sb	= kill_litter_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 
 static struct vfsmount *hugetlbfs_vfsmount;
fs/nfs/inode.c +1 -1
diff -ruNp 404-check-mounts-support.patch-old/fs/nfs/inode.c 404-check-mounts-support.patch-new/fs/nfs/inode.c
@@ -1490,7 +1490,7 @@ static struct file_system_type nfs_fs_ty
 	.name		= "nfs",
 	.get_sb		= nfs_get_sb,
 	.kill_sb	= nfs_kill_super,
-	.fs_flags	= FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+	.fs_flags	= FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA|FS_RW_S4_RESUME_SAFE,
 };
 
 #ifdef CONFIG_NFS_V4
fs/pipe.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/fs/pipe.c 404-check-mounts-support.patch-new/fs/pipe.c
@@ -810,6 +810,7 @@ static struct file_system_type pipe_fs_t
 	.name		= "pipefs",
 	.get_sb		= pipefs_get_sb,
 	.kill_sb	= kill_anon_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 
 static int __init init_pipe_fs(void)
fs/proc/root.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/fs/proc/root.c 404-check-mounts-support.patch-new/fs/proc/root.c
@@ -34,6 +34,7 @@ static struct file_system_type proc_fs_t
 	.name		= "proc",
 	.get_sb		= proc_get_sb,
 	.kill_sb	= kill_anon_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 
 extern int __init proc_init_inodecache(void);
fs/ramfs/inode.c +2 -0
diff -ruNp 404-check-mounts-support.patch-old/fs/ramfs/inode.c 404-check-mounts-support.patch-new/fs/ramfs/inode.c
@@ -218,11 +218,13 @@ static struct file_system_type ramfs_fs_
 	.name		= "ramfs",
 	.get_sb		= ramfs_get_sb,
 	.kill_sb	= kill_litter_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 static struct file_system_type rootfs_fs_type = {
 	.name		= "rootfs",
 	.get_sb		= rootfs_get_sb,
 	.kill_sb	= kill_litter_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 
 static int __init init_ramfs_fs(void)
fs/super.c +62 -0

68 lines not on this page · raw message

fs/sysfs/mount.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/fs/sysfs/mount.c 404-check-mounts-support.patch-new/fs/sysfs/mount.c
@@ -74,6 +74,7 @@ static struct file_system_type sysfs_fs_
 	.name		= "sysfs",
 	.get_sb		= sysfs_get_sb,
 	.kill_sb	= kill_litter_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 
 int __init sysfs_init(void)
include/linux/fs.h +4 -0
diff -ruNp 404-check-mounts-support.patch-old/include/linux/fs.h 404-check-mounts-support.patch-new/include/linux/fs.h
@@ -81,6 +81,7 @@ extern int dir_notify_enable;
 /* public flags for file_system_type */
 #define FS_REQUIRES_DEV 1 
 #define FS_BINARY_MOUNTDATA 2
+#define FS_RW_S4_RESUME_SAFE 4 /* Can this FS be safely mounted RW when we're doing S4 resume? */
 #define FS_REVAL_DOT	16384	/* Check the paths ".", ".." for staleness */
 #define FS_ODD_RENAME	32768	/* Temporary stuff; will go away as soon
 				  * as nfs_rename() will be cleaned up
@@ -1199,6 +1200,9 @@ int __put_super(struct super_block *sb);
 int __put_super_and_need_restart(struct super_block *sb);
 void unnamed_dev_init(void);
 
+extern int mounts_are_S4_resume_safe(void);
+extern void get_S4_resume_unsafe_mounts(char * buffer, int buffer_size);
+
 /* Alas, no aliases. Too much hassle with bringing module.h everywhere */
 #define fops_get(fops) \
 	(((fops) && try_module_get((fops)->owner) ? (fops) : NULL))
ipc/mqueue.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/ipc/mqueue.c 404-check-mounts-support.patch-new/ipc/mqueue.c
@@ -1149,6 +1149,7 @@ static struct file_system_type mqueue_fs
 	.name = "mqueue",
 	.get_sb = mqueue_get_sb,
 	.kill_sb = kill_litter_super,
+	.fs_flags = FS_RW_S4_RESUME_SAFE,
 };
 
 static int msg_max_limit_min = DFLT_MSGMAX;
kernel/futex.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/kernel/futex.c 404-check-mounts-support.patch-new/kernel/futex.c
@@ -781,6 +781,7 @@ static struct file_system_type futex_fs_
 	.name		= "futexfs",
 	.get_sb		= futexfs_get_sb,
 	.kill_sb	= kill_anon_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 
 static int __init init(void)
mm/shmem.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/mm/shmem.c 404-check-mounts-support.patch-new/mm/shmem.c
@@ -2203,6 +2203,7 @@ static struct file_system_type tmpfs_fs_
 	.name		= "tmpfs",
 	.get_sb		= shmem_get_sb,
 	.kill_sb	= kill_litter_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 static struct vfsmount *shm_mnt;
 
mm/tiny-shmem.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/mm/tiny-shmem.c 404-check-mounts-support.patch-new/mm/tiny-shmem.c
@@ -25,6 +25,7 @@ static struct file_system_type tmpfs_fs_
 	.name		= "tmpfs",
 	.get_sb		= ramfs_get_sb,
 	.kill_sb	= kill_litter_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 
 static struct vfsmount *shm_mnt;
net/socket.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/net/socket.c 404-check-mounts-support.patch-new/net/socket.c
@@ -336,6 +336,7 @@ static struct file_system_type sock_fs_t
 	.name =		"sockfs",
 	.get_sb =	sockfs_get_sb,
 	.kill_sb =	kill_anon_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 static int sockfs_delete_dentry(struct dentry *dentry)
 {
net/sunrpc/rpc_pipe.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/net/sunrpc/rpc_pipe.c 404-check-mounts-support.patch-new/net/sunrpc/rpc_pipe.c
@@ -796,6 +796,7 @@ static struct file_system_type rpc_pipe_
 	.name		= "rpc_pipefs",
 	.get_sb		= rpc_get_sb,
 	.kill_sb	= kill_litter_super,
+	.fs_flags 	= FS_RW_S4_RESUME_SAFE,
 };
 
 static void
security/selinux/selinuxfs.c +1 -0
diff -ruNp 404-check-mounts-support.patch-old/security/selinux/selinuxfs.c 404-check-mounts-support.patch-new/security/selinux/selinuxfs.c
@@ -1308,6 +1308,7 @@ static struct file_system_type sel_fs_ty
 	.name		= "selinuxfs",
 	.get_sb		= sel_get_sb,
 	.kill_sb	= kill_litter_super,
+	.fs_flags	= FS_RW_S4_RESUME_SAFE,
 };
 
 struct vfsmount *selinuxfs_mount;
#51 lore raw

Re: [PATCH] [13/48] Suspend2 2.1.9.8 for 2.6.12: 403-debug-pagealloc-support.patch

this is missing a description. But I don't think that one is gonna help, we're not gonna add truckloads of crap just to print a warning when a user shoots himself in his foot.

#52 lore raw

Re: [PATCH] [13/48] Suspend2 2.1.9.8 for 2.6.12: 403-debug-pagealloc-support.patch

Hi.

Quoted 3 lines · Christoph Hellwig

this is missing a description. But I don't think that one is gonna help, we're not gonna add truckloads of crap just to print a warning when a user shoots himself in his foot.

I would like to improve this so we actually check the mount time for the filesystems, but this was a simpler intermediate step.

It may seem superfluous to you, but Suspend2 has over 12,000 users, and not all of them are expert users. Not everyone gets it right first time.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#53 lore raw

PATCH 14/48 Suspend2 2.1.9.8 for 2.6.12: 404-check-mounts-support.patch

In reply to Nigel Cunningham
mm/swapfile.c +1 -0
diff -ruNp 405-clear-swapfile-bdev-in-swapoff.patch-old/mm/swapfile.c 405-clear-swapfile-bdev-in-swapoff.patch-new/mm/swapfile.c
@@ -1162,6 +1162,7 @@ asmlinkage long sys_swapoff(const char _
 	swap_file = p->swap_file;
 	p->swap_file = NULL;
 	p->max = 0;
+	p->bdev = NULL;
 	swap_map = p->swap_map;
 	p->swap_map = NULL;
 	p->flags = 0;
#54 lore raw

Re: [PATCH] [14/48] Suspend2 2.1.9.8 for 2.6.12: 404-check-mounts-support.patch

mm/swapfile.c asmlinkage long sys_swapoff(const char _ · line 1168

Quoted 11 lines · Nigel Cunningham

diff -ruNp 405-clear-swapfile-bdev-in-swapoff.patch-old/mm/swapfile.c 405-clear-swapfile-bdev-in-swapoff.patch-new/mm/swapfile.c

mm/swapfile.c +1 -0
@@ -1162,6 +1162,7 @@ asmlinkage long sys_swapoff(const char _
 	swap_file = p->swap_file;
 	p->swap_file = NULL;
 	p->max = 0;
+	p->bdev = NULL;
 	swap_map = p->swap_map;
 	p->swap_map = NULL;
 	p->flags = 0;

I guess some explanation is needed here; and if it is bugfix it should just go in...
Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#55 lore raw

Re: [PATCH] [14/48] Suspend2 2.1.9.8 for 2.6.12: 404-check-mounts-support.patch

Hi.

Sorry.

It's not really a bug in the swapoff code. Rather, clearing this field allows simple identification of the devices being used for swap (for flushing writes).

Regards,

Nigel

Quoted 16 lines · Pavel Machek

mm/swapfile.c asmlinkage long sys_swapoff(const char _ · line 1168

Quoted 11 lines · Nigel Cunningham

diff -ruNp 405-clear-swapfile-bdev-in-swapoff.patch-old/mm/swapfile.c 405-clear-swapfile-bdev-in-swapoff.patch-new/mm/swapfile.c

mm/swapfile.c +1 -0
@@ -1162,6 +1162,7 @@ asmlinkage long sys_swapoff(const char _
 	swap_file = p->swap_file;
 	p->swap_file = NULL;
 	p->max = 0;
+	p->bdev = NULL;
 	swap_map = p->swap_map;
 	p->swap_map = NULL;
 	p->flags = 0;

I guess some explanation is needed here; and if it is bugfix it should just go in...
Pavel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#56 lore raw

PATCH 15/48 Suspend2 2.1.9.8 for 2.6.12: 405-clear-swapfile-bdev-in-swapoff.patch

In reply to Nigel Cunningham
include/linux/dyn_pageflags.h +63 -0
diff -ruNp 406-dynamic-pageflags.patch-old/include/linux/dyn_pageflags.h 406-dynamic-pageflags.patch-new/include/linux/dyn_pageflags.h
@@ -0,0 +1,63 @@
+/*
+ * include/linux/dyn_pageflags.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * It implements support for dynamically allocated bitmaps that are
+ * used for temporary or infrequently used pageflags, in lieu of
+ * bits in the struct page flags entry.
+ */
+
+#ifndef DYN_PAGEFLAGS_H
+#define DYN_PAGEFLAGS_H
+
+#include <linux/mm.h>
+
+typedef unsigned long ** dyn_pageflags_t;
+
+#define BITNUMBER(page) (page_to_pfn(page))
+
+#define PAGEBIT(page) ((int) ((page_to_pfn(page))%(8 * sizeof(unsigned long))))
+
+#define BITS_PER_PAGE (PAGE_SIZE * 8)
+#define PAGES_PER_BITMAP ((max_mapnr + BITS_PER_PAGE - 1) / BITS_PER_PAGE)
+#define PAGENUMBER(page) (BITNUMBER(page) / BITS_PER_PAGE)
+
+#define PAGEINDEX(page) ((BITNUMBER(page) - (BITS_PER_PAGE * PAGENUMBER(page)))/(8*sizeof(unsigned long)))
+
+#define PAGE_UL_PTR(bitmap, pagenum) ((bitmap[PAGENUMBER(pagenum)])+PAGEINDEX(pagenum))
+
+#define __get_next_bit_on_safe(bitmap, counter) \
+	do { \
+		(counter)++; \
+	} while(((counter) < max_mapnr) && \
+		(!test_bit(PAGEBIT(pfn_to_page((counter))), \
+			PAGE_UL_PTR(bitmap, pfn_to_page((counter))))));
+
+static inline int __get_next_bit_on(dyn_pageflags_t bitmap, int counter)
+{
+	do {
+		counter++;
+	} while((counter < max_mapnr) &&
+		(!test_bit(PAGEBIT(pfn_to_page(counter)),
+			PAGE_UL_PTR(bitmap, pfn_to_page(counter)))));
+	return counter;
+}
+
+/* With the above macros defined, you can do...
+
+#define PageInUse(page)	\
+	test_bit(PAGEBIT(page), PAGE_UL_PTR(in_use_map, page))
+#define SetPageInUse(page) \
+	set_bit(PAGEBIT(page), PAGE_UL_PTR(in_use_map, page))
+#define ClearPageInUse(page) \
+	clear_bit(PAGEBIT(page), PAGE_UL_PTR(in_use_map, page))
+*/
+
+extern void clear_dyn_pageflags(dyn_pageflags_t pagemap);
+extern int allocate_dyn_pageflags(dyn_pageflags_t *pagemap);
+extern int free_dyn_pageflags(dyn_pageflags_t *pagemap);
+
+#endif
lib/dyn_pageflags.c +78 -0

78 lines not on this page · raw message

lib/Makefile +1 -1
diff -ruNp 406-dynamic-pageflags.patch-old/lib/Makefile 406-dynamic-pageflags.patch-new/lib/Makefile
@@ -8,7 +8,7 @@ lib-y := errno.o ctype.o string.o vsprin
 	 bitmap.o extable.o kobject_uevent.o prio_tree.o sha1.o \
 	 halfmd4.o
 
-obj-y += sort.o parser.o
+obj-y += sort.o parser.o dyn_pageflags.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG
#57 lore raw

PATCH 16/48 Suspend2 2.1.9.8 for 2.6.12: 406-dynamic-pageflags.patch

In reply to Nigel Cunningham
arch/i386/power/Makefile +1 -1
diff -ruNp 500-version-specific-i386.patch-old/arch/i386/power/Makefile 500-version-specific-i386.patch-new/arch/i386/power/Makefile
@@ -1,2 +1,2 @@
-obj-$(CONFIG_PM)		+= cpu.o
+obj-$(CONFIG_PM)		+= cpu.o smp.o
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o
arch/i386/power/smp.c +84 -0

84 lines not on this page · raw message

include/asm-i386/suspend2.h +391 -0

391 lines not on this page · raw message

include/asm-i386/suspend.h +1 -0
diff -ruNp 500-version-specific-i386.patch-old/include/asm-i386/suspend.h 500-version-specific-i386.patch-new/include/asm-i386/suspend.h
@@ -3,6 +3,7 @@
  * Based on code
  * Copyright 2001 Patrick Mochel <[email protected]>
  */
+#include <linux/errno.h>
 #include <asm/desc.h>
 #include <asm/i387.h>
 
#58 lore raw

Re: [PATCH] [16/48] Suspend2 2.1.9.8 for 2.6.12: 406-dynamic-pageflags.patch

Quoted 60 lines · Nigel Cunningham
arch/i386/power/smp.c +60 -0
+
+/*
+ * Save and restore processor state for secondary processors.
+ * IRQs (and therefore preemption) are already disabled 
+ * when we enter here (IPI).
+ */
+
+static volatile int loop __nosavedata;
+
+void __smp_suspend_lowlevel(void * data)
+{
+	__asm__( "movl %%ecx,%%cr3\n" ::"c"(__pa(swsusp_pg_dir)));
+
+	if (test_suspend_state(SUSPEND_NOW_RESUMING)) {
+		BUG_ON(!irqs_disabled());
+		kernel_fpu_begin();
+		c_loops_per_jiffy_ref[_smp_processor_id()] = current_cpu_data.loops_per_jiffy;
+		atomic_inc(&suspend_cpu_counter);
+
+		/* Only image copied back while we spin in this loop. Our
+		 * task info should not be looked at while this is happening
+		 * (which smp_processor_id() will do( */
+		while (test_suspend_state(SUSPEND_FREEZE_SMP)) { 
+			cpu_relax();
+			barrier();
+		}
+
+		while (atomic_read(&suspend_cpu_counter) != _smp_processor_id()) {
+			cpu_relax();
+			barrier();
+		}
+	       	my_saved_context = (unsigned char *) (suspend2_saved_contexts + _smp_processor_id());
+		for (loop = sizeof(struct suspend2_saved_context); loop--; loop)
+			*(((unsigned char *) &suspend2_saved_context) + loop - 1) = *(my_saved_context + loop - 1);
+		suspend2_restore_processor_context();
+		cpu_clear(_smp_processor_id(), per_cpu(cpu_tlbstate, _smp_processor_id()).active_mm->cpu_vm_mask);
+		load_cr3(swapper_pg_dir);
+		wbinvd();
+		__flush_tlb_all();
+		current_cpu_data.loops_per_jiffy = c_loops_per_jiffy_ref[_smp_processor_id()];
+		mtrr_restore_one_cpu();
+		atomic_dec(&suspend_cpu_counter);
+	} else {	/* suspending */
+		BUG_ON(!irqs_disabled());
+		/* 
+		 *Save context and go back to idling.
+		 * Note that we cannot leave the processor
+		 * here. It must be able to receive IPIs if
+		 * the LZF compression driver (eg) does a
+		 * vfree after compressing the kernel etc
+		 */
+		while (test_suspend_state(SUSPEND_FREEZE_SMP) &&
+			(atomic_read(&suspend_cpu_counter) != (_smp_processor_id() - 1))) {
+			cpu_relax();
+			barrier();
+		}
+		suspend2_save_processor_context();
+		my_saved_context = (unsigned char *) (suspend2_saved_contexts + _smp_processor_id());
+		for (loop = sizeof(struct suspend2_saved_context); loop--; loop)
+			*(my_saved_context + loop - 1) = *(((unsigned char *) &suspend2_saved_context) + loop - 1);

arch/i386/power/smp.c line 83

Quoted 10 lines
arch/i386/power/smp.c +10 -0
+		atomic_inc(&suspend_cpu_counter);
+		/* Now spin until the atomic copy of the kernel is made. */
+		while (test_suspend_state(SUSPEND_FREEZE_SMP)) {
+			cpu_relax();
+			barrier();
+		}
+		atomic_dec(&suspend_cpu_counter);
+		kernel_fpu_end();
+	}
+}

we are using cpu hotplug for S3 & S4 SMP to avoid nasty deadlocks. Could this be avoided in suspend2 SMP?

Thanks,
Shaohua

#59 lore raw

Re: [PATCH] [16/48] Suspend2 2.1.9.8 for 2.6.12: 406-dynamic-pageflags.patch

Hi.

Quoted 2 lines · Shaohua Li

we are using cpu hotplug for S3 & S4 SMP to avoid nasty deadlocks. Could this be avoided in suspend2 SMP?

I haven't had any problems with this code but yes, I do want to switch to using hotplug. It's only in -mm, not mainline?

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#60 lore raw

Re: [PATCH] [16/48] Suspend2 2.1.9.8 for 2.6.12: 406-dynamic-pageflags.patch

Quoted 8 lines · Nigel Cunningham

Hi.

Quoted 2 lines · Shaohua Li

we are using cpu hotplug for S3 & S4 SMP to avoid nasty deadlocks. Could this be avoided in suspend2 SMP?

I haven't had any problems with this code but yes, I do want to switch to using hotplug. It's only in -mm, not mainline?

It's in base kernel now.

Thanks,
Shaohua

#61 lore raw

PATCH 17/48 Suspend2 2.1.9.8 for 2.6.12: 500-version-specific-i386.patch

In reply to Nigel Cunningham
arch/i386/kernel/smp.c +1 -1
diff -ruNp 501-tlb-flushing-functions.patch-old/arch/i386/kernel/smp.c 501-tlb-flushing-functions.patch-new/arch/i386/kernel/smp.c
@@ -476,7 +476,7 @@ void flush_tlb_page(struct vm_area_struc
 	preempt_enable();
 }
 
-static void do_flush_tlb_all(void* info)
+void do_flush_tlb_all(void* info)
 {
 	unsigned long cpu = smp_processor_id();
 
include/asm-i386/tlbflush.h +5 -0
diff -ruNp 501-tlb-flushing-functions.patch-old/include/asm-i386/tlbflush.h 501-tlb-flushing-functions.patch-new/include/asm-i386/tlbflush.h
@@ -82,6 +82,7 @@ extern unsigned long pgkern_mask;
 #define flush_tlb() __flush_tlb()
 #define flush_tlb_all() __flush_tlb_all()
 #define local_flush_tlb() __flush_tlb()
+#define local_flush_tlb_all() __flush_tlb_all();
 
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
@@ -114,6 +115,10 @@ extern void flush_tlb_all(void);
 extern void flush_tlb_current_task(void);
 extern void flush_tlb_mm(struct mm_struct *);
 extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
+extern void do_flush_tlb_all(void * info);
+
+#define local_flush_tlb_all() \
+	do_flush_tlb_all(NULL);
 
 #define flush_tlb()	flush_tlb_current_task()
 
#62 lore raw

Re: [PATCH] [17/48] Suspend2 2.1.9.8 for 2.6.12: 500-version-specific-i386.patch

In article <[email protected]> (at Wed, 6 Jul 2005 12:20:41 +1000), Nigel Cunningham <[email protected]> says:

Quoted 2 lines

#define local_flush_tlb() __flush_tlb()
+#define local_flush_tlb_all() __flush_tlb_all();

You should remove ";".

include/asm-i386/tlbflush.h extern void flush_tlb_all(void); · line 121

Quoted 6 lines

extern void flush_tlb_page(struct vm_area_struct *, unsigned long);

include/asm-i386/tlbflush.h +4 -0
+extern void do_flush_tlb_all(void * info);
+
+#define local_flush_tlb_all() \
+	do_flush_tlb_all(NULL);

ditto

--yoshfuji

#63 lore raw

PATCH 18/48 Suspend2 2.1.9.8 for 2.6.12: 501-tlb-flushing-functions.patch

In reply to Nigel Cunningham
arch/ppc/Kconfig +1 -1
diff -ruNp 510-version-specific-mac.patch-old/arch/ppc/Kconfig 510-version-specific-mac.patch-new/arch/ppc/Kconfig
@@ -1081,7 +1081,7 @@ config PROC_HARDWARE
 
 source "drivers/zorro/Kconfig"
 
-source kernel/power/Kconfig
+source "kernel/power/Kconfig"
 
 endmenu
 
arch/ppc/kernel/signal.c +9 -0
diff -ruNp 510-version-specific-mac.patch-old/arch/ppc/kernel/signal.c 510-version-specific-mac.patch-new/arch/ppc/kernel/signal.c
@@ -711,6 +711,15 @@ int do_signal(sigset_t *oldset, struct p
 			goto no_signal;
 	}
 
+	if (freezing(current)) {
+		try_to_freeze();
+		signr = 0;
+		ret = regs->gpr[3];
+		recalc_sigpending();
+		if (!signal_pending(current))
+			goto no_signal;
+	}
+
 	if (!oldset)
 		oldset = &current->blocked;
 
arch/ppc/kernel/swsusp.c +88 -0

88 lines not on this page · raw message

arch/ppc/kernel/vmlinux.lds.S +6 -0
diff -ruNp 510-version-specific-mac.patch-old/arch/ppc/kernel/vmlinux.lds.S 510-version-specific-mac.patch-new/arch/ppc/kernel/vmlinux.lds.S
@@ -80,6 +80,12 @@ SECTIONS
   . = ALIGN(4096);
   __nosave_end = .;
 
+  . = ALIGN(4096);
+  __nosave_begin = .;
+  .data_nosave : { *(.data.nosave) }
+  . = ALIGN(4096);
+  __nosave_end = .;
+
   . = ALIGN(32);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
arch/ppc/mm/init.c +13 -1
diff -ruNp 510-version-specific-mac.patch-old/arch/ppc/mm/init.c 510-version-specific-mac.patch-new/arch/ppc/mm/init.c
@@ -32,6 +32,7 @@
 #include <linux/highmem.h>
 #include <linux/initrd.h>
 #include <linux/pagemap.h>
+#include <linux/suspend.h>
 
 #include <asm/pgalloc.h>
 #include <asm/prom.h>
@@ -150,6 +151,7 @@ static void free_sec(unsigned long start
 
 	while (start < end) {
 		ClearPageReserved(virt_to_page(start));
+		ClearPageNosave(virt_to_page(start));
 		set_page_count(virt_to_page(start), 1);
 		free_page(start);
 		cnt++;
@@ -190,6 +192,7 @@ void free_initrd_mem(unsigned long start
 
 	for (; start < end; start += PAGE_SIZE) {
 		ClearPageReserved(virt_to_page(start));
+		ClearPageNosave(virt_to_page(start));
 		set_page_count(virt_to_page(start), 1);
 		free_page(start);
 		totalram_pages++;
@@ -425,8 +428,10 @@ void __init mem_init(void)
 	/* if we are booted from BootX with an initial ramdisk,
 	   make sure the ramdisk pages aren't reserved. */
 	if (initrd_start) {
-		for (addr = initrd_start; addr < initrd_end; addr += PAGE_SIZE)
+		for (addr = initrd_start; addr < initrd_end; addr += PAGE_SIZE) {
 			ClearPageReserved(virt_to_page(addr));
+			ClearPageNosave(virt_to_page(addr));
+		}
 	}
 #endif /* CONFIG_BLK_DEV_INITRD */
 
@@ -452,6 +457,12 @@ void __init mem_init(void)
 	     addr += PAGE_SIZE) {
 		if (!PageReserved(virt_to_page(addr)))
 			continue;
+		/*
+		 * Mark nosave pages
+		 */
+		if (addr >= (void *)&__nosave_begin && addr < (void *)&__nosave_end)
+			SetPageNosave(virt_to_page(addr));
+
 		if (addr < (ulong) etext)
 			codepages++;
 		else if (addr >= (unsigned long)&__init_begin
@@ -469,6 +480,7 @@ void __init mem_init(void)
 			struct page *page = mem_map + pfn;
 
 			ClearPageReserved(page);
+			ClearPageNosave(page);
 			set_bit(PG_highmem, &page->flags);
 			set_page_count(page, 1);
 			__free_page(page);
arch/ppc/platforms/pmac_feature.c +4 -1
diff -ruNp 510-version-specific-mac.patch-old/arch/ppc/platforms/pmac_feature.c 510-version-specific-mac.patch-new/arch/ppc/platforms/pmac_feature.c
@@ -2291,7 +2291,10 @@ static struct pmac_mb_def pmac_mb_defs[]
 	},
 	{	"PowerBook5,1",			"PowerBook G4 17\"",
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
-		PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+		PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+#ifdef CONFIG_SOFTWARE_REPLACE_SLEEP
+		| PMAC_MB_CAN_SLEEP,
+#endif
 	},
 	{	"PowerBook5,2",			"PowerBook G4 15\"",
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
arch/ppc/syslib/of_device.c +1 -1
diff -ruNp 510-version-specific-mac.patch-old/arch/ppc/syslib/of_device.c 510-version-specific-mac.patch-new/arch/ppc/syslib/of_device.c
@@ -104,7 +104,7 @@ static int of_device_remove(struct devic
 	return 0;
 }
 
-static int of_device_suspend(struct device *dev, u32 state)
+static int of_device_suspend(struct device *dev, pm_message_t state)
 {
 	struct of_device * of_dev = to_of_device(dev);
 	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
drivers/macintosh/Kconfig +4 -0
diff -ruNp 510-version-specific-mac.patch-old/drivers/macintosh/Kconfig 510-version-specific-mac.patch-new/drivers/macintosh/Kconfig
@@ -195,4 +195,8 @@ config ANSLCD
 	tristate "Support for ANS LCD display"
 	depends on ADB_CUDA && PPC_PMAC
 
+config SOFTWARE_REPLACE_SLEEP
+	bool "Using Software suspend replace broken sleep function"
+	depends on SOFTWARE_SUSPEND2
+
 endmenu
drivers/macintosh/via-pmu.c +7 -0
diff -ruNp 510-version-specific-mac.patch-old/drivers/macintosh/via-pmu.c 510-version-specific-mac.patch-new/drivers/macintosh/via-pmu.c
@@ -2894,6 +2894,13 @@ pmu_ioctl(struct inode * inode, struct f
 			return -EACCES;
 		if (sleep_in_progress)
 			return -EBUSY;
+#ifdef CONFIG_SOFTWARE_REPLACE_SLEEP
+		{
+		extern void software_suspend_pending(void);
+		software_suspend_pending();
+		return (0);
+		}
+#endif
 		sleep_in_progress = 1;
 		switch (pmu_kind) {
 		case PMU_OHARE_BASED:
include/asm-ppc/cpu_context.h +98 -0

98 lines not on this page · raw message

include/asm-ppc/suspend2.h +74 -0

74 lines not on this page · raw message

kernel/kthread.c +0 -4
diff -ruNp 510-version-specific-mac.patch-old/kernel/kthread.c 510-version-specific-mac.patch-new/kernel/kthread.c
@@ -94,10 +94,6 @@ static int kthread(void *_create)
 	current->flags |= flags_used;
 	atomic_set(&(current->freeze_status), 0);
 
-	/* Set our freezer flags */
-	current->flags &= ~(PF_SYNCTHREAD | PF_NOFREEZE);
-	current->flags |= create->freezer_flags;
-
 	/* OK, tell user we're spawned, wait for stop or wakeup */
 	__set_current_state(TASK_INTERRUPTIBLE);
 	complete(&create->started);
#64 lore raw

Re: [PATCH] [18/48] Suspend2 2.1.9.8 for 2.6.12: 501-tlb-flushing-functions.patch

Hi!

arch/ppc/platforms/pmac_feature.c static struct pmac_mb_def pmac_mb_defs[] · line 2297

Quoted 12 lines

diff -ruNp 510-version-specific-mac.patch-old/arch/ppc/platforms/pmac_feature.c 510-version-specific-mac.patch-new/arch/ppc/platforms/pmac_feature.c

arch/ppc/platforms/pmac_feature.c +4 -1
@@ -2291,7 +2291,10 @@ static struct pmac_mb_def pmac_mb_defs[]
 	},
 	{	"PowerBook5,1",			"PowerBook G4 17\"",
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
-		PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+		PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
+#ifdef CONFIG_SOFTWARE_REPLACE_SLEEP
+		| PMAC_MB_CAN_SLEEP,
+#endif

There's different number of ","s depending on CONFIG_... Is that ok?

arch/ppc/syslib/of_device.c static int of_device_remove(struct devic · line 110

Quoted 12 lines

diff -ruNp 510-version-specific-mac.patch-old/arch/ppc/syslib/of_device.c 510-version-specific-mac.patch-new/arch/ppc/syslib/of_device.c

arch/ppc/syslib/of_device.c +1 -1
@@ -104,7 +104,7 @@ static int of_device_remove(struct devic
 	return 0;
 }
 
-static int of_device_suspend(struct device *dev, u32 state)
+static int of_device_suspend(struct device *dev, pm_message_t state)
 {
 	struct of_device * of_dev = to_of_device(dev);
 	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);

Can I have these separately?

Quoted 7 lines

diff -ruNp 510-version-specific-mac.patch-old/drivers/macintosh/via-pmu.c 510-version-specific-mac.patch-new/drivers/macintosh/via-pmu.c

drivers/macintosh/via-pmu.c +0 -0
@@ -2894,6 +2894,13 @@ pmu_ioctl(struct inode * inode, struct f
 			return -EACCES;
 		if (sleep_in_progress)
 			return -EBUSY;

drivers/macintosh/via-pmu.c pmu_ioctl(struct inode * inode, struct f · line 2906

Quoted 10 lines
drivers/macintosh/via-pmu.c +7 -0
+#ifdef CONFIG_SOFTWARE_REPLACE_SLEEP
+		{
+		extern void software_suspend_pending(void);
+		software_suspend_pending();
+		return (0);
+		}
+#endif
 		sleep_in_progress = 1;
 		switch (pmu_kind) {
 		case PMU_OHARE_BASED:

Indentation? And use return 0; not return (0);

Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#65 lore raw

PATCH 19/48 Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch

In reply to Nigel Cunningham
arch/x86_64/kernel/asm-offsets.c +2 -0
diff -ruNp 520-version-specific-x86_64.patch-old/arch/x86_64/kernel/asm-offsets.c 520-version-specific-x86_64.patch-new/arch/x86_64/kernel/asm-offsets.c
@@ -62,8 +62,10 @@ int main(void)
 	       offsetof (struct rt_sigframe32, uc.uc_mcontext));
 	BLANK();
 #endif
+#ifdef CONFIG_PM
 	DEFINE(pbe_address, offsetof(struct pbe, address));
 	DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
 	DEFINE(pbe_next, offsetof(struct pbe, next));
+#endif
 	return 0;
 }
arch/x86_64/kernel/Makefile +1 -0
diff -ruNp 520-version-specific-x86_64.patch-old/arch/x86_64/kernel/Makefile 520-version-specific-x86_64.patch-new/arch/x86_64/kernel/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o m
 		genapic.o genapic_cluster.o genapic_flat.o
 obj-$(CONFIG_PM)		+= suspend.o
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= suspend_asm.o
+obj-$(CONFIG_SUSPEND2)		+= suspend2.o
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 obj-$(CONFIG_GART_IOMMU)	+= pci-gart.o aperture.o
arch/x86_64/kernel/suspend.c +3 -0
diff -ruNp 520-version-specific-x86_64.patch-old/arch/x86_64/kernel/suspend.c 520-version-specific-x86_64.patch-new/arch/x86_64/kernel/suspend.c
@@ -26,6 +26,7 @@
 #include <asm/tlbflush.h>
 #include <asm/io.h>
 #include <asm/proto.h>
+#include <asm/i387.h>
 
 struct saved_context saved_context;
 
@@ -35,6 +36,8 @@ unsigned long saved_context_r08, saved_c
 unsigned long saved_context_r12, saved_context_r13, saved_context_r14, saved_context_r15;
 unsigned long saved_context_eflags;
 
+void fix_processor_context(void);
+
 void __save_processor_state(struct saved_context *ctxt)
 {
 	kernel_fpu_begin();
arch/x86_64/mm/init.c +19 -0
diff -ruNp 520-version-specific-x86_64.patch-old/arch/x86_64/mm/init.c 520-version-specific-x86_64.patch-new/arch/x86_64/mm/init.c
@@ -618,3 +618,22 @@ int in_gate_area_no_task(unsigned long a
 {
 	return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END);
 }
+
+#if defined(CONFIG_PM_DISK) || defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_SUSPEND2)
+/*
+ * Software suspend & friends need this for resume because things like the intel-agp
+ * driver might have split up a kernel 4MB mapping.
+ */
+char __nosavedata swsusp_pg_dir[PAGE_SIZE]
+	__attribute__ ((aligned (PAGE_SIZE)));
+
+static inline void save_pg_dir(void)
+{
+	memcpy(swsusp_pg_dir, swapper_pg_dir, PAGE_SIZE);
+}
+#else
+static inline void save_pg_dir(void)
+{
+}
+#endif
+
include/asm-x86_64/suspend2.h +432 -0

432 lines not on this page · raw message

include/asm-x86_64/suspend.h +1 -1
diff -ruNp 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend.h 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend.h
@@ -43,7 +43,7 @@ extern unsigned long saved_context_eflag
                        : /* no output */ \
                        :"r" ((thread)->debugreg##register))
 
-extern void fix_processor_context(void);
+/* extern void fix_processor_context(void); */
 
 #ifdef CONFIG_ACPI_SLEEP
 extern unsigned long saved_eip;
#66 lore raw

Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch

include/asm-x86_64/suspend2.h line 110

Quoted 4 lines · Nigel Cunningham
include/asm-x86_64/suspend2.h +4 -0
+	/*
+	 * eflags
+	 */
+	asm volatile ("pushfl ; popl (%0)" : "=m" (suspend2_saved_context.eflags));

To be future proof you probably want to do pushfq/popq

include/asm-x86_64/suspend2.h line 141

Quoted 8 lines
include/asm-x86_64/suspend2.h +8 -0
+
+	/*
+	 * control registers 
+	 */
+	asm volatile ("movl %%cr0, %0" : "=r" (suspend2_saved_context.cr0));
+	asm volatile ("movl %%cr2, %0" : "=r" (suspend2_saved_context.cr2));
+	asm volatile ("movl %%cr3, %0" : "=r" (suspend2_saved_context.cr3));
+	asm volatile ("movl %%cr4, %0" : "=r" (suspend2_saved_context.cr4));

I guess we don't have to worry about %cr8 for now?

Quoted 4 lines

+ * a little clearer, but it needs to be inlined because we won't have a
+ * stack when we get here (so we can't push a return address).
+ */

include/asm-x86_64/suspend2.h +1 -0
+static inline void restore_processor_context(void)

include/asm-x86_64/suspend2.h line 203

Quoted 10 lines
include/asm-x86_64/suspend2.h +10 -0
+{
+	/*
+	 * first restore %ds, so we can access our data properly
+	 */
+	//asm volatile ("movw %0, %%ds" :: "r" ((u16)__KERNEL_DS));
+	
+	__flush_tlb_global(); /* INLINE? */
+
+	asm volatile ("movl	$24, %eax");
+	asm volatile ("movl	%eax, %ds");

Shouldn't that be KERNEL_DS?

include/asm-x86_64/suspend2.h line 234

Quoted 1 line
include/asm-x86_64/suspend2.h +1 -0
+	asm volatile ("pushl %0 ; popfl" :: "m" (suspend2_saved_context.eflags));

pushq/popfq?

include/asm-x86_64/suspend2.h line 388

Quoted 13 lines
include/asm-x86_64/suspend2.h +13 -0
+	save_and_set_irq_affinity();
+	
+	c_loops_per_jiffy_ref[_smp_processor_id()] = current_cpu_data.loops_per_jiffy;
+#ifndef CONFIG_SMP
+	cpu_khz_ref = cpu_khz;
+	c_loops_per_jiffy_ref[_smp_processor_id()] = loops_per_jiffy;
+#endif
+	
+	/* We want to run from swsusp_pg_dir, since swsusp_pg_dir is stored in constant
+	 * place in memory 
+	 */
+
+        __asm__( "movl %%ecx,%%cr3\n" ::"c"(__pa(swsusp_pg_dir)));

This looks like it depends on the swsusp_pg_dir being in lower 32bit address space, shouldn't it be a movq %%rcx?

#67 lore raw

Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch

Hi.

I've just noticed that all the subject lines are off by one. Sorry. Shall I repost with it right this time?

Regarding this x86_64 patch, I haven't been able to test x86_64 support yet (no hardware here), so I'm sure you're right about all the things. I've really just parroted what swsusp does in its lowlevel code, since saving and restoring cpu state is one thing we do the same way.

Will apply changes.

Regards,

Nigel

Quoted 58 lines · Zwane Mwaikambo

include/asm-x86_64/suspend2.h line 110

Quoted 4 lines · Nigel Cunningham
include/asm-x86_64/suspend2.h +4 -0
+	/*
+	 * eflags
+	 */
+	asm volatile ("pushfl ; popl (%0)" : "=m" (suspend2_saved_context.eflags));

To be future proof you probably want to do pushfq/popq

include/asm-x86_64/suspend2.h line 141

Quoted 8 lines
include/asm-x86_64/suspend2.h +8 -0
+
+	/*
+	 * control registers 
+	 */
+	asm volatile ("movl %%cr0, %0" : "=r" (suspend2_saved_context.cr0));
+	asm volatile ("movl %%cr2, %0" : "=r" (suspend2_saved_context.cr2));
+	asm volatile ("movl %%cr3, %0" : "=r" (suspend2_saved_context.cr3));
+	asm volatile ("movl %%cr4, %0" : "=r" (suspend2_saved_context.cr4));

I guess we don't have to worry about %cr8 for now?

Quoted 4 lines

+ * a little clearer, but it needs to be inlined because we won't have a
+ * stack when we get here (so we can't push a return address).
+ */

include/asm-x86_64/suspend2.h +1 -0
+static inline void restore_processor_context(void)

include/asm-x86_64/suspend2.h line 203

Quoted 10 lines
include/asm-x86_64/suspend2.h +10 -0
+{
+	/*
+	 * first restore %ds, so we can access our data properly
+	 */
+	//asm volatile ("movw %0, %%ds" :: "r" ((u16)__KERNEL_DS));
+	
+	__flush_tlb_global(); /* INLINE? */
+
+	asm volatile ("movl	$24, %eax");
+	asm volatile ("movl	%eax, %ds");

Shouldn't that be KERNEL_DS?

include/asm-x86_64/suspend2.h line 234

Quoted 1 line
include/asm-x86_64/suspend2.h +1 -0
+	asm volatile ("pushl %0 ; popfl" :: "m" (suspend2_saved_context.eflags));

pushq/popfq?

include/asm-x86_64/suspend2.h line 388

Quoted 13 lines
include/asm-x86_64/suspend2.h +13 -0
+	save_and_set_irq_affinity();
+	
+	c_loops_per_jiffy_ref[_smp_processor_id()] = current_cpu_data.loops_per_jiffy;
+#ifndef CONFIG_SMP
+	cpu_khz_ref = cpu_khz;
+	c_loops_per_jiffy_ref[_smp_processor_id()] = loops_per_jiffy;
+#endif
+	
+	/* We want to run from swsusp_pg_dir, since swsusp_pg_dir is stored in constant
+	 * place in memory 
+	 */
+
+        __asm__( "movl %%ecx,%%cr3\n" ::"c"(__pa(swsusp_pg_dir)));

This looks like it depends on the swsusp_pg_dir being in lower 32bit address space, shouldn't it be a movq %%rcx?

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#68 lore raw

Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch

Quoted 2 lines · Nigel Cunningham

I've just noticed that all the subject lines are off by one. Sorry. Shall I repost with it right this time?

Yes the subject lines did look a bit confusing, it may be easier in future to add a short description of the patch instead of relying on the patch name.

Quoted 6 lines

Regarding this x86_64 patch, I haven't been able to test x86_64 support yet (no hardware here), so I'm sure you're right about all the things. I've really just parroted what swsusp does in its lowlevel code, since saving and restoring cpu state is one thing we do the same way.

Will apply changes.

Fair enough.

Thanks,
Zwane

#69 lore raw

Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch

In reply to Nigel Cunningham

Hi.

This patch came from Hu Gang.

Regards,

Nigel

Quoted 525 lines · Nigel Cunningham

diff -ruNp 520-version-specific-x86_64.patch-old/arch/x86_64/kernel/asm-offsets.c 520-version-specific-x86_64.patch-new/arch/x86_64/kernel/asm-offsets.c

arch/x86_64/kernel/asm-offsets.c +2 -0
@@ -62,8 +62,10 @@ int main(void)
 	       offsetof (struct rt_sigframe32, uc.uc_mcontext));
 	BLANK();
 #endif
+#ifdef CONFIG_PM
 	DEFINE(pbe_address, offsetof(struct pbe, address));
 	DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
 	DEFINE(pbe_next, offsetof(struct pbe, next));
+#endif
 	return 0;
 }

diff -ruNp 520-version-specific-x86_64.patch-old/arch/x86_64/kernel/Makefile 520-version-specific-x86_64.patch-new/arch/x86_64/kernel/Makefile

arch/x86_64/kernel/Makefile +1 -0
@@ -22,6 +22,7 @@ obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o m
 		genapic.o genapic_cluster.o genapic_flat.o
 obj-$(CONFIG_PM)		+= suspend.o
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= suspend_asm.o
+obj-$(CONFIG_SUSPEND2)		+= suspend2.o
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
 obj-$(CONFIG_GART_IOMMU)	+= pci-gart.o aperture.o

diff -ruNp 520-version-specific-x86_64.patch-old/arch/x86_64/kernel/suspend.c 520-version-specific-x86_64.patch-new/arch/x86_64/kernel/suspend.c

arch/x86_64/kernel/suspend.c +3 -0
@@ -26,6 +26,7 @@
 #include <asm/tlbflush.h>
 #include <asm/io.h>
 #include <asm/proto.h>
+#include <asm/i387.h>
 
 struct saved_context saved_context;
 
@@ -35,6 +36,8 @@ unsigned long saved_context_r08, saved_c
 unsigned long saved_context_r12, saved_context_r13, saved_context_r14, saved_context_r15;
 unsigned long saved_context_eflags;
 
+void fix_processor_context(void);
+
 void __save_processor_state(struct saved_context *ctxt)
 {
 	kernel_fpu_begin();

diff -ruNp 520-version-specific-x86_64.patch-old/arch/x86_64/mm/init.c 520-version-specific-x86_64.patch-new/arch/x86_64/mm/init.c

arch/x86_64/mm/init.c +19 -0
@@ -618,3 +618,22 @@ int in_gate_area_no_task(unsigned long a
 {
 	return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END);
 }
+
+#if defined(CONFIG_PM_DISK) || defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_SUSPEND2)
+/*
+ * Software suspend & friends need this for resume because things like the intel-agp
+ * driver might have split up a kernel 4MB mapping.
+ */
+char __nosavedata swsusp_pg_dir[PAGE_SIZE]
+	__attribute__ ((aligned (PAGE_SIZE)));
+
+static inline void save_pg_dir(void)
+{
+	memcpy(swsusp_pg_dir, swapper_pg_dir, PAGE_SIZE);
+}
+#else
+static inline void save_pg_dir(void)
+{
+}
+#endif
+

diff -ruNp 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend2.h 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend2.h

include/asm-x86_64/suspend2.h +432 -0
@@ -0,0 +1,432 @@
+ /*
+  * Copyright 2005 Nigel Cunningham <[email protected]>
+  * Based on code
+  * Copyright 2001-2002 Pavel Machek <[email protected]>
+  * Based on code
+  * Copyright 2001 Patrick Mochel <[email protected]>
+  */
+#include <linux/irq.h>
+#include <asm/desc.h>
+#include <asm/i387.h>
+#include <asm/tlbflush.h>
+#include <asm/desc.h>
+#include <asm/suspend.h>
+#undef inline
+#define inline	__inline__ __attribute__((always_inline))
+
+/* image of the saved processor states */
+struct suspend2_saved_context {
+	unsigned long eax, ebx, ecx, edx;
+	unsigned long esp, ebp, esi, edi;
+	unsigned long r8, r9, r10, r11;
+	unsigned long r12, r13, r14, r15;
+
+#if 0
+	u16 es, fs, gs, ss;
+	u32 cr0, cr2, cr3, cr4;
+	u16 gdt_pad;
+	u16 gdt_limit;
+	u32 gdt_base;
+	u16 idt_pad;
+	u16 idt_limit;
+	u32 idt_base;
+	u16 ldt;
+	u16 tss;
+	u32 tr;
+	u32 safety;
+	u32 return_address;
+#endif
+	unsigned long eflags;
+} __attribute__((packed));
+
+extern struct suspend2_saved_context suspend2_saved_context;	/* temporary storage */
+
+#ifdef CONFIG_MTRR
+/* MTRR functions */
+extern int mtrr_save(void);
+extern int mtrr_restore_one_cpu(void);
+extern void mtrr_restore_finish(void);
+#else
+#define mtrr_save() do { } while(0)
+#define mtrr_restore_one_cpu() do { } while(0)
+#define mtrr_restore_finish() do { } while(0)
+#endif
+		  
+#ifndef CONFIG_SMP
+#undef cpu_clear
+#define cpu_clear(a, b) do { } while(0)
+#endif
+
+extern struct suspend2_saved_context suspend2_saved_context;	/* temporary storage */
+
+/*
+ * save_processor_context
+ * 
+ * Save the state of the processor before we go to sleep.
+ *
+ * return_stack is the value of the stack pointer (%esp) as the caller sees it.
+ * A good way could not be found to obtain it from here (don't want to make _too_
+ * many assumptions about the layout of the stack this far down.) Also, the 
+ * handy little __builtin_frame_pointer(level) where level > 0, is blatantly 
+ * buggy - it returns the value of the stack at the proper location, not the 
+ * location, like it should (as of gcc 2.91.66)
+ * 
+ * Note that the context and timing of this function is pretty critical.
+ * With a minimal amount of things going on in the caller and in here, gcc
+ * does a good job of being just a dumb compiler.  Watch the assembly output
+ * if anything changes, though, and make sure everything is going in the right
+ * place. 
+ */
+static inline void suspend2_save_processor_context(void)
+{
+	/*
+	 * save the general registers.
+	 * note that gcc has constructs to specify output of certain registers,
+	 * but they're not used here, because it assumes that you want to modify
+	 * those registers, so it tries to be smart and save them beforehand.
+	 * It's really not necessary, and kinda fishy (check the assembly output),
+	 * so it's avoided. 
+	 */
+	asm volatile ("movl %%rsp, (%0)" : "=m" (suspend2_saved_context.esp));
+	asm volatile ("movl %%rax, (%0)" : "=m" (suspend2_saved_context.eax));
+	asm volatile ("movl %%rbx, (%0)" : "=m" (suspend2_saved_context.ebx));
+	asm volatile ("movl %%rcx, (%0)" : "=m" (suspend2_saved_context.ecx));
+	asm volatile ("movl %%rdx, (%0)" : "=m" (suspend2_saved_context.edx));
+	asm volatile ("movl %%rbp, (%0)" : "=m" (suspend2_saved_context.ebp));
+	asm volatile ("movl %%rsi, (%0)" : "=m" (suspend2_saved_context.esi));
+	asm volatile ("movl %%rdi, (%0)" : "=m" (suspend2_saved_context.edi));
+	asm volatile ("movl %%r8, (%0)" : "=m" (suspend2_saved_context.r8));
+	asm volatile ("movl %%r9, (%0)" : "=m" (suspend2_saved_context.r9));
+	asm volatile ("movl %%r10, (%0)" : "=m" (suspend2_saved_context.r10));
+	asm volatile ("movl %%r11, (%0)" : "=m" (suspend2_saved_context.r11));
+	asm volatile ("movl %%r12, (%0)" : "=m" (suspend2_saved_context.r12));
+	asm volatile ("movl %%r13, (%0)" : "=m" (suspend2_saved_context.r13));
+	asm volatile ("movl %%r14, (%0)" : "=m" (suspend2_saved_context.r14));
+	asm volatile ("movl %%r15, (%0)" : "=m" (suspend2_saved_context.r15));
+
+	/*
+	 * eflags
+	 */
+	asm volatile ("pushfl ; popl (%0)" : "=m" (suspend2_saved_context.eflags));
+
+	kernel_fpu_begin();
+
+	/*
+	 * descriptor tables
+	 */
+	asm volatile ("sgdt (%0)" : "=m" (suspend2_saved_context.gdt_limit));
+	asm volatile ("sidt (%0)" : "=m" (suspend2_saved_context.idt_limit));
+	asm volatile ("sldt (%0)" : "=m" (suspend2_saved_context.ldt));
+	asm volatile ("str (%0)"  : "=m" (suspend2_saved_context.tr));
+
+	/*
+	 * segment registers
+	 */
+	asm volatile ("movw %%ds, %0" : "=r" (suspend2_saved_context.ds));
+	asm volatile ("movw %%es, %0" : "=r" (suspend2_saved_context.es));
+	asm volatile ("movw %%fs, %0" : "=r" (suspend2_saved_context.fs));
+	asm volatile ("movw %%gs, %0" : "=r" (suspend2_saved_context.gs));
+	asm volatile ("movw %%ss, %0" : "=r" (suspend2_saved_context.ss));
+
+	rdmsrl(MSR_FS_BASE, suspend2_saved_context.fs_base);
+	rdmsrl(MSR_GS_BASE, suspend2_saved_context.gs_base);
+	rdmsrl(MSR_KERNEL_GS_BASE, suspend2_saved_context.gs_kernel_base);
+
+	/*
+	 * control registers 
+	 */
+	asm volatile ("movl %%cr0, %0" : "=r" (suspend2_saved_context.cr0));
+	asm volatile ("movl %%cr2, %0" : "=r" (suspend2_saved_context.cr2));
+	asm volatile ("movl %%cr3, %0" : "=r" (suspend2_saved_context.cr3));
+	asm volatile ("movl %%cr4, %0" : "=r" (suspend2_saved_context.cr4));
+
+}
+
+static void fix_processor_context(void)
+{
+	int nr = _smp_processor_id();
+	struct tss_struct * t = &per_cpu(init_tss,nr);
+
+	set_tss_desc(nr,t);	/* This just modifies memory; should not be neccessary. But... This is neccessary, because 386 hardware has concept of busy tsc or some similar stupidity. */
+	cpu_gdt_table[nr][GDT_ENTRY_TSS].type = 9;
+
+	syscall_init();                         /* This sets MSR_*STAR and related */
+	load_TR_desc();
+	load_LDT(&current->active_mm->context);	/* This does lldt */
+
+	/*
+	 * Now maybe reload the debug registers
+	 */
+	if (current->thread.debugreg7){
+                loaddebug(&current->thread, 0);
+                loaddebug(&current->thread, 1);
+                loaddebug(&current->thread, 2);
+                loaddebug(&current->thread, 3);
+                /* no 4 and 5 */
+                loaddebug(&current->thread, 6);
+                loaddebug(&current->thread, 7);
+	}
+}
+
+static void do_fpu_end(void)
+{
+        /* restore FPU regs if necessary */
+	/* Do it out of line so that gcc does not move cr0 load to some stupid place */
+        kernel_fpu_end();
+	mxcsr_feature_mask_init();
+}
+
+/*
+ * restore_processor_context
+ * 
+ * Restore the processor context as it was before we went to sleep
+ * - descriptor tables
+ * - control registers
+ * - segment registers
+ * - flags
+ * 
+ * Note that it is critical that this function is declared inline.  
+ * It was separated out from restore_state to make that function
+ * a little clearer, but it needs to be inlined because we won't have a
+ * stack when we get here (so we can't push a return address).
+ */
+static inline void restore_processor_context(void)
+{
+	/*
+	 * first restore %ds, so we can access our data properly
+	 */
+	//asm volatile ("movw %0, %%ds" :: "r" ((u16)__KERNEL_DS));
+	
+	__flush_tlb_global(); /* INLINE? */
+
+	asm volatile ("movl	$24, %eax");
+	asm volatile ("movl	%eax, %ds");
+
+	/*
+	 * the other general registers
+	 *
+	 * note that even though gcc has constructs to specify memory 
+	 * input into certain registers, it will try to be too smart
+	 * and save them at the beginning of the function.  This is esp.
+	 * bad since we don't have a stack set up when we enter, and we 
+	 * want to preserve the values on exit. So, we set them manually.
+	 */
+	asm volatile ("movl %0, %%rsp" :: "m" (suspend2_saved_context.esp));
+	asm volatile ("movl %0, %%rbp" :: "m" (suspend2_saved_context.ebp));
+	//asm volatile ("movl %0, %%eax" :: "m" (suspend2_saved_context.eax));
+	asm volatile ("movl %0, %%rbx" :: "m" (suspend2_saved_context.ebx));
+	asm volatile ("movl %0, %%rcx" :: "m" (suspend2_saved_context.ecx));
+	asm volatile ("movl %0, %%rdx" :: "m" (suspend2_saved_context.edx));
+	asm volatile ("movl %0, %%rsi" :: "m" (suspend2_saved_context.esi));
+	asm volatile ("movl %0, %%rdi" :: "m" (suspend2_saved_context.edi));
+	asm volatile ("movl %0, %%r8" :: "m" (suspend2_saved_context.r8));
+	asm volatile ("movl %0, %%r9" :: "m" (suspend2_saved_context.r9));
+	asm volatile ("movl %0, %%r10" :: "m" (suspend2_saved_context.r10));
+	asm volatile ("movl %0, %%r11" :: "m" (suspend2_saved_context.r11));
+	asm volatile ("movl %0, %%r12" :: "m" (suspend2_saved_context.r12));
+	asm volatile ("movl %0, %%r13" :: "m" (suspend2_saved_context.r13));
+	asm volatile ("movl %0, %%r14" :: "m" (suspend2_saved_context.r14));
+	asm volatile ("movl %0, %%r15" :: "m" (suspend2_saved_context.r15));
+
+	/*
+	 * the flags
+	 */
+	asm volatile ("pushl %0 ; popfl" :: "m" (suspend2_saved_context.eflags));
+	
+	asm volatile ("xorq	%rax, %rax");
+
+	/*
+	 * control registers
+	 */
+	asm volatile ("movl %0, %%cr4" :: "r" (suspend2_saved_context.cr4));
+	asm volatile ("movl %0, %%cr3" :: "r" (suspend2_saved_context.cr3));
+	asm volatile ("movl %0, %%cr2" :: "r" (suspend2_saved_context.cr2));
+	asm volatile ("movl %0, %%cr0" :: "r" (suspend2_saved_context.cr0));
+
+	/*
+	 * segment registers
+	 */
+	asm volatile ("movw %0, %%ds" :: "r" (suspend2_saved_context.ds));
+	asm volatile ("movw %0, %%es" :: "r" (suspend2_saved_context.es));
+	asm volatile ("movw %0, %%fs" :: "r" (suspend2_saved_context.fs));
+	load_gs_index(suspend2_saved_context.gs);
+	asm volatile ("movw %0, %%ss" :: "r" (suspend2_saved_context.ss));
+
+	wrmsrl(MSR_FS_BASE, suspend2_saved_context.fs_base);
+	wrmsrl(MSR_GS_BASE, suspend2_saved_context.gs_base);
+	wrmsrl(MSR_KERNEL_GS_BASE, suspend2_saved_context.gs_kernel_base);
+
+	/*
+	 * now restore the descriptor tables to their proper values
+	 * ltr is done in fix_processor_context().
+	 */
+
+	asm volatile ("lgdt (%0)" :: "m" (suspend2_saved_context.gdt_limit));
+	asm volatile ("lidt (%0)" :: "m" (suspend2_saved_context.idt_limit));
+	asm volatile ("lldt (%0)" :: "m" (suspend2_saved_context.ldt));
+
+	fix_processor_context();
+
+	do_fpu_end();
+}
+
+#if defined(CONFIG_SUSPEND2) || defined(CONFIG_SMP)
+extern atomic_t suspend_cpu_counter __nosavedata;
+extern unsigned char * my_saved_context __nosavedata;
+static unsigned long c_loops_per_jiffy_ref[NR_CPUS] __nosavedata;
+#endif
+
+#ifdef CONFIG_SUSPEND2
+#ifndef CONFIG_SMP
+extern unsigned long loops_per_jiffy;
+volatile static unsigned long cpu_khz_ref __nosavedata = 0;
+#endif
+
+/* 
+ * APIC support: These routines save the APIC
+ * configuration for the CPU on which they are
+ * being executed
+ */
+extern void suspend_apic_save_state(void);
+extern void suspend_apic_reload_state(void);
+
+#ifdef CONFIG_SMP
+/* ------------------------------------------------
+ * BEGIN Irq affinity code, based on code from LKCD.
+ *
+ * IRQ affinity support:
+ * Save and restore IRQ affinities, and set them
+ * all to CPU 0.
+ *
+ * Section between dashes taken from LKCD code.
+ * Perhaps we should be working toward a shared library
+ * of such routines for kexec, lkcd, software suspend
+ * and whatever other similar projects there are?
+ */
+
+extern irq_desc_t irq_desc[];
+extern cpumask_t irq_affinity[];
+extern cpumask_t saved_affinity[NR_IRQS];
+
+/*
+ * Routine to save the old irq affinities and change affinities of all irqs to
+ * the dumping cpu.
+ */
+static void save_and_set_irq_affinity(void)
+{
+	int i;
+	int cpu = _smp_processor_id();
+
+	memcpy(saved_affinity, irq_affinity, NR_IRQS * sizeof(cpumask_t));
+	for (i = 0; i < NR_IRQS; i++) {
+		if (irq_desc[i].handler == NULL)
+			continue;
+		irq_affinity[i] = cpumask_of_cpu(cpu);
+		if (irq_desc[i].handler->set_affinity != NULL)
+			irq_desc[i].handler->set_affinity(i, irq_affinity[i]);
+	}
+}
+
+/*
+ * Restore old irq affinities.
+ */
+static void reset_irq_affinity(void)
+{
+	int i;
+
+	memcpy(irq_affinity, saved_affinity, NR_IRQS * sizeof(cpumask_t));
+	for (i = 0; i < NR_IRQS; i++) {
+		if (irq_desc[i].handler == NULL)
+			continue;
+		if (irq_desc[i].handler->set_affinity != NULL)
+			irq_desc[i].handler->set_affinity(i, irq_affinity[i]);
+	}
+}
+
+/*
+ * END of IRQ affinity code, based on LKCD code.
+ * -----------------------------------------------------------------
+ */
+#else
+#define save_and_set_irq_affinity() do { } while(0)
+#define reset_irq_affinity() do { } while(0)
+#endif
+
+static inline void suspend2_pre_copy(void)
+{
+	/*
+	 * Save the irq affinities before we freeze the
+	 * other processors!
+	 */
+	save_and_set_irq_affinity();
+	mtrr_save();
+}
+
+static inline void suspend2_post_copy(void)
+{
+}
+
+static inline void suspend2_pre_copyback(void)
+{
+
+	/* Send all IRQs to CPU 0. We will replace the saved affinities
+	 * with the suspend-time ones when we copy the original kernel
+	 * back in place
+	 */
+	save_and_set_irq_affinity();
+	
+	c_loops_per_jiffy_ref[_smp_processor_id()] = current_cpu_data.loops_per_jiffy;
+#ifndef CONFIG_SMP
+	cpu_khz_ref = cpu_khz;
+	c_loops_per_jiffy_ref[_smp_processor_id()] = loops_per_jiffy;
+#endif
+	
+	/* We want to run from swsusp_pg_dir, since swsusp_pg_dir is stored in constant
+	 * place in memory 
+	 */
+
+        __asm__( "movl %%ecx,%%cr3\n" ::"c"(__pa(swsusp_pg_dir)));
+	__asm__( "leaq	init_level4_pgt(%rip),%rax");
+	__asm__( "subq	$__START_KERNEL_map,%rax");
+	__asm__( "movq	%rax,%cr3");
+}
+
+static inline void suspend2_restore_processor_context(void)
+{
+	restore_processor_context();
+}
+	
+static inline void suspend2_flush_caches(void)
+{
+	cpu_clear(_smp_processor_id(), per_cpu(cpu_tlbstate, _smp_processor_id()).active_mm->cpu_vm_mask);
+	wbinvd();
+	__flush_tlb_all();
+	
+}
+
+static inline void suspend2_post_copyback(void)
+{
+	mtrr_restore_one_cpu();
+
+	/* Get other CPUs to restore their contexts and flush their tlbs. */
+	clear_suspend_state(SUSPEND_FREEZE_SMP);
+	
+	do {
+		cpu_relax();
+		barrier();
+	} while (atomic_read(&suspend_cpu_counter));
+	mtrr_restore_finish();
+	
+	BUG_ON(!irqs_disabled());
+
+	/* put the irq affinity tables back */
+	reset_irq_affinity();
+	
+	current_cpu_data.loops_per_jiffy = c_loops_per_jiffy_ref[_smp_processor_id()];
+#ifndef CONFIG_SMP
+	loops_per_jiffy = c_loops_per_jiffy_ref[_smp_processor_id()];
+	cpu_khz = cpu_khz_ref;
+#endif
+}
+
+#endif

diff -ruNp 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend.h 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend.h

include/asm-x86_64/suspend.h +1 -2
@@ -43,7 +43,7 @@ extern unsigned long saved_context_eflag
                        : /* no output */ \
                        :"r" ((thread)->debugreg##register))
 
-extern void fix_processor_context(void);
+/* extern void fix_processor_context(void); */
 
 #ifdef CONFIG_ACPI_SLEEP
 extern unsigned long saved_eip;
 
-

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#70 lore raw

Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch

Quoted 7 lines · Nigel Cunningham

Hi.

This patch came from Hu Gang.

Regards,

Nigel

:), Maybe you are wrong, I just do a ppc port not x86_64.

Signature · 5 lines
Hu Gang       .-.
              /v\
             // \\ 
Linux User  /(   )\  [204016]
GPG Key ID   ^^-^^   http://soulinfo.com/~hugang/hugang.asc
#71 lore raw

Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch

Ah my bad.

This must be from before I discovered that the subjects got mismatched with the patches :>

Nigel

Quoted 10 lines · On Wed, 2005-07-06 at 15:30, [email protected] wrote:
Quoted 7 lines · Nigel Cunningham

Hi.

This patch came from Hu Gang.

Regards,

Nigel

:), Maybe you are wrong, I just do a ppc port not x86_64.

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#72 lore raw

Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch

In reply to Nigel Cunningham

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 2

Quoted 6 lines · Nigel Cunningham

diff -ruNp 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend2.h 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend2.h

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +2 -0
@@ -0,0 +1,432 @@
+#undef inline
+#define inline __inline__ __attribute__((always_inline))

Please drop this macro. <linux/compiler.h> takes care of it already.

Quoted 13 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +13 -0
+
+/* image of the saved processor states */
+struct suspend2_saved_context {
+       unsigned long eax, ebx, ecx, edx;
+       unsigned long esp, ebp, esi, edi;
+       unsigned long r8, r9, r10, r11;
+       unsigned long r12, r13, r14, r15;
+
+#if 0
+       u16 es, fs, gs, ss;
+       u32 cr0, cr2, cr3, cr4;
+       u16 gdt_pad;
+       u16 gdt_limit;

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 25

Quoted 10 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +10 -0
+       u32 gdt_base;
+       u16 idt_pad;
+       u16 idt_limit;
+       u32 idt_base;
+       u16 ldt;
+       u16 tss;
+       u32 tr;
+       u32 safety;
+       u32 return_address;
+#endif

Please drop the #ifdef

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 29

Quoted 4 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +4 -0
+       unsigned long eflags;
+} __attribute__((packed));
+
+extern struct suspend2_saved_context suspend2_saved_context;   /* temporary storage */

Please move the comment above the declaration (looks as if you're breaking 80 columns).

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 39

Quoted 10 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +10 -0
+
+#ifdef CONFIG_MTRR
+/* MTRR functions */
+extern int mtrr_save(void);
+extern int mtrr_restore_one_cpu(void);
+extern void mtrr_restore_finish(void);
+#else
+#define mtrr_save() do { } while(0)
+#define mtrr_restore_one_cpu() do { } while(0)
+#define mtrr_restore_finish() do { } while(0)

Empty static inline functions are preferred.

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 44

Quoted 5 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +5 -0
+#endif
+
+#ifndef CONFIG_SMP
+#undef cpu_clear
+#define cpu_clear(a, b) do { } while(0)

Same here.

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 47

Quoted 3 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +3 -0
+#endif
+
+extern struct suspend2_saved_context suspend2_saved_context;   /* temporary storage */

Move comment up.

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 53

Quoted 6 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +6 -0
+static void fix_processor_context(void)
+{
+       int nr = _smp_processor_id();
+       struct tss_struct * t = &per_cpu(init_tss,nr);
+
+       set_tss_desc(nr,t);     /* This just modifies memory; should not be neccessary. But... This is neccessary, because 386 hardware has concept of busy tsc or some similar stupidity. */

Please move comment before function call and indent it properly.

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 60

Quoted 7 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +7 -0
+/*
+ * END of IRQ affinity code, based on LKCD code.
+ * -----------------------------------------------------------------
+ */
+#else
+#define save_and_set_irq_affinity() do { } while(0)
+#define reset_irq_affinity() do { } while(0)

Empty static inlines please.

include/asm-x86_64/suspend.h 2005-07-04 23:14:19.000000000 +1000 extern unsigned long saved_context_eflag · line 46

Quoted 9 lines

diff -ruNp 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend.h 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend.h

include/asm-x86_64/suspend.h 2005-07-04 23:14:19.000000000 +1000 renamed from include/asm-x86_64/suspend.h 2005-06-20 11:47:28.000000000 +1000 +1 -1
@@ -43,7 +43,7 @@ extern unsigned long saved_context_eflag
                        : /* no output */ \
                        :"r" ((thread)->debugreg##register))
 
-extern void fix_processor_context(void);
+/* extern void fix_processor_context(void); */

Please drop commented out code.

Quoted 10 lines
include/asm-x86_64/suspend.h 2005-07-04 23:14:19.000000000 +1000 renamed from include/asm-x86_64/suspend.h 2005-06-20 11:47:28.000000000 +1000 +0 -1
 #ifdef CONFIG_ACPI_SLEEP
 extern unsigned long saved_eip;
 
-

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#73 lore raw

Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch

Hi.

Thanks for pointing those things out. The ifdef is there because x86_64 is still work in progress. I'll try Qemu to get this patch up to scratch.

Regards,

Nigel

Quoted 113 lines · Pekka Enberg

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 2

Quoted 6 lines · Nigel Cunningham

diff -ruNp 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend2.h 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend2.h

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +2 -0
@@ -0,0 +1,432 @@
+#undef inline
+#define inline __inline__ __attribute__((always_inline))

Please drop this macro. <linux/compiler.h> takes care of it already.

Quoted 13 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +13 -0
+
+/* image of the saved processor states */
+struct suspend2_saved_context {
+       unsigned long eax, ebx, ecx, edx;
+       unsigned long esp, ebp, esi, edi;
+       unsigned long r8, r9, r10, r11;
+       unsigned long r12, r13, r14, r15;
+
+#if 0
+       u16 es, fs, gs, ss;
+       u32 cr0, cr2, cr3, cr4;
+       u16 gdt_pad;
+       u16 gdt_limit;

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 25

Quoted 10 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +10 -0
+       u32 gdt_base;
+       u16 idt_pad;
+       u16 idt_limit;
+       u32 idt_base;
+       u16 ldt;
+       u16 tss;
+       u32 tr;
+       u32 safety;
+       u32 return_address;
+#endif

Please drop the #ifdef

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 29

Quoted 4 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +4 -0
+       unsigned long eflags;
+} __attribute__((packed));
+
+extern struct suspend2_saved_context suspend2_saved_context;   /* temporary storage */

Please move the comment above the declaration (looks as if you're breaking 80 columns).

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 39

Quoted 10 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +10 -0
+
+#ifdef CONFIG_MTRR
+/* MTRR functions */
+extern int mtrr_save(void);
+extern int mtrr_restore_one_cpu(void);
+extern void mtrr_restore_finish(void);
+#else
+#define mtrr_save() do { } while(0)
+#define mtrr_restore_one_cpu() do { } while(0)
+#define mtrr_restore_finish() do { } while(0)

Empty static inline functions are preferred.

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 44

Quoted 5 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +5 -0
+#endif
+
+#ifndef CONFIG_SMP
+#undef cpu_clear
+#define cpu_clear(a, b) do { } while(0)

Same here.

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 47

Quoted 3 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +3 -0
+#endif
+
+extern struct suspend2_saved_context suspend2_saved_context;   /* temporary storage */

Move comment up.

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 53

Quoted 6 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +6 -0
+static void fix_processor_context(void)
+{
+       int nr = _smp_processor_id();
+       struct tss_struct * t = &per_cpu(init_tss,nr);
+
+       set_tss_desc(nr,t);     /* This just modifies memory; should not be neccessary. But... This is neccessary, because 386 hardware has concept of busy tsc or some similar stupidity. */

Please move comment before function call and indent it properly.

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 60

Quoted 7 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +7 -0
+/*
+ * END of IRQ affinity code, based on LKCD code.
+ * -----------------------------------------------------------------
+ */
+#else
+#define save_and_set_irq_affinity() do { } while(0)
+#define reset_irq_affinity() do { } while(0)

Empty static inlines please.

include/asm-x86_64/suspend.h 2005-07-04 23:14:19.000000000 +1000 extern unsigned long saved_context_eflag · line 46

Quoted 9 lines

diff -ruNp 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend.h 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend.h

include/asm-x86_64/suspend.h 2005-07-04 23:14:19.000000000 +1000 renamed from include/asm-x86_64/suspend.h 2005-06-20 11:47:28.000000000 +1000 +1 -1
@@ -43,7 +43,7 @@ extern unsigned long saved_context_eflag
                        : /* no output */ \
                        :"r" ((thread)->debugreg##register))
 
-extern void fix_processor_context(void);
+/* extern void fix_processor_context(void); */

Please drop commented out code.

Quoted 10 lines
include/asm-x86_64/suspend.h 2005-07-04 23:14:19.000000000 +1000 renamed from include/asm-x86_64/suspend.h 2005-06-20 11:47:28.000000000 +1000 +0 -1
 #ifdef CONFIG_ACPI_SLEEP
 extern unsigned long saved_eip;
 
-

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#74 lore raw

Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch

In reply to Pekka Enberg

Requested changes applied.

Thanks!

Nigel

Quoted 113 lines · Pekka Enberg

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 2

Quoted 6 lines · Nigel Cunningham

diff -ruNp 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend2.h 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend2.h

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +2 -0
@@ -0,0 +1,432 @@
+#undef inline
+#define inline __inline__ __attribute__((always_inline))

Please drop this macro. <linux/compiler.h> takes care of it already.

Quoted 13 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +13 -0
+
+/* image of the saved processor states */
+struct suspend2_saved_context {
+       unsigned long eax, ebx, ecx, edx;
+       unsigned long esp, ebp, esi, edi;
+       unsigned long r8, r9, r10, r11;
+       unsigned long r12, r13, r14, r15;
+
+#if 0
+       u16 es, fs, gs, ss;
+       u32 cr0, cr2, cr3, cr4;
+       u16 gdt_pad;
+       u16 gdt_limit;

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 25

Quoted 10 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +10 -0
+       u32 gdt_base;
+       u16 idt_pad;
+       u16 idt_limit;
+       u32 idt_base;
+       u16 ldt;
+       u16 tss;
+       u32 tr;
+       u32 safety;
+       u32 return_address;
+#endif

Please drop the #ifdef

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 29

Quoted 4 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +4 -0
+       unsigned long eflags;
+} __attribute__((packed));
+
+extern struct suspend2_saved_context suspend2_saved_context;   /* temporary storage */

Please move the comment above the declaration (looks as if you're breaking 80 columns).

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 39

Quoted 10 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +10 -0
+
+#ifdef CONFIG_MTRR
+/* MTRR functions */
+extern int mtrr_save(void);
+extern int mtrr_restore_one_cpu(void);
+extern void mtrr_restore_finish(void);
+#else
+#define mtrr_save() do { } while(0)
+#define mtrr_restore_one_cpu() do { } while(0)
+#define mtrr_restore_finish() do { } while(0)

Empty static inline functions are preferred.

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 44

Quoted 5 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +5 -0
+#endif
+
+#ifndef CONFIG_SMP
+#undef cpu_clear
+#define cpu_clear(a, b) do { } while(0)

Same here.

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 47

Quoted 3 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +3 -0
+#endif
+
+extern struct suspend2_saved_context suspend2_saved_context;   /* temporary storage */

Move comment up.

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 53

Quoted 6 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +6 -0
+static void fix_processor_context(void)
+{
+       int nr = _smp_processor_id();
+       struct tss_struct * t = &per_cpu(init_tss,nr);
+
+       set_tss_desc(nr,t);     /* This just modifies memory; should not be neccessary. But... This is neccessary, because 386 hardware has concept of busy tsc or some similar stupidity. */

Please move comment before function call and indent it properly.

include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 line 60

Quoted 7 lines
include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000 renamed from include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000 +7 -0
+/*
+ * END of IRQ affinity code, based on LKCD code.
+ * -----------------------------------------------------------------
+ */
+#else
+#define save_and_set_irq_affinity() do { } while(0)
+#define reset_irq_affinity() do { } while(0)

Empty static inlines please.

include/asm-x86_64/suspend.h 2005-07-04 23:14:19.000000000 +1000 extern unsigned long saved_context_eflag · line 46

Quoted 9 lines

diff -ruNp 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend.h 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend.h

include/asm-x86_64/suspend.h 2005-07-04 23:14:19.000000000 +1000 renamed from include/asm-x86_64/suspend.h 2005-06-20 11:47:28.000000000 +1000 +1 -1
@@ -43,7 +43,7 @@ extern unsigned long saved_context_eflag
                        : /* no output */ \
                        :"r" ((thread)->debugreg##register))
 
-extern void fix_processor_context(void);
+/* extern void fix_processor_context(void); */

Please drop commented out code.

Quoted 10 lines
include/asm-x86_64/suspend.h 2005-07-04 23:14:19.000000000 +1000 renamed from include/asm-x86_64/suspend.h 2005-06-20 11:47:28.000000000 +1000 +0 -1
 #ifdef CONFIG_ACPI_SLEEP
 extern unsigned long saved_eip;
 
-

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#75 lore raw

PATCH 20/48 Suspend2 2.1.9.8 for 2.6.12: 520-version-specific-x86_64.patch

In reply to Nigel Cunningham
Documentation/kernel-parameters.txt +8 -1
diff -ruNp 550-documentation.patch-old/Documentation/kernel-parameters.txt 550-documentation.patch-new/Documentation/kernel-parameters.txt
@@ -910,6 +910,8 @@ running once the system is up.
 
 	noresume	[SWSUSP] Disables resume and restore original swap space.
  
+	noresume2	[SWSUSP2] Disables resuming and restores original swap signature.
+ 
 	no-scroll	[VGA] Disables scrollback.
 			This is required for the Braillex ib80-piezo Braille
 			reader made by F.H. Papenmeier (Germany).
@@ -1146,7 +1148,12 @@ running once the system is up.
 
 	reserve=	[KNL,BUGS] Force the kernel to ignore some iomem area
 
-	resume=		[SWSUSP] Specify the partition device for software suspension
+	resume=		[SWSUSP] Specify the partition device for software suspension.
+
+	resume2=	[SWSUSP2] Specify the storage device for software suspend.
+			Format: <writer>:<writer-parameters>.
+			See Documentation/power/swsusp2.txt for details of the formats
+			for available image writers.
 
 	rhash_entries=	[KNL,NET]
 			Set number of hash buckets for route cache
Documentation/power/internals.txt +364 -0

364 lines not on this page · raw message

Documentation/power/suspend2.txt +631 -0

631 lines not on this page · raw message

Documentation/power/todo.txt +12 -0
diff -ruNp 550-documentation.patch-old/Documentation/power/todo.txt 550-documentation.patch-new/Documentation/power/todo.txt
@@ -0,0 +1,12 @@
+Suspend2 todo list
+
+20050705
+  2.1.9.8 known issues:
+  ----------------
+- NFS support missing
+- DRI support for 2.4 & 2.6
+- USB support under 2.4 and 2.6
+- Incomplete support in other drivers
+- No support for discontig memory
+- Currently requires PSE extension (/proc/cpuinfo)
+- Highmem >4GB not supported
#76 lore raw

PATCH 21/48 Suspend2 2.1.9.8 for 2.6.12: 550-documentation.patch

In reply to Nigel Cunningham
kernel/power/Kconfig +77 -0
diff -ruNp 560-Kconfig-and-Makefile-for-suspend2.patch-old/kernel/power/Kconfig 560-Kconfig-and-Makefile-for-suspend2.patch-new/kernel/power/Kconfig
@@ -1,5 +1,6 @@
 config PM
 	bool "Power Management support"
+	select SYSFS
 	---help---
 	  "Power Management" means that parts of your computer are shut
 	  off or put into a power conserving "sleep" mode if they are not
@@ -30,6 +31,8 @@ config SOFTWARE_SUSPEND
 	bool "Software Suspend (EXPERIMENTAL)"
 	depends on EXPERIMENTAL && PM && SWAP
 	---help---
+	  Pavel's original version.
+
 	  Enable the possibility of suspending the machine.
 	  It doesn't need APM.
 	  You may suspend your machine by 'swsusp' or 'shutdown -z <time>' 
@@ -72,3 +75,77 @@ config PM_STD_PARTITION
 	  suspended image to. It will simply pick the first available swap 
 	  device.
 
+menuconfig SUSPEND2
+	bool "Software Suspend 2"
+	depends on PM
+	---help---
+	  Software Suspend 2 is the 'new and improved' suspend support.
+	  
+	  See the Software Suspend home page (suspend2.net)
+	  for FAQs, HOWTOs and other documentation.
+
+	comment 'Image Storage (you need at least one writer)'
+		depends on SUSPEND2
+	
+	config SUSPEND2_FILEWRITER
+		bool '  File Writer'
+		depends on SUSPEND2
+		---help---
+		  This option enables support for storing an image in a
+		  simple file. This should be possible, but we're still
+		  testing it.
+
+	config SUSPEND2_SWAPWRITER
+		bool '  Swap Writer'
+		depends on SWAP && SUSPEND2
+		---help---
+		  This option enables support for storing an image in your
+		  swap space.
+
+	comment 'General Options'
+		depends on SUSPEND2
+
+	config SUSPEND2_DEFAULT_RESUME2
+		string '  Default resume device name'
+		depends on SUSPEND2
+		---help---
+		  You normally need to add a resume2= parameter to your lilo.conf or
+		  equivalent. With this option properly set, the kernel has a value
+		  to default. No damage will be done if the value is invalid.
+
+	config SUSPEND2_KEEP_IMAGE
+		bool '  Allow Keep Image Mode'
+		depends on SUSPEND2
+		---help---
+		  This option allows you to keep and image and reuse it. It is intended
+		  __ONLY__ for use with systems where all filesystems are mounted read-
+		  only (kiosks, for example). To use it, compile this option in and boot
+		  normally. Set the KEEP_IMAGE flag in /proc/software_suspend and suspend.
+		  When you resume, the image will not be removed. You will be unable to turn
+		  off swap partitions (assuming you are using the swap writer), but future
+		  suspends simply do a power-down. The image can be updated using the
+		  kernel command line parameter suspend_act= to turn off the keep image
+		  bit. Keep image mode is a little less user friendly on purpose - it
+		  should not be used without thought!
+
+	config SUSPEND2_CHECK_RESUME_SAFE
+		bool '  Warn if possibility of filesystem corruption'
+		depends on SUSPEND2
+		default y
+		---help---
+		  This option enables code that looks at what filesystems you have
+		  mounted prior to resuming. If you have any filesystems of type
+		  ext2, ext3, reiser or such like mounted rw, it will warn you
+		  before resuming and default to removing the image instead of
+		  resuming.
+		  
+		  If you're just beginning to set up suspend, it is a good idea to
+		  leave this option on. You can always turn this option off later -
+		  if you only change this option, recompiling the kernel/modules
+		  won't take long at all.
+
+		  Note that if you have this on and use an initrd/initramfs, you
+		  may well need to add
+			mount / -o remount,ro
+		  prior to the echo > /proc/software_suspend/resume call in your
+		  initrd/initramfs. You might want to remount it rw again afterwards.
kernel/power/Makefile +7 -3
diff -ruNp 560-Kconfig-and-Makefile-for-suspend2.patch-old/kernel/power/Makefile 560-Kconfig-and-Makefile-for-suspend2.patch-new/kernel/power/Makefile
@@ -3,9 +3,13 @@ ifeq ($(CONFIG_PM_DEBUG),y)
 EXTRA_CFLAGS	+=	-DDEBUG
 endif
 
-swsusp-smp-$(CONFIG_SMP)	+= smp.o
-
 obj-y				:= main.o process.o console.o pm.o
-obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o $(swsusp-smp-y) disk.o
+obj-$(CONFIG_HOTPLUG_CPU)	+= smp.o
+
+obj-$(CONFIG_SUSPEND2)			+= suspend2_core/
+obj-$(CONFIG_SUSPEND2_SWAPWRITER)	+= suspend_block_io.o suspend_swap.o
+obj-$(CONFIG_SUSPEND2_FILEWRITER)	+= suspend_block_io.o suspend_file.o
+
+obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o disk.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
kernel/power/suspend2_core/Makefile +13 -0
diff -ruNp 560-Kconfig-and-Makefile-for-suspend2.patch-old/kernel/power/suspend2_core/Makefile 560-Kconfig-and-Makefile-for-suspend2.patch-new/kernel/power/suspend2_core/Makefile
@@ -0,0 +1,13 @@
+# Order is important for compression and encryption - we
+# compress before encrypting.
+
+suspend_core-objs := io.o pagedir.o prepare_image.o \
+		extent.o suspend.o plugins.o utility.o \
+		driver_model.o pageflags.o ui.o proc.o \
+		userspace-nofreeze.o all_settings.o \
+		power_off.o atomic_copy.o
+
+obj-$(CONFIG_SMP)			+= smp.o
+
+obj-$(CONFIG_SUSPEND2)			+= suspend_core.o
+obj-$(CONFIG_CRYPTO)			+= compression.o encryption.o
#77 lore raw

PATCH 22/48 Suspend2 2.1.9.8 for 2.6.12: 560-Kconfig-and-Makefile-for-suspend2.patch

In reply to Nigel Cunningham
include/linux/suspend2.h +213 -0
diff -ruNp 600-suspend-header.patch-old/include/linux/suspend2.h 600-suspend-header.patch-new/include/linux/suspend2.h
@@ -0,0 +1,213 @@
+#ifndef _LINUX_SUSPEND2_H
+#define _LINUX_SUSPEND2_H
+
+#include <linux/dyn_pageflags.h>
+#include <linux/init.h>
+
+/* arch/i386/mm/init.c */
+extern char __nosave_begin, __nosave_end;
+
+extern char __nosavedata swsusp_pg_dir[PAGE_SIZE]
+                  __attribute__ ((aligned (PAGE_SIZE)));
+
+/* kernel/power/process.c */
+
+/* fs/buffer.c */
+extern unsigned int suspend_task;
+
+#define SUSPEND_KEY_KEYBOARD 1
+#define SUSPEND_KEY_SERIAL 2
+
+/* kernel/power/main.c */
+extern unsigned long suspend_result;
+
+/* kernel/power/process.c */
+extern unsigned long suspend_debug_state;
+
+/* arch/i386/power/suspend2.c */
+extern unsigned long suspend_action;
+extern int suspend_io_time[2][2];
+
+/* Pre and post lowlevel routines */
+//extern void suspend2_suspend_1 (void);
+//extern void suspend2_suspend_2 (void);
+//extern void suspend2_resume_1 (void);
+//extern void suspend2_resume_2 (void);
+
+extern dyn_pageflags_t pageset1_map;
+extern dyn_pageflags_t	pageset1_copy_map;
+
+#ifdef CONFIG_PM_DEBUG
+#define TEST_DEBUG_STATE(bit) (test_bit(bit, &suspend_debug_state))
+#else
+#define TEST_DEBUG_STATE(bit) (0)
+#endif
+
+#define TEST_RESULT_STATE(bit) (test_bit(bit, &suspend_result))
+
+/* 
+ * First status register - this is suspend's return code.
+ *
+ * All the rest are in kernel/power/suspend2_common.h
+ */
+#define SUSPEND_ABORTED			0
+
+/* Second status register - ditto */
+#define SUSPEND_RETRY_RESUME		0
+
+/* Debug sections  - if debugging compiled in */
+#define SUSPEND_ANY_SECTION	0
+#define SUSPEND_FREEZER		1
+#define SUSPEND_EAT_MEMORY 	2
+#define SUSPEND_PAGESETS	3
+#define SUSPEND_IO		4
+#define SUSPEND_BMAP		5
+#define SUSPEND_HEADER		6
+#define SUSPEND_WRITER		7
+#define SUSPEND_MEMORY		8
+#define SUSPEND_EXTENTS		9
+#define SUSPEND_SPINLOCKS	10
+#define SUSPEND_MEM_POOL	11
+#define SUSPEND_RANGE_PARANOIA	12
+#define SUSPEND_NOSAVE		13
+#define SUSPEND_INTEGRITY	14
+
+/* debugging levels. */
+#define SUSPEND_STATUS		0
+#define SUSPEND_ERROR		2
+#define SUSPEND_LOW	 	3
+#define SUSPEND_MEDIUM	 	4
+#define SUSPEND_HIGH	  	5
+#define SUSPEND_VERBOSE		6
+
+extern void __suspend_message(unsigned long section, unsigned long level, int log_normally,
+		const char *fmt, ...);
+
+#ifdef CONFIG_PM_DEBUG
+#define suspend_message(sn, lev, log, fmt, a...) \
+do { \
+	if (TEST_DEBUG_STATE(sn)) \
+		__suspend_message(sn, lev, log, fmt, ##a); \
+} while(0)
+#else /* CONFIG_PM_DEBUG */
+#define suspend_message(sn, lev, log, fmt, a...) \
+do { \
+	if (lev == 0) \
+		__suspend_message(sn, lev, log, fmt, ##a); \
+} while(0)
+#endif /* CONFIG_PM_DEBUG */
+  
+/* Suspend 2 */
+
+#define SUSPEND_DISABLED		0
+#define SUSPEND_RUNNING			1
+#define SUSPEND_RESUME_DEVICE_OK	2
+#define SUSPEND_NORESUME_SPECIFIED	3
+#define SUSPEND_COMMANDLINE_ERROR 	4
+#define SUSPEND_IGNORE_IMAGE		5
+#define SUSPEND_SANITY_CHECK_PROMPT	6
+#define SUSPEND_FREEZER_ON		7
+#define SUSPEND_DISABLE_SYNCING		8
+#define SUSPEND_BLOCK_PAGE_ALLOCATIONS	9
+#define SUSPEND_USE_MEMORY_POOL		10
+#define SUSPEND_STAGE2_CONTINUE		11
+#define SUSPEND_FREEZE_SMP		12
+#define SUSPEND_PAGESET2_NOT_LOADED	13
+#define SUSPEND_CONTINUE_REQ		14
+#define SUSPEND_RESUMED_BEFORE		15
+#define SUSPEND_RUNNING_INITRD		16
+#define SUSPEND_RESUME_NOT_DONE		17
+#define SUSPEND_BOOT_TIME		18
+#define SUSPEND_NOW_RESUMING		19
+#define SUSPEND_SLAB_ALLOC_FALLBACK	20
+#define SUSPEND_IGNORE_LOGLEVEL		21
+#define SUSPEND_TIMER_FREEZER_ON	22
+#define SUSPEND_ACT_USED		23
+#define SUSPEND_DBG_USED		24
+#define SUSPEND_LVL_USED		25
+#define SUSPEND_TRYING_TO_RESUME	27
+
+#define test_and_set_suspend_state(bit) \
+	(test_and_set_bit(bit, &software_suspend_state))
+
+#define get_suspend_state() 		(software_suspend_state)
+#define restore_suspend_state(saved_state) \
+	do { software_suspend_state = saved_state; } while(0)
+	
+/* Kernel threads are type 3 */
+#define FREEZER_ALL_THREADS 0
+#define FREEZER_KERNEL_THREADS 3
+
+/* --------------------------------------------------------------------- */
+#ifdef CONFIG_SUSPEND2
+
+/* Used in init dir files */
+extern unsigned long software_suspend_state;
+
+extern void suspend2_try_resume(void);
+extern int suspend_early_boot_message 
+	(int can_erase_image, int default_answer, char *warning_reason, ...);
+extern void suspend_handle_keypress(unsigned int keycode, int source);
+extern unsigned long suspend2_update_status (unsigned long value, unsigned long maximum,
+		const char *fmt, ...);
+extern void suspend2_prepare_status (int printalways, int clearbar, const char *fmt, ...);
+extern void suspend2_cleanup_finished_io(void);
+
+#define test_suspend_state(bit) \
+	(test_bit(bit, &software_suspend_state))
+
+#define clear_suspend_state(bit) \
+	(clear_bit(bit, &software_suspend_state))
+
+#define set_suspend_state(bit) \
+	(set_bit(bit, &software_suspend_state))
+
+#ifdef CONFIG_SMP
+void smp_pause(void);
+void smp_continue(void);
+void smp_suspend(void);
+#else
+#define smp_pause() do { } while(0)
+#define smp_continue() do { } while(0)
+#define smp_suspend() do { } while(0)
+#endif
+
+extern unsigned long suspend2_get_nonconflicting_page(void);
+extern unsigned long suspend2_get_nonconflicting_pages(int order);
+
+extern inline void suspend2_copyback_low(void);
+extern inline void suspend2_copyback_high(void);
+
+extern void suspend2_try_suspend(void);
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+int suspend_map_kernel_page(struct page * page, int enable);
+#else
+static inline int suspend_map_kernel_page(struct page * page, int enable)
+{
+	return (enable == 1);
+}
+#endif
+
+/* --------------------------------------------------------------------- */
+#else
+/* --------------------------------------------------------------------- */
+
+#define software_suspend_state		(0)
+#define clear_suspend_state(bit)	do { } while (0)
+#define test_suspend_state(bit) 	(0)
+#define set_suspend_state(bit)		do { } while(0)
+
+#define suspend2_try_resume()			do { } while(0)
+static inline int suspend_early_boot_message(int a, int b, char *c, ...)	{ return 0; }
+#define suspend_handle_keypress(a, b) 		do { } while(0)
+static inline unsigned long suspend2_update_status(unsigned long value, unsigned long maximum,
+		const char *fmt, ...)
+{
+	return maximum;
+}
+#define suspend2_cleanup_finished_io() do { } while(0)
+#define suspend2_prepare_status(a, ...)  do { } while(0)
+
+#endif /* CONFIG_SUSPEND2 */
+#endif /* _LINUX_SUSPEND2_H */
include/linux/suspend.h +10 -7
diff -ruNp 600-suspend-header.patch-old/include/linux/suspend.h 600-suspend-header.patch-new/include/linux/suspend.h
@@ -9,6 +9,7 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/pm.h>
+#include <linux/suspend2.h>
 
 /* page backup entry */
 typedef struct pbe {
@@ -58,18 +59,20 @@ static inline int software_suspend(void)
 }
 #endif
 
-#ifdef CONFIG_SMP
+void save_processor_state(void);
+void restore_processor_state(void);
+struct saved_context;
+void __save_processor_state(struct saved_context *ctxt);
+void __restore_processor_state(struct saved_context *ctxt);
+
+#ifdef CONFIG_HOTPLUG_CPU
 extern void disable_nonboot_cpus(void);
 extern void enable_nonboot_cpus(void);
 #else
-static inline void disable_nonboot_cpus(void) {}
+static inline int disable_nonboot_cpus(void) { return 0; }
 static inline void enable_nonboot_cpus(void) {}
 #endif
 
-void save_processor_state(void);
-void restore_processor_state(void);
-struct saved_context;
-void __save_processor_state(struct saved_context *ctxt);
-void __restore_processor_state(struct saved_context *ctxt);
+extern char resume2_file[256];
 
 #endif /* _LINUX_SWSUSP_H */
#78 lore raw

PATCH 23/48 Suspend2 2.1.9.8 for 2.6.12: 600-suspend-header.patch

In reply to Nigel Cunningham
kernel/power/power.h +2 -0
diff -ruNp 601-kernel_power_power-header.patch-old/kernel/power/power.h 601-kernel_power_power-header.patch-new/kernel/power/power.h
@@ -1,6 +1,8 @@
 #include <linux/suspend.h>
 #include <linux/utsname.h>
 
+#include "suspend.h"
+
 /* With SUSPEND_CONSOLE defined, it suspend looks *really* cool, but
    we probably do not take enough locks for switching consoles, etc,
    so bad things might happen.
#79 lore raw

PATCH 24/48 Suspend2 2.1.9.8 for 2.6.12: 601-kernel_power_power-header.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/smp.c +12 -0
diff -ruNp 602-smp.patch-old/kernel/power/suspend2_core/smp.c 602-smp.patch-new/kernel/power/suspend2_core/smp.c
@@ -0,0 +1,12 @@
+#include <linux/sched.h>
+
+void ensure_on_processor_zero(void)
+{
+	set_cpus_allowed(current, cpumask_of_cpu(0));
+	BUG_ON(smp_processor_id() != 0);
+}
+
+void return_to_all_processors(void)
+{
+	set_cpus_allowed(current, CPU_MASK_ALL);
+}
kernel/power/suspend2_core/smp.h +7 -0
diff -ruNp 602-smp.patch-old/kernel/power/suspend2_core/smp.h 602-smp.patch-new/kernel/power/suspend2_core/smp.h
@@ -0,0 +1,7 @@
+#ifdef CONFIG_SMP
+extern void ensure_on_processor_zero(void);
+extern void return_to_all_processors(void);
+#else
+#define ensure_on_processor_zero() do { } while(0)
+#define return_to_all_processors() do { } while(0)
+#endif
#80 lore raw

Re: [PATCH] [24/48] Suspend2 2.1.9.8 for 2.6.12: 601-kernel_power_power-header.patch

Quoted 6 lines · Nigel Cunningham

diff -ruNp 602-smp.patch-old/kernel/power/suspend2_core/smp.c 602-smp.patch-new/kernel/power/suspend2_core/smp.c

kernel/power/suspend2_core/smp.c +2 -0
@@ -0,0 +1,12 @@
+#include <linux/sched.h>
+

kernel/power/suspend2_core/smp.c line 12

Quoted 10 lines
kernel/power/suspend2_core/smp.c +10 -0
+void ensure_on_processor_zero(void)
+{
+	set_cpus_allowed(current, cpumask_of_cpu(0));
+	BUG_ON(smp_processor_id() != 0);
+}
+
+void return_to_all_processors(void)
+{
+	set_cpus_allowed(current, CPU_MASK_ALL);
+}

Do we really need to wrap these?

#81 lore raw

Re: [PATCH] [24/48] Suspend2 2.1.9.8 for 2.6.12: 601-kernel_power_power-header.patch

Hi.

Quoted 12 lines · Zwane Mwaikambo
Quoted 10 lines · Nigel Cunningham

diff -ruNp 602-smp.patch-old/kernel/power/suspend2_core/smp.c 602-smp.patch-new/kernel/power/suspend2_core/smp.c

kernel/power/suspend2_core/smp.c +6 -0
@@ -0,0 +1,12 @@
+#include <linux/sched.h>
+
+void ensure_on_processor_zero(void)
+{
+	set_cpus_allowed(current, cpumask_of_cpu(0));
+	BUG_ON(smp_processor_id() != 0);
Quoted 8 lines

kernel/power/suspend2_core/smp.c line 12

Quoted 6 lines
kernel/power/suspend2_core/smp.c +6 -0
+}
+
+void return_to_all_processors(void)
+{
+	set_cpus_allowed(current, CPU_MASK_ALL);
+}

Do we really need to wrap these?

Fair enough. If I remember rightly, it's just a result of the flux with testing cpu hotplug, so I should certainly drop the wrappers.

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#82 lore raw

PATCH 25/48 Suspend2 2.1.9.8 for 2.6.12: 602-smp.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/suspend2_common.h +49 -0
diff -ruNp 603-suspend2_common-headers.patch-old/kernel/power/suspend2_core/suspend2_common.h 603-suspend2_common-headers.patch-new/kernel/power/suspend2_core/suspend2_common.h
@@ -0,0 +1,49 @@
+#ifdef CONFIG_PM_DEBUG
+#define SET_DEBUG_STATE(bit) (test_and_set_bit(bit, &suspend_debug_state))
+#define CLEAR_DEBUG_STATE(bit) (test_and_clear_bit(bit, &suspend_debug_state))
+#else
+#define SET_DEBUG_STATE(bit) (0)
+#define CLEAR_DEBUG_STATE(bit) (0)
+#endif
+
+#define SET_RESULT_STATE(bit) (test_and_set_bit(bit, &suspend_result))
+#define CLEAR_RESULT_STATE(bit) (test_and_clear_bit(bit, &suspend_result))
+
+#define SUSPEND_ABORT_REQUESTED		1
+#define SUSPEND_NOSTORAGE_AVAILABLE	2
+#define SUSPEND_INSUFFICIENT_STORAGE	3
+#define SUSPEND_FREEZING_FAILED		4
+#define SUSPEND_UNEXPECTED_ALLOC	5
+#define SUSPEND_KEPT_IMAGE		6
+#define SUSPEND_WOULD_EAT_MEMORY	7
+#define SUSPEND_UNABLE_TO_FREE_ENOUGH_MEMORY 8
+#define SUSPEND_ENCRYPTION_SETUP_FAILED	9
+
+/* second status register */
+#define SUSPEND_REBOOT			1
+#define SUSPEND_PAUSE			2
+#define SUSPEND_SLOW			3
+#define SUSPEND_NOPAGESET2		4
+#define SUSPEND_LOGALL			5
+#define SUSPEND_CAN_CANCEL		6
+#define SUSPEND_KEEP_IMAGE		7
+#define SUSPEND_FREEZER_TEST		8
+#define SUSPEND_FREEZER_TEST_SHOWALL	9
+#define SUSPEND_SINGLESTEP		10
+#define SUSPEND_PAUSE_NEAR_PAGESET_END	11
+#define SUSPEND_USE_ACPI_S4		12
+#define SUSPEND_KEEP_METADATA		13
+#define SUSPEND_TEST_FILTER_SPEED	14
+#define SUSPEND_FREEZE_TIMERS		15
+#define SUSPEND_DISABLE_SYSDEV_SUPPORT	16
+#define SUSPEND_VGA_POST		17
+
+#define TEST_ACTION_STATE(bit) (test_bit(bit, &suspend_action))
+#define SET_ACTION_STATE(bit) (test_and_set_bit(bit, &suspend_action))
+#define CLEAR_ACTION_STATE(bit) (test_and_clear_bit(bit, &suspend_action))
+
+extern int suspend_act_used;
+extern int suspend_lvl_used;
+extern int suspend_dbg_used;
+extern int suspend_default_console_level;
+extern unsigned int nr_suspends;
kernel/power/suspend2_core/suspend.h +24 -0
diff -ruNp 603-suspend2_common-headers.patch-old/kernel/power/suspend2_core/suspend.h 603-suspend2_common-headers.patch-new/kernel/power/suspend2_core/suspend.h
@@ -0,0 +1,24 @@
+/*
+ * kernel/power/suspend2.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * It contains declarations used throughout swsusp and suspend2.
+ *
+ */
+#ifndef KERNEL_POWER_SUSPEND_CORE_H
+#define KERNEL_POWER_SUSPEND_CORE_H
+
+#include <linux/delay.h>
+#include <linux/bootmem.h>
+
+extern unsigned long suspend2_orig_mem_free;
+
+#define KB(x) ((x) << (PAGE_SHIFT - 10))
+#define MB(x) ((x) >> (20 - PAGE_SHIFT))
+
+extern int suspend_start_anything(int starting_cycle);
+extern void suspend_finish_anything(int finishing_cycle);
+#endif
kernel/power/suspend2_core/version.h +5 -0
diff -ruNp 603-suspend2_common-headers.patch-old/kernel/power/suspend2_core/version.h 603-suspend2_common-headers.patch-new/kernel/power/suspend2_core/version.h
@@ -0,0 +1,5 @@
+#define SUSPEND_CORE_VERSION "2.1.9.8"
+#ifndef KERNEL_POWER_SWSUSP_C
+#define name_suspend "Software Suspend " SUSPEND_CORE_VERSION ": "
+#endif
+
#83 lore raw

Re: [PATCH] [25/48] Suspend2 2.1.9.8 for 2.6.12: 602-smp.patch

Quoted 37 lines · Nigel Cunningham

diff -ruNp 603-suspend2_common-headers.patch-old/kernel/power/suspend2_core/suspend2_common.h 603-suspend2_common-headers.patch-new/kernel/power/suspend2_core/suspend2_common.h

kernel/power/suspend2_core/suspend2_common.h 2005-07-04 23:14:19.000000000 +1000 renamed from kernel/power/suspend2_core/suspend2_common.h 1970-01-01 10:00:00.000000000 +1000 +33 -0
@@ -0,0 +1,49 @@
+#ifdef CONFIG_PM_DEBUG
+#define SET_DEBUG_STATE(bit) (test_and_set_bit(bit, &suspend_debug_state))
+#define CLEAR_DEBUG_STATE(bit) (test_and_clear_bit(bit, &suspend_debug_state))
+#else
+#define SET_DEBUG_STATE(bit) (0)
+#define CLEAR_DEBUG_STATE(bit) (0)
+#endif
+
+#define SET_RESULT_STATE(bit) (test_and_set_bit(bit, &suspend_result))
+#define CLEAR_RESULT_STATE(bit) (test_and_clear_bit(bit, &suspend_result))
+
+#define SUSPEND_ABORT_REQUESTED                1
+#define SUSPEND_NOSTORAGE_AVAILABLE    2
+#define SUSPEND_INSUFFICIENT_STORAGE   3
+#define SUSPEND_FREEZING_FAILED                4
+#define SUSPEND_UNEXPECTED_ALLOC       5
+#define SUSPEND_KEPT_IMAGE             6
+#define SUSPEND_WOULD_EAT_MEMORY       7
+#define SUSPEND_UNABLE_TO_FREE_ENOUGH_MEMORY 8
+#define SUSPEND_ENCRYPTION_SETUP_FAILED        9
+
+/* second status register */
+#define SUSPEND_REBOOT                 1
+#define SUSPEND_PAUSE                  2
+#define SUSPEND_SLOW                   3
+#define SUSPEND_NOPAGESET2             4
+#define SUSPEND_LOGALL                 5
+#define SUSPEND_CAN_CANCEL             6
+#define SUSPEND_KEEP_IMAGE             7
+#define SUSPEND_FREEZER_TEST           8
+#define SUSPEND_FREEZER_TEST_SHOWALL   9
+#define SUSPEND_SINGLESTEP             10
+#define SUSPEND_PAUSE_NEAR_PAGESET_END 11

kernel/power/suspend2_core/suspend2_common.h 2005-07-04 23:14:19.000000000 +1000 line 43

Quoted 10 lines
kernel/power/suspend2_core/suspend2_common.h 2005-07-04 23:14:19.000000000 +1000 renamed from kernel/power/suspend2_core/suspend2_common.h 1970-01-01 10:00:00.000000000 +1000 +10 -0
+#define SUSPEND_USE_ACPI_S4            12
+#define SUSPEND_KEEP_METADATA          13
+#define SUSPEND_TEST_FILTER_SPEED      14
+#define SUSPEND_FREEZE_TIMERS          15
+#define SUSPEND_DISABLE_SYSDEV_SUPPORT 16
+#define SUSPEND_VGA_POST               17
+
+#define TEST_ACTION_STATE(bit) (test_bit(bit, &suspend_action))
+#define SET_ACTION_STATE(bit) (test_and_set_bit(bit, &suspend_action))
+#define CLEAR_ACTION_STATE(bit) (test_and_clear_bit(bit, &suspend_action))

Enums, please.

#84 lore raw

Re: [PATCH] [25/48] Suspend2 2.1.9.8 for 2.6.12: 602-smp.patch

Hi.

On Wed, 2005-07-06 at 22:03, Pekka Enberg wrote:

[snip]

Quoted 6 lines
Quoted 6 lines
kernel/power/suspend2_core/suspend2_common.h +6 -0
+#define SUSPEND_SINGLESTEP             10
+#define SUSPEND_PAUSE_NEAR_PAGESET_END 11
+#define SUSPEND_USE_ACPI_S4            12
+#define SUSPEND_KEEP_METADATA          13
+#define SUSPEND_TEST_FILTER_SPEED      14
+#define SUSPEND_FREEZE_TIMERS          15
Quoted 8 lines

kernel/power/suspend2_core/suspend2_common.h line 43

Quoted 6 lines
kernel/power/suspend2_core/suspend2_common.h +6 -0
+#define SUSPEND_DISABLE_SYSDEV_SUPPORT 16
+#define SUSPEND_VGA_POST               17
+
+#define TEST_ACTION_STATE(bit) (test_bit(bit, &suspend_action))
+#define SET_ACTION_STATE(bit) (test_and_set_bit(bit, &suspend_action))
+#define CLEAR_ACTION_STATE(bit) (test_and_clear_bit(bit, &suspend_action))

Enums, please.

Done. I'm off to bed now. Don't think I'm ignoring the rest :>

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#85 lore raw

PATCH 26/48 Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/utility.c +46 -0
diff -ruNp 604-utility-header.patch-old/kernel/power/suspend2_core/utility.c 604-utility-header.patch-new/kernel/power/suspend2_core/utility.c
@@ -0,0 +1,46 @@
+/*
+ * kernel/power/utility.c
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <[email protected]>
+ * 
+ * This file is released under the GPLv2.
+ *
+ * Routines that only suspend uses at the moment, but which might move
+ * when we merge because they're generic.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <asm/string.h>
+
+#include "pageflags.h"
+
+/*
+ * suspend_snprintf
+ *
+ * Functionality    : Print a string with parameters to a buffer of a 
+ *                    limited size. Unlike vsnprintf, we return the number
+ *                    of bytes actually put in the buffer, not the number
+ *                    that would have been put in if it was big enough.
+ */
+int suspend_snprintf(char * buffer, int buffer_size, const char *fmt, ...)
+{
+	int result;
+	va_list args;
+
+	if (!buffer_size) {
+		return 0;
+	}
+
+	va_start(args, fmt);
+	result = vsnprintf(buffer, buffer_size, fmt, args);
+	va_end(args);
+
+	if (result > buffer_size) {
+		return buffer_size;
+	}
+
+	return result;
+}
kernel/power/suspend2_core/utility.h +12 -0
diff -ruNp 604-utility-header.patch-old/kernel/power/suspend2_core/utility.h 604-utility-header.patch-new/kernel/power/suspend2_core/utility.h
@@ -0,0 +1,12 @@
+/*
+ * kernel/power/suspend2_core/utility.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <[email protected]>
+ * 
+ * This file is released under the GPLv2.
+ *
+ * Routines that only suspend uses at the moment, but which might move
+ * when we merge because they're generic.
+ */
+
+extern int suspend_snprintf(char * buffer, int buffer_size, const char *fmt, ...);
#86 lore raw

Re: [PATCH] [26/48] Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch

Quoted 54 lines · Nigel Cunningham

diff -ruNp 604-utility-header.patch-old/kernel/power/suspend2_core/utility.c 604-utility-header.patch-new/kernel/power/suspend2_core/utility.c

kernel/power/suspend2_core/utility.c 2005-07-05 23:48:59.000000000 +1000 renamed from kernel/power/suspend2_core/utility.c 1970-01-01 10:00:00.000000000 +1000 +46 -0
@@ -0,0 +1,46 @@
+/*
+ * kernel/power/utility.c
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Routines that only suspend uses at the moment, but which might move
+ * when we merge because they're generic.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <asm/string.h>
+
+#include "pageflags.h"
+
+/*
+ * suspend_snprintf
+ *
+ * Functionality    : Print a string with parameters to a buffer of a
+ *                    limited size. Unlike vsnprintf, we return the number
+ *                    of bytes actually put in the buffer, not the number
+ *                    that would have been put in if it was big enough.
+ */
+int suspend_snprintf(char * buffer, int buffer_size, const char *fmt, ...)
+{
+       int result;
+       va_list args;
+
+       if (!buffer_size) {
+               return 0;
+       }
+
+       va_start(args, fmt);
+       result = vsnprintf(buffer, buffer_size, fmt, args);
+       va_end(args);
+
+       if (result > buffer_size) {
+               return buffer_size;
+       }
+
+       return result;
+}

diff -ruNp 604-utility-header.patch-old/kernel/power/suspend2_core/utility.h 604-utility-header.patch-new/kernel/power/suspend2_core/utility.h

kernel/power/suspend2_core/utility.h 2005-07-05 23:48:59.000000000 +1000 line 10

Quoted 10 lines
kernel/power/suspend2_core/utility.h 2005-07-05 23:48:59.000000000 +1000 renamed from kernel/power/suspend2_core/utility.h 1970-01-01 10:00:00.000000000 +1000 +10 -0
@@ -0,0 +1,12 @@
+/*
+ * kernel/power/suspend2_core/utility.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Routines that only suspend uses at the moment, but which might move
+ * when we merge because they're generic.
+ */

Please do move these.

kernel/power/suspend2_core/utility.h 2005-07-05 23:48:59.000000000 +1000 line 12

Quoted 2 lines
kernel/power/suspend2_core/utility.h 2005-07-05 23:48:59.000000000 +1000 renamed from kernel/power/suspend2_core/utility.h 1970-01-01 10:00:00.000000000 +1000 +2 -0
+
+extern int suspend_snprintf(char * buffer, int buffer_size, const char *fmt, ...);

What's wrong with regular snprintf?

Pekka

#87 lore raw

Re: [PATCH] [26/48] Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch

Hi.

Quoted 5 lines · Pekka Enberg

kernel/power/suspend2_core/utility.h 2005-07-05 23:48:59.000000000 +1000

Quoted 3 lines

diff -ruNp 604-utility-header.patch-old/kernel/power/suspend2_core/utility.h 604-utility-header.patch-new/kernel/power/suspend2_core/utility.h

kernel/power/suspend2_core/utility.h 2005-07-05 23:48:59.000000000 +1000 renamed from kernel/power/suspend2_core/utility.h 1970-01-01 10:00:00.000000000 +1000 +0 -0

Please do move these.

Okay.

Quoted 4 lines

kernel/power/suspend2_core/utility.h 2005-07-05 23:48:59.000000000 +1000

Quoted 2 lines
kernel/power/suspend2_core/utility.h 2005-07-05 23:48:59.000000000 +1000 renamed from kernel/power/suspend2_core/utility.h 1970-01-01 10:00:00.000000000 +1000 +2 -0
+
+extern int suspend_snprintf(char * buffer, int buffer_size, const char *fmt, ...);

What's wrong with regular snprintf?

If there's a buffer overrun, it returns the number of bytes it wanted to use, not the number actually used.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#88 lore raw

Re: Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch

Quoted 4 lines · Pekka Enberg
Quoted 4 lines

kernel/power/suspend2_core/utility.h line 12

Quoted 2 lines
kernel/power/suspend2_core/utility.h +2 -0
+
+extern int suspend_snprintf(char * buffer, int buffer_size, const char *fmt, ...);

What's wrong with regular snprintf?

Quoted 2 lines · Nigel Cunningham

If there's a buffer overrun, it returns the number of bytes it wanted to use, not the number actually used.

But on buffer overrun, you know it wrote size-1 characters. I am unconvinced you need a special snprintf() for suspend. Are there other potential users? If not, please consider dropping suspend_snprintf completelely.

Pekka

#89 lore raw

Re: [PATCH] [26/48] Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch

In reply to Pekka Enberg

Hi again.

Quoted 8 lines · Pekka Enberg
Quoted 7 lines

+ * suspend_snprintf
+ *
+ * Functionality : Print a string with parameters to a buffer of a

+ *                    limited size. Unlike vsnprintf, we return the number
+ *                    of bytes actually put in the buffer, not the number
+ *                    that would have been put in if it was big enough.

+ */

Please do move these.

Renamed and merged into lib/vsprintf.c.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#90 lore raw

Re: [PATCH] [26/48] Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch

In reply to Nigel Cunningham

Hi!

Quoted 40 lines

diff -ruNp 604-utility-header.patch-old/kernel/power/suspend2_core/utility.c 604-utility-header.patch-new/kernel/power/suspend2_core/utility.c

kernel/power/suspend2_core/utility.c +36 -0
@@ -0,0 +1,46 @@
+/*
+ * kernel/power/utility.c
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <[email protected]>
+ * 
+ * This file is released under the GPLv2.
+ *
+ * Routines that only suspend uses at the moment, but which might move
+ * when we merge because they're generic.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <asm/string.h>
+
+#include "pageflags.h"
+
+/*
+ * suspend_snprintf
+ *
+ * Functionality    : Print a string with parameters to a buffer of a 
+ *                    limited size. Unlike vsnprintf, we return the number
+ *                    of bytes actually put in the buffer, not the number
+ *                    that would have been put in if it was big enough.
+ */
+int suspend_snprintf(char * buffer, int buffer_size, const char *fmt, ...)
+{
+	int result;
+	va_list args;
+
+	if (!buffer_size) {
+		return 0;
+	}
+

kernel/power/suspend2_core/utility.c line 46

Quoted 10 lines
kernel/power/suspend2_core/utility.c +10 -0
+	va_start(args, fmt);
+	result = vsnprintf(buffer, buffer_size, fmt, args);
+	va_end(args);
+
+	if (result > buffer_size) {
+		return buffer_size;
+	}
+
+	return result;
+}

Eh, this needs to be either generic function or not there at all.
Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#91 lore raw

PATCH 27/48 Suspend2 2.1.9.8 for 2.6.12: 604-utility.patch

In reply to Nigel Cunningham
kernel/power/suspend.h +28 -0
diff -ruNp 605-kernel_power_suspend-header.patch-old/kernel/power/suspend.h 605-kernel_power_suspend-header.patch-new/kernel/power/suspend.h
@@ -0,0 +1,28 @@
+/*
+ * kernel/power/suspend.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * It contains declarations used throughout swsusp.
+ *
+ */
+
+#ifndef KERNEL_POWER_SUSPEND_H
+#define KERNEL_POWER_SUSPEND_H
+
+#define SUSPEND_PD_PAGES(x)     (((x)*sizeof(struct pbe))/PAGE_SIZE+1)
+   
+/* mm/page_alloc.c */
+extern void drain_local_pages(void);
+
+void save_processor_state(void);
+void restore_processor_state(void);
+struct saved_context;
+void __save_processor_state(struct saved_context *ctxt);
+void __restore_processor_state(struct saved_context *ctxt);
+
+extern suspend_pagedir_t *pagedir_nosave __nosavedata;
+
+#endif
#92 lore raw

PATCH 28/48 Suspend2 2.1.9.8 for 2.6.12: 605-kernel_power_suspend.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/all_settings.c +325 -0
diff -ruNp 606-all-settings.patch-old/kernel/power/suspend2_core/all_settings.c 606-all-settings.patch-new/kernel/power/suspend2_core/all_settings.c
@@ -0,0 +1,325 @@
+/*
+ * /kernel/power/suspend2_core/all_settings.c
+ *
+ * Suspend2 is released under the GPLv2.
+ * 
+ * Copyright (C) 2002-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file provides the all_settings proc entry, used to save
+ * and restore all suspend2 settings en masse.
+ */
+
+#include <linux/mm.h>
+#include <linux/suspend.h>
+#include <asm/uaccess.h>
+
+#include "plugins.h"
+#include "proc.h"
+#include "suspend2_common.h"
+#include "prepare_image.h"
+#include "power_off.h"
+#include "io.h"
+
+#define ALL_SETTINGS_VERSION 4
+
+static int resume2_len;
+
+/*
+ * suspend_write2_compat_proc.
+ *
+ * This entry allows all of the settings to be set at once. 
+ * It was originally for compatibility with pre- /proc/suspend
+ * versions, but has been retained because it makes saving and
+ * restoring the configuration simpler.
+ */
+static int suspend2_write_compat_proc(struct file *file, const char * buffer,
+		unsigned long count, void * data)
+{
+	char * buf1 = (char *) get_zeroed_page(GFP_ATOMIC), *curbuf, *lastbuf;
+	char * buf2 = (char *) get_zeroed_page(GFP_ATOMIC); 
+	int i, file_offset = 0, used_size = 0, reparse_resume_device = 0;
+	unsigned long nextval;
+	struct suspend_plugin_ops * plugin;
+	struct plugin_header * plugin_header = NULL;
+	int version_applying = 0;
+
+	if ((!buf1) || (!buf2)) {
+		count = -ENOMEM;
+		goto out2;
+	}
+
+	while (file_offset < count) {
+		int length = count - file_offset;
+		if (length > (PAGE_SIZE - used_size))
+			length = PAGE_SIZE - used_size;
+
+		if (copy_from_user(buf1 + used_size, buffer + file_offset, length)) {
+			count = -EFAULT;
+			goto out2;
+		}
+
+		curbuf = buf1;
+
+		if (!file_offset) {
+			/* Integers first */
+			for (i = 0; i < 8; i++) {
+				if (!*curbuf)
+					break;
+				lastbuf = curbuf;
+				nextval = simple_strtoul(curbuf, &curbuf, 0);
+				if (curbuf == lastbuf)
+					break;
+				switch (i) {
+					case 0:
+						version_applying = nextval;
+						if (nextval < 3) {
+							printk("Error loading saved settings. This data is for version %ld, but kernel module supports format 3 or later.\n",
+									nextval);
+							goto out2;
+						}
+					case 1:
+						suspend_result = nextval;
+						break;
+					case 2:
+						suspend_action = nextval;
+						break;
+					case 3:
+#ifdef CONFIG_PM_DEBUG
+						suspend_debug_state = nextval;
+#endif
+						break;
+					case 4:
+						suspend_default_console_level = nextval;
+#ifndef CONFIG_PM_DEBUG
+						if (suspend_default_console_level > 1)
+							suspend_default_console_level = 1;
+#endif
+						break;
+					case 5:
+						image_size_limit = nextval;
+						break;
+					case 6:
+#ifdef CONFIG_ACPI
+						suspend2_powerdown_method = nextval;
+						if (suspend2_powerdown_method < 3)
+							suspend2_powerdown_method = 3;
+						if (suspend2_powerdown_method > 5)
+#endif
+							suspend2_powerdown_method = 5;
+						break;
+					case 7:
+						resume2_len = nextval;
+				}
+
+				curbuf++;
+				while (*curbuf == ' ')
+					curbuf++;
+
+				if (version_applying == 3 && i == 7)
+					break;
+			}
+
+			if (count <= (curbuf - buf1))
+				goto out;
+			else {
+				list_for_each_entry(plugin, &suspend_plugins, plugin_list)
+					plugin->disabled = 1;
+			}
+
+			if (version_applying > 3) {
+				/* Resume2.
+				 *
+				 * Since the integers will be short and resume2 is 255 chars max,
+				 * there's no danger of buffer overflow.
+				 */
+				strncpy(resume2_file, curbuf, resume2_len);
+				curbuf += resume2_len + 1;
+			}
+		}
+
+		if (((unsigned long) curbuf  & ~PAGE_MASK) + sizeof(plugin_header) > PAGE_SIZE)
+			goto shift_buffer;
+		
+		/* Plugins */
+		plugin_header = (struct plugin_header *) curbuf;
+
+		if (((unsigned long) curbuf & ~PAGE_MASK) + sizeof(plugin_header) + plugin_header->data_length  > PAGE_SIZE)
+			goto shift_buffer;
+		
+		if (plugin_header->signature != 0xADEDC0DE) {
+			printk("Bad plugin data signature.\n");
+			break;
+		}
+
+		plugin = find_plugin_given_name(plugin_header->name);
+
+		if (plugin) {	/* May validly have config saved for a plugin not now loaded */
+			if ((plugin->type == WRITER_PLUGIN) &&
+			    ((!active_writer && plugin->disabled && !plugin_header->disabled) ||
+			     (active_writer == plugin && plugin_header->disabled)))
+				reparse_resume_device = 1;
+			plugin->disabled = plugin_header->disabled;
+			if (plugin_header->data_length)
+				plugin->load_config_info(curbuf + sizeof(struct plugin_header), 
+						plugin_header->data_length);
+		} else
+			printk("Data for plugin %s not used because not currently loaded.\n", plugin_header->name);
+
+		curbuf += sizeof(struct plugin_header) + plugin_header->data_length;
+
+shift_buffer:
+		if (!(curbuf - buf1))
+			break;
+
+		file_offset += curbuf - buf1;
+		
+		used_size = PAGE_SIZE + buf1 - curbuf;
+		memcpy(buf2, curbuf, used_size);
+		memcpy(buf1, buf2, used_size);
+	}
+out:
+	attempt_to_parse_resume_device();
+
+out2:
+	if (buf1)
+		free_pages((unsigned long) buf1, 0);
+
+	if (buf2)
+		free_pages((unsigned long) buf2, 0);
+	
+	return count;
+}
+
+/*
+ * suspend2_read_compat_proc.
+ *
+ * Like its sibling, this entry allows all of the settings
+ * to be read at once.
+ * It too was originally for compatibility with pre- /proc/suspend
+ * versions, but has been retained because it makes saving and
+ * restoring the configuration simpler.
+ */
+static int suspend2_read_compat_proc(char * page, char ** start, off_t off, int count,
+		int *eof, void *data)
+{
+	struct suspend_plugin_ops * this_plugin;
+	char * buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	int index = 1, file_pos = 0, page_offset = 0, len;
+	int copy_len = 0;
+	struct plugin_header plugin_header;
+
+	if (!buffer) {
+		printk("Failed to allocate a buffer for getting "
+				"plugin configuration info.\n");
+		return -ENOMEM;
+	}
+		
+	plugin_header.signature = 0xADEDC0DE;
+
+	len = sprintf(buffer, "%d %ld %ld %ld %d %d %ld %d %s\n",
+			ALL_SETTINGS_VERSION,
+			suspend_result,
+			suspend_action,
+			suspend_debug_state,
+			suspend_default_console_level,
+			image_size_limit,
+			suspend2_powerdown_method,
+			strlen(resume2_file),
+			resume2_file);
+
+	if (len >= off) {
+		copy_len = (len < off + count) ? len - off : count - off;
+		memcpy(page, buffer + off, copy_len);
+		page_offset+= copy_len;
+	}
+
+	file_pos += len;
+
+	/* 
+	 * We have to know which data goes with which plugin, so we at
+	 * least write a length of zero for a plugin. Note that we are
+	 * also assuming every plugin's config data takes <= PAGE_SIZE.
+	 */
+
+	/* For each plugin (in registration order) */
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+
+		/* Get the data from the plugin */
+		if (this_plugin->save_config_info) {
+			plugin_header.data_length = this_plugin->save_config_info(buffer);
+		} else
+			plugin_header.data_length = 0;
+
+		if (file_pos > (off + count)) {
+			file_pos += sizeof(struct plugin_header) + plugin_header.data_length;
+			continue;
+		}
+
+		len = 0;
+		if ((file_pos + sizeof(struct plugin_header) >= off) &&
+		    (file_pos < (off + count))) {
+
+			/* Save the details of the plugin */
+			memcpy(plugin_header.name, this_plugin->name, 
+					SUSPEND_MAX_PLUGIN_NAME_LENGTH);
+			plugin_header.disabled = this_plugin->disabled;
+			plugin_header.type = this_plugin->type;
+			plugin_header.index = index++;
+			
+			copy_len = sizeof(struct plugin_header);
+
+			if (copy_len + page_offset > count)
+				copy_len = count - page_offset;
+
+			memcpy(page + page_offset,
+				 ((char *) &plugin_header) + off + page_offset - file_pos,
+				 copy_len);	 
+
+			page_offset += copy_len;
+		}
+
+		file_pos += sizeof(struct plugin_header);
+
+		if (plugin_header.data_length && (file_pos >= off) && (file_pos < (off + count))) {
+			copy_len = plugin_header.data_length;
+
+			if (copy_len + page_offset > count + off)
+				copy_len = count - page_offset;
+			
+			memcpy(page + page_offset,
+				 buffer,
+				 copy_len);	 
+
+			page_offset += copy_len;
+
+		}
+
+		file_pos += plugin_header.data_length;
+		
+	}
+	free_pages((unsigned long) buffer, 0);
+	if (page_offset < count)
+		*eof = 1;
+	return page_offset;
+}
+
+static struct suspend_proc_data proc_params =
+	{ .filename			= "all_settings",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_CUSTOM,
+	  .data = {
+		  .special = {
+	  		 .read_proc	= suspend2_read_compat_proc,
+			 .write_proc	= suspend2_write_compat_proc,
+		  }
+	  }
+	}
+;
+
+/* Create the entry when we boot. */
+__init int suspend2_all_settings_proc_init(void)
+{
+	suspend_register_procfile(&proc_params);
+	return 0;
+}
+late_initcall(suspend2_all_settings_proc_init);
#93 lore raw

Re: [PATCH] [28/48] Suspend2 2.1.9.8 for 2.6.12: 605-kernel_power_suspend.patch

Hi!

Quoted 28 lines

diff -ruNp 606-all-settings.patch-old/kernel/power/suspend2_core/all_settings.c 606-all-settings.patch-new/kernel/power/suspend2_core/all_settings.c

kernel/power/suspend2_core/all_settings.c +24 -0
@@ -0,0 +1,325 @@
+/*
+ * /kernel/power/suspend2_core/all_settings.c
+ *
+ * Suspend2 is released under the GPLv2.
+ * 
+ * Copyright (C) 2002-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file provides the all_settings proc entry, used to save
+ * and restore all suspend2 settings en masse.
+ */
+
+#include <linux/mm.h>
+#include <linux/suspend.h>
+#include <asm/uaccess.h>
+
+#include "plugins.h"
+#include "proc.h"
+#include "suspend2_common.h"
+#include "prepare_image.h"
+#include "power_off.h"
+#include "io.h"
+
+#define ALL_SETTINGS_VERSION 4
+

kernel/power/suspend2_core/all_settings.c line 34

Quoted 10 lines
kernel/power/suspend2_core/all_settings.c +10 -0
+static int resume2_len;
+
+/*
+ * suspend_write2_compat_proc.
+ *
+ * This entry allows all of the settings to be set at once. 
+ * It was originally for compatibility with pre- /proc/suspend
+ * versions, but has been retained because it makes saving and
+ * restoring the configuration simpler.
+ */

Okay, and it is also extremely ugly. Now you have chance to clean it up, please drop it.
Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#94 lore raw

Re: [PATCH] [28/48] Suspend2 2.1.9.8 for 2.6.12: 605-kernel_power_suspend.patch

Hi.

Quoted 5 lines · Pavel Machek

Hi!

Quoted 3 lines

diff -ruNp 606-all-settings.patch-old/kernel/power/suspend2_core/all_settings.c 606-all-settings.patch-new/kernel/power/suspend2_core/all_settings.c

kernel/power/suspend2_core/all_settings.c +0 -0

[...]

Quoted 8 lines
Quoted 5 lines

+ * This entry allows all of the settings to be set at once.
+ * It was originally for compatibility with pre- /proc/suspend
+ * versions, but has been retained because it makes saving and
+ * restoring the configuration simpler.
+ */

Okay, and it is also extremely ugly. Now you have chance to clean it up, please drop it.

After checking with users, done.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#95 lore raw

PATCH 29/48 Suspend2 2.1.9.8 for 2.6.12: 606-all-settings.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/atomic_copy.c +465 -0
diff -ruNp 607-atomic-copy.patch-old/kernel/power/suspend2_core/atomic_copy.c 607-atomic-copy.patch-new/kernel/power/suspend2_core/atomic_copy.c
@@ -0,0 +1,465 @@
+/*
+ * SMP support:
+ * CPU enters this routine during suspend. All other CPUs enter
+ * __smp_suspend_lowlevel. The one through
+ * which the suspend is initiated (which, for simplicity, is always CPU 0)
+ * sends the others here using an IPI during do_suspend2_suspend_1. They
+ * remain here until after the atomic copy of the kernel is made, to ensure
+ * that they don't mess with memory in the meantime (even just idling will
+ * do that). Once the atomic copy is made, they are free to carry on idling.
+ * Note that we must let them go, because if we're using compression, the
+ * vfree calls in the compressors will result in IPIs being called and hanging
+ * because the CPUs are still here.
+ *
+ * At resume time, we do a similar thing. CPU 0 sends the others in here using
+ * an IPI. It then copies the original kernel back, restores its own processor
+ * context and flushes local tlbs before freeing the others to do the same.
+ * They can then go back to idling while CPU 0 reloads pageset 2, cleans up
+ * and unfreezes the processes.
+ *
+ * (Remember that freezing and thawing processes also uses IPIs, as may
+ * decompressing the data. Again, therefore, we cannot leave the other processors
+ * in here).
+ * 
+ * At the moment, we do nothing about APICs, even though the code is there.
+ */
+
+#include <linux/suspend.h>
+#include <linux/highmem.h>
+#include <linux/kthread.h>
+#include <asm/setup.h>
+#include <asm/suspend2.h>
+#include <asm/param.h>
+#include "suspend2_common.h"
+#include "io.h"
+#include "power_off.h"
+#include "version.h"
+#include "driver_model.h"
+#include "ui.h"
+#include "plugins.h"
+#include "atomic_copy.h"
+#include "suspend.h"
+#include "smp.h"
+
+volatile static int state1 __nosavedata = 0;
+volatile static int state2 __nosavedata = 0;
+volatile static int state3 __nosavedata = 0;
+volatile static int io_speed_save[2][2] __nosavedata;
+
+static dyn_pageflags_t __nosavedata origmap;
+static dyn_pageflags_t __nosavedata copymap;
+static int __nosavedata origoffset;
+static int __nosavedata copyoffset;
+
+__nosavedata char resume_commandline[COMMAND_LINE_SIZE];
+
+static atomic_t atomic_copy_hold;
+
+/**
+ * suspend2_resume_1
+ * Functionality   : Preparatory steps for copying the original kernel back.
+ * Called From     : do_suspend2_lowlevel
+ **/
+
+static void suspend2_resume_1(void)
+{
+	suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
+			name_suspend "About to copy pageset1 back...\n");
+
+	suspend_drivers_suspend(SUSPEND_DRIVERS_IRQS_ENABLED);
+	local_irq_disable(); /* irqs might have been re-enabled on us */
+
+	suspend_drivers_suspend(SUSPEND_DRIVERS_IRQS_DISABLED);
+	local_irq_enable();
+
+	suspend2_map_atomic_copy_pages();
+
+	/* Get other cpus ready to restore their original contexts */
+	smp_suspend();
+
+	local_irq_disable();
+
+	preempt_disable();
+
+	barrier();
+	mb();
+}
+
+/*
+ * suspend2_resume_2
+ * Functionality   : Steps taken after copying back the original kernel at
+ *                   resume.
+ * Key Assumptions : Will be able to read back secondary pagedir (if 
+ *                   applicable).
+ * Called From     : do_suspend2_lowlevel
+ */
+
+static void suspend2_resume_2(void)
+{
+	set_suspend_state(SUSPEND_NOW_RESUMING);
+	set_suspend_state(SUSPEND_PAGESET2_NOT_LOADED);
+
+	suspend2_unmap_atomic_copy_pages();
+
+	preempt_enable();
+
+	local_irq_disable();
+	suspend_drivers_resume(SUSPEND_DRIVERS_IRQS_DISABLED);
+	local_irq_enable();
+
+#if defined(CONFIG_PREEMPT) && defined(CONFIG_USE_3DNOW)
+	preempt_enable();
+#endif
+
+	suspend_drivers_resume(SUSPEND_DRIVERS_IRQS_ENABLED);
+
+	userui_redraw();
+
+	check_shift_keys(1, "About to reload secondary pagedir.");
+
+	read_pageset2(0);
+	clear_suspend_state(SUSPEND_PAGESET2_NOT_LOADED);
+	
+	suspend2_prepare_status(0, 0, "Cleaning up...");
+}
+
+
+/*
+ * suspend2_suspend_1
+ * Functionality   : Steps taken prior to saving CPU state and the image
+ *                   itself.
+ * Called From     : do_suspend2_lowlevel
+ */
+
+static void suspend2_suspend_1(void)
+{
+	/* Save other cpu contexts */
+	smp_suspend();
+
+	suspend_drivers_suspend(SUSPEND_DRIVERS_IRQS_ENABLED);
+
+	mb();
+	barrier();
+
+	preempt_disable();
+	local_irq_disable();
+
+	suspend_drivers_suspend(SUSPEND_DRIVERS_IRQS_DISABLED);
+}
+
+/*
+ * suspend2_suspend_2
+ * Functionality   : Steps taken after saving CPU state to save the
+ *                   image and powerdown/reboot or recover on failure.
+ * Key Assumptions : save_image returns zero on success; otherwise we need to
+ *                   clean up and exit. The state on exiting this routine 
+ *                   should be essentially the same as if we have suspended,
+ *                   resumed and reached the end of suspend2_resume_2.
+ * Called From     : do_suspend2_lowlevel
+ */
+extern void suspend_power_down(void);
+
+static void suspend2_suspend_2(void)
+{
+	if (!save_image_part1()) {
+		suspend_power_down();
+
+		if (suspend2_powerdown_method == 3) {
+			int temp_result;
+
+			temp_result = read_pageset2(1);
+
+			/* If that failed, we're sunk. Panic! */
+			if (temp_result)
+				panic("Attempt to reload pagedir 2 failed. Try rebooting.");
+		}
+	}
+
+	if (!TEST_RESULT_STATE(SUSPEND_ABORT_REQUESTED) &&
+	    !TEST_ACTION_STATE(SUSPEND_TEST_FILTER_SPEED) &&
+	    suspend2_powerdown_method != 3)
+		printk(KERN_EMERG name_suspend
+			"Suspend failed, trying to recover...\n");
+	barrier();
+	mb();
+}
+
+/*
+ * suspend2_copyback_low
+ */
+
+void suspend2_copyback_low(void)
+{
+	unsigned long * origpage;
+	unsigned long * copypage;
+	int loop;
+
+	origmap = pageset1_map;
+	copymap = pageset1_copy_map;
+
+	origoffset = __get_next_bit_on(origmap, -1);
+	copyoffset = __get_next_bit_on(copymap, -1);
+	
+	while ((origoffset < max_mapnr) && (!PageHighMem(pfn_to_page(origoffset)))) {
+		origpage = (unsigned long *) __va(origoffset << PAGE_SHIFT);
+		copypage = (unsigned long *) __va(copyoffset << PAGE_SHIFT);
+		
+		loop = (PAGE_SIZE / sizeof(unsigned long)) - 1;
+		
+		while (loop >= 0) {
+			*(origpage + loop) = *(copypage + loop);
+			loop--;
+		}
+		
+		origoffset = __get_next_bit_on(origmap, origoffset);
+		copyoffset = __get_next_bit_on(copymap, copyoffset);
+	}
+}
+
+/*
+ * suspend2_copyback_high
+ */
+void suspend2_copyback_high(void)
+{
+	unsigned long * origpage;
+	unsigned long * copypage;
+
+	while (origoffset < max_mapnr) {
+		origpage = (unsigned long *) kmap_atomic(pfn_to_page(origoffset), KM_USER1);
+		copypage = (unsigned long *) (lowmem_page_address(pfn_to_page(copyoffset)));
+
+		memcpy(origpage, copypage, PAGE_SIZE);
+
+		kunmap_atomic(origpage, KM_USER1);
+		
+		origoffset = __get_next_bit_on(origmap, origoffset);
+		copyoffset = __get_next_bit_on(copymap, copyoffset);
+	}
+}
+
+void do_suspend2_lowlevel(int resume)
+{
+	int loop;
+
+	if (!resume) {
+
+		suspend2_pre_copy();
+
+		suspend2_suspend_1();
+
+		suspend2_save_processor_context();	/* We need to capture registers and memory at "same time" */
+
+		suspend2_suspend_2();		/* If everything goes okay, this function does not return */
+		return;
+	}
+	
+	state1 = suspend_action;
+	state2 = suspend_debug_state;
+	state3 = console_loglevel;
+	for (loop = 0; loop < 4; loop++)
+		io_speed_save[loop/2][loop%2] = 
+			suspend_io_time[loop/2][loop%2];
+
+	memcpy(resume_commandline, saved_command_line, COMMAND_LINE_SIZE);
+
+	suspend2_pre_copyback();
+
+/*
+ * Final function for resuming: after copying the pages to their original
+ * position, it restores the register state.
+ *
+ * What about page tables? Writing data pages may toggle
+ * accessed/dirty bits in our page tables. That should be no problems
+ * with 4MB page tables. That's why we require have_pse.  
+ *
+ * Critical section here: noone should touch saved memory after
+ * do_suspend2_resume_1.
+ *
+ * If we're running with DEBUG_PAGEALLOC, the boot and resume kernels both have
+ * all the pages we need mapped into kernel space, so we don't need to change
+ * page protections while doing the copy-back.
+ */
+
+	suspend2_resume_1();
+
+	suspend2_copyback_low(); /* 0 = use logical addresses */
+	
+	suspend2_restore_processor_context();
+	suspend2_flush_caches();
+
+	BUG_ON(!irqs_disabled());
+	
+	/* Now we are running with our old stack, and with registers copied
+	 * from suspend time. Let's copy back those remaining Highmem pages. */
+
+	suspend2_copyback_high();
+
+	BUG_ON(!irqs_disabled());
+
+	suspend2_flush_caches();
+
+	suspend2_post_copyback();
+
+	suspend_action = state1;
+	suspend_debug_state = state2;
+	console_loglevel = state3;
+
+	for (loop = 0; loop < 4; loop++)
+		suspend_io_time[loop/2][loop%2] =
+			io_speed_save[loop/2][loop%2];
+
+	suspend2_resume_2();
+}
+
+/* suspend_copy_pageset1
+ *
+ * Description:	Make the atomic copy of pageset1. We can't use copy_page (as we
+ * 		once did) because we can't be sure what side effects it has. On
+ * 		my old Duron, with 3DNOW, kernel_fpu_begin increments preempt
+ * 		count, making our preempt count at resume time 4 instead of 3.
+ * 		
+ * 		We don't want to call kmap_atomic unconditionally because it has
+ * 		the side effect of incrementing the preempt count, which will
+ * 		leave it one too high post resume (the page containing the
+ * 		preempt count will be copied after its incremented. This is
+ * 		essentially the same problem.
+ */
+
+void suspend2_copy_pageset1(void)
+{
+	int i, source_index = -1, dest_index = -1;
+
+	for (i = 0; i < pageset1_size; i++) {
+		unsigned long * origvirt, *copyvirt;
+		struct page * origpage;
+		int loop = (PAGE_SIZE / sizeof(unsigned long)) - 1;
+
+		source_index = __get_next_bit_on(pageset1_map, source_index);
+		dest_index = __get_next_bit_on(pageset1_copy_map, dest_index);
+
+		origpage = pfn_to_page(source_index);
+		
+		copyvirt = (unsigned long *) page_address(pfn_to_page(dest_index));
+
+	       	if (PageHighMem(origpage))
+			origvirt = kmap_atomic(origpage, KM_USER1);
+		else
+			origvirt = page_address(origpage);
+
+		while (loop >= 0) {
+			*(copyvirt + loop) = *(origvirt + loop);
+			loop--;
+		}
+		
+
+		if (PageHighMem(origpage))
+			kunmap_atomic(origvirt, KM_USER1);
+	}
+}
+
+/*
+ * suspend2_map_atomic_copy_pages
+ *
+ * When DEBUG_PAGEALLOC is enabled, we need to map the pages before
+ * an atomic copy.
+ */
+#ifdef CONFIG_DEBUG_PAGEALLOC
+void suspend2_map_atomic_copy_pages(void)
+{
+	int i = 0, source_index = -1, dest_index = -1;
+
+	for (i = 0; i < pageset1_size; i++) {
+		int orig_was_mapped = 1, copy_was_mapped = 1;
+		struct page * origpage, * copypage;
+
+		source_index = __get_next_bit_on(pageset1_map, source_index);
+		dest_index = __get_next_bit_on(pageset1_copy_map, dest_index);
+
+		origpage = pfn_to_page(source_index);
+		copypage = pfn_to_page(dest_index);
+		
+	       	if (!PageHighMem(origpage)) {
+			orig_was_mapped = suspend_map_kernel_page(origpage, 1);
+			if ((!orig_was_mapped) &&
+			    (!test_suspend_state(SUSPEND_NOW_RESUMING)))
+				SetPageUnmap(origpage);
+		}
+
+		copy_was_mapped = suspend_map_kernel_page(copypage, 1);
+		if ((!copy_was_mapped) &&
+		    (!test_suspend_state(SUSPEND_NOW_RESUMING)))
+			SetPageUnmap(copypage);
+	}
+}
+
+/*
+ * suspend2_unmap_atomic_copy_pages
+ *
+ * We also need to unmap pages when DEBUG_PAGEALLOC is enabled.
+ */
+void suspend2_unmap_atomic_copy_pages(void)
+{
+	int i;
+	for (i = 0; i < max_mapnr; i++) {
+		struct page * page = pfn_to_page(i);
+		if (PageUnmap(page))
+			suspend_map_kernel_page(page, 0);
+	}
+}
+#endif
+
+int __suspend_atomic_restore(void *data)
+{
+	while atomic_read(&atomic_copy_hold)
+		schedule();
+
+	/* Suspend always runs on processor 0 */
+	ensure_on_processor_zero();
+
+	suspend2_prepare_status(0, 0, "Freezing processes");
+	
+	freeze_processes(1);
+	
+	suspend2_prepare_status(0, 0,
+		"Copying original kernel back");
+	
+	do_suspend2_lowlevel(1);
+
+	BUG();
+	
+	return 0;
+}
+
+
+void suspend_atomic_restore(void)
+{
+	LIST_HEAD(non_conflicting_pages);
+	unsigned long next;
+	struct page * this_page, * next_page;
+	
+	/* Allocate all memory available, then free only those pages
+	 * that don't conflict. This ensures that the stack for our
+	 * copy-back thread is non-conflicting */
+	while ((next = suspend2_get_nonconflicting_page())) {
+		struct page * page = virt_to_page(next);
+		list_add(&page->lru, &non_conflicting_pages);
+	}
+
+	list_for_each_entry_safe(this_page, next_page, &non_conflicting_pages, lru)
+		__free_pages(this_page, 0);
+
+	atomic_set(&atomic_copy_hold, 1);
+
+	/* Now start the new thread */
+	BUG_ON((kernel_thread(__suspend_atomic_restore, 0,
+			CLONE_KERNEL) < 0));
+
+	suspend2_release_conflicting_pages();
+	
+	atomic_set(&atomic_copy_hold, 0);
+	
+	while(1) {
+		try_to_freeze();
+		schedule();
+	}
+}
kernel/power/suspend2_core/atomic_copy.h +3 -0
diff -ruNp 607-atomic-copy.patch-old/kernel/power/suspend2_core/atomic_copy.h 607-atomic-copy.patch-new/kernel/power/suspend2_core/atomic_copy.h
@@ -0,0 +1,3 @@
+extern inline void move_stack_to_nonconflicing_area(void);
+extern int save_image_part1(void);
+extern void suspend_atomic_restore(void);
#96 lore raw

Re: [PATCH] [29/48] Suspend2 2.1.9.8 for 2.6.12: 606-all-settings.patch

Hi!

kernel/power/suspend2_core/atomic_copy.c line 170

Quoted 9 lines
kernel/power/suspend2_core/atomic_copy.c +9 -0
+static void suspend2_suspend_2(void)
+{
+	if (!save_image_part1()) {
+		suspend_power_down();
+
+		if (suspend2_powerdown_method == 3) {
+			int temp_result;
+
+			temp_result = read_pageset2(1);

Is that just me or do I see way too many numbers. suspend2_suspend_2 is really funny name for a functions. powerdown_method should really use some symbolic constants.
Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#97 lore raw

Re: [PATCH] [29/48] Suspend2 2.1.9.8 for 2.6.12: 606-all-settings.patch

Hi.

Quoted 16 lines · Pavel Machek

Hi!

kernel/power/suspend2_core/atomic_copy.c line 170

Quoted 9 lines
kernel/power/suspend2_core/atomic_copy.c +9 -0
+static void suspend2_suspend_2(void)
+{
+	if (!save_image_part1()) {
+		suspend_power_down();
+
+		if (suspend2_powerdown_method == 3) {
+			int temp_result;
+
+			temp_result = read_pageset2(1);

Is that just me or do I see way too many numbers. suspend2_suspend_2 is really funny name for a functions. powerdown_method should really use some symbolic constants.

No, it's not just you. It's one of those hangovers from the original code that I hadn't gotten around to cleaning up.

Symbolic constants now in place for the powerdown method too.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#98 lore raw

PATCH 30/48 Suspend2 2.1.9.8 for 2.6.12: 607-atomic-copy.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/compression.c +636 -0
diff -ruNp 608-compression.patch-old/kernel/power/suspend2_core/compression.c 608-compression.patch-new/kernel/power/suspend2_core/compression.c
@@ -0,0 +1,636 @@
+/*
+ * kernel/power/suspend2_core/compression.c
+ *
+ * Copyright (C) 2003-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * This file contains data compression routines for suspend,
+ * using LZH compression.
+ *
+ */
+
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/highmem.h>
+#include <linux/vmalloc.h>
+#include <linux/crypto.h>
+
+#include "suspend.h"
+#include "plugins.h"
+#include "proc.h"
+#include "suspend2_common.h"
+#include "utility.h"
+#include "io.h"
+
+#define S2C_WRITE 0
+#define S2C_READ 1
+
+static int s2_expected_compression = 0;
+
+static struct suspend_plugin_ops s2_compression_ops;
+static struct suspend_plugin_ops * next_driver;
+
+static char s2_compressor_name[32];
+static struct crypto_tfm * s2_compressor_transform;
+
+static u8 *local_buffer = NULL;
+static u8 *page_buffer = NULL;
+static unsigned int bufofs;
+
+static int position = 0;
+
+/* ---- Local buffer management ---- */
+
+/* allocate_local_buffer
+ *
+ * Description:	Allocates a page of memory for buffering output.
+ * Returns:	Int: Zero if successful, -ENONEM otherwise.
+ */
+
+static int allocate_local_buffer(void)
+{
+	if (!local_buffer) {
+		local_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	
+		if (!local_buffer) {
+			printk(KERN_ERR
+				"Failed to allocate the local buffer for "
+				"suspend2 compression driver.\n");
+			return -ENOMEM;
+		}
+	}
+
+	if (!page_buffer) {
+		page_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	
+		if (!page_buffer) {
+			printk(KERN_ERR
+				"Failed to allocate the page buffer for "
+				"suspend2 compression driver.\n");
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+/* free_local_buffer
+ *
+ * Description:	Frees memory allocated for buffering output.
+ */
+
+static inline void free_local_buffer(void)
+{
+	if (local_buffer)
+		free_pages((unsigned long) local_buffer, 0);
+
+	local_buffer = NULL;
+
+	if (page_buffer)
+		free_pages((unsigned long) page_buffer, 0);
+
+	page_buffer = NULL;
+}
+
+/* suspend2_crypto_cleanup
+ *
+ * Description:	Frees memory allocated for our labours.
+ */
+
+static void suspend2_crypto_cleanup(void)
+{
+	if (s2_compressor_transform) {
+		crypto_free_tfm(s2_compressor_transform);
+		s2_compressor_transform = NULL;
+	}
+}
+
+/* suspend2_crypto_prepare
+ *
+ * Description:	Prepare to do some work by allocating buffers and transforms.
+ * Returns:	Int: Zero if successful, -ENONEM otherwise.
+ */
+
+static int s2_compress_crypto_prepare(int mode)
+{
+	if (!*s2_compressor_name) {
+		printk("Suspend2: Compression enabled but no compressor name set.\n");
+		return 1;
+	}
+
+	if (!(s2_compressor_transform = crypto_alloc_tfm(s2_compressor_name, 0))) {
+		printk("Suspend2: Failed to initialise the compression transform.\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+/* ---- Exported functions ---- */
+
+/* write_init()
+ *
+ * Description:	Allocate buffers and prepare to compress data.
+ * Arguments:	Stream_number:	Ignored.
+ * Returns:	Zero on success, -ENOMEM if unable to vmalloc.
+ */
+
+static int s2_compress_write_init(int stream_number)
+{
+	int result;
+	
+	next_driver = get_next_filter(&s2_compression_ops);
+
+	if (!next_driver) {
+		printk("Compression Driver: Argh! No one wants my output!");
+		return -ECHILD;
+	}
+
+	if ((result = s2_compress_crypto_prepare(S2C_WRITE))) {
+		return result;
+	}
+	
+	if ((result = allocate_local_buffer()))
+		return result;
+
+	/* Only reset the stats if starting to write an image */
+	if (stream_number == 2)
+		bytes_in = bytes_out = 0;
+	
+	bufofs = 0;
+
+	position = 0;
+
+	return 0;
+}
+
+/* s2_compress_write()
+ *
+ * Description:	Helper function for write_chunk. Write the compressed data.
+ * Arguments:	u8*:		Output buffer to be written.
+ * 		unsigned int:	Length of buffer.
+ * Return:	int:		Result to be passed back to caller.
+ */
+
+static int s2_compress_write (u8 *buffer, unsigned int len)
+{
+	int ret;
+
+	bytes_out += len;
+
+	while (len + bufofs > PAGE_SIZE) {
+		unsigned int chunk = PAGE_SIZE - bufofs;
+		memcpy (local_buffer + bufofs, buffer, chunk);
+		buffer += chunk;
+		len -= chunk;
+		bufofs = 0;
+		if ((ret = next_driver->ops.filter.write_chunk(virt_to_page(local_buffer))) < 0)
+			return ret;
+	}
+	memcpy (local_buffer + bufofs, buffer, len);
+	bufofs += len;
+	return 0;
+}
+
+/* s2_compress_write_chunk()
+ *
+ * Description:	Compress a page of data, buffering output and passing on
+ * 		filled pages to the next plugin in the pipeline.
+ * Arguments:	Buffer_page:	Pointer to a buffer of size PAGE_SIZE, 
+ * 				containing data to be compressed.
+ * Returns:	0 on success. Otherwise the error is that returned by later
+ * 		plugins, -ECHILD if we have a broken pipeline or -EIO if
+ * 		zlib errs.
+ */
+
+static int s2_compress_write_chunk(struct page * buffer_page)
+{
+	int ret; 
+	unsigned int len;
+	u16 len_written;
+	char * buffer_start;
+	
+	if (!s2_compressor_transform)
+		return next_driver->ops.filter.write_chunk(buffer_page);
+
+	buffer_start = kmap(buffer_page);
+
+	bytes_in += PAGE_SIZE;
+
+	len = PAGE_SIZE;
+
+	ret = crypto_comp_compress(s2_compressor_transform,
+			buffer_start, PAGE_SIZE,
+			page_buffer, &len);
+	
+	if (ret) {
+		printk("Compression failed.\n");
+		goto failure;
+	}
+	
+	len_written = (u16) len;
+		
+	if ((ret = s2_compress_write((u8 *)&len_written, 2)) >= 0) {
+		if ((ret = s2_compress_write((u8 *) &position, sizeof(position))))
+			return -EIO;
+		if (len < PAGE_SIZE) { // some compression
+			position += len;
+			ret = s2_compress_write(page_buffer, len);
+		} else {
+			ret = s2_compress_write(buffer_start, PAGE_SIZE);
+			position += PAGE_SIZE;
+		}
+	}
+	position += 2 + sizeof(int);
+
+
+failure:
+	kunmap(buffer_page);
+	return ret;
+}
+
+/* write_cleanup()
+ *
+ * Description: Write unflushed data and free workspace.
+ * Returns:	Result of writing last page.
+ */
+
+static int s2_compress_write_cleanup(void)
+{
+	int ret = 0;
+	
+	if (s2_compressor_transform)
+		ret = next_driver->ops.filter.write_chunk(virt_to_page(local_buffer));
+
+	suspend2_crypto_cleanup();
+	free_local_buffer();
+
+	return ret;
+}
+
+/* read_init()
+ *
+ * Description:	Prepare to read a new stream of data.
+ * Arguments:	int: Section of image about to be read.
+ * Returns:	int: Zero on success, error number otherwise.
+ */
+
+static int s2_compress_read_init(int stream_number)
+{
+	int result;
+
+	next_driver = get_next_filter(&s2_compression_ops);
+
+	if (!next_driver) {
+		printk("Compression Driver: Argh! No one wants "
+				"to feed me data!");
+		return -ECHILD;
+	}
+	
+	if ((result = s2_compress_crypto_prepare(S2C_READ)))
+		return result;
+	
+	if ((result = allocate_local_buffer()))
+		return result;
+
+	bufofs = PAGE_SIZE;
+
+	position = 0;
+
+	return 0;
+}
+
+/* s2_compress_read()
+ *
+ * Description:	Read data into compression buffer.
+ * Arguments:	u8 *:		Address of the buffer.
+ * 		unsigned int:	Length
+ * Returns:	int:		Result of reading the image chunk.
+ */
+
+static int s2_compress_read (u8 * buffer, unsigned int len)
+{
+	int ret;
+
+	while (len + bufofs > PAGE_SIZE) {
+		unsigned int chunk = PAGE_SIZE - bufofs;
+		memcpy(buffer, local_buffer + bufofs, chunk);
+		buffer += chunk;
+		len -= chunk;
+		bufofs = 0;
+		if ((ret = next_driver->ops.filter.read_chunk(
+				virt_to_page(local_buffer), SUSPEND_SYNC)) < 0) {
+			return ret;
+		}
+	}
+	memcpy (buffer, local_buffer + bufofs, len);
+	bufofs += len;
+	return 0;
+}
+
+/* s2_compress_read_chunk()
+ *
+ * Description:	Retrieve data from later plugins and decompress it until the
+ * 		input buffer is filled.
+ * Arguments:	Buffer_start: 	Pointer to a buffer of size PAGE_SIZE.
+ * 		Sync:		Whether the previous plugin (or core) wants its
+ * 				data synchronously.
+ * Returns:	Zero if successful. Error condition from me or from downstream
+ * 		on failure.
+ */
+
+static int s2_compress_read_chunk(struct page * buffer_page, int sync)
+{
+	int ret, position_saved; 
+	unsigned int len;
+	u16 len_written;
+	char * buffer_start;
+
+	if (!s2_compressor_transform)
+		return next_driver->ops.filter.read_chunk(buffer_page, SUSPEND_ASYNC);
+
+	/* 
+	 * All our reads must be synchronous - we can't decompress
+	 * data that hasn't been read yet.
+	 */
+
+	buffer_start = kmap(buffer_page);
+
+	if ((ret = s2_compress_read ((u8 *)&len_written, 2)) >= 0) {
+		len = (unsigned int) len_written;
+		ret = s2_compress_read((u8 *) &position_saved, sizeof(position_saved));
+		if (ret)
+			return ret;
+
+		if (position != position_saved) {
+			printk("Position saved (%d) != position I'm at now (%d).\n",
+					position_saved, position);
+			BUG_ON(1);
+		}
+		if (len >= PAGE_SIZE) { // uncompressed
+			ret = s2_compress_read(buffer_start, PAGE_SIZE);
+			if (ret)
+				return ret;
+
+			position += PAGE_SIZE;
+		} else { // compressed
+			if ((ret = s2_compress_read(page_buffer, len)) >= 0) {
+				int outlen = PAGE_SIZE;
+				/* Important note.
+				 *
+				 * For Deflate, decompression return values may represent
+				 * errors. Deflate complains when everything is alright, so
+				 * we ignore the errors unless the number of output bytes is
+				 * not PAGE_SIZE.
+				 */
+				crypto_comp_decompress(s2_compressor_transform, 
+						page_buffer, len,
+						buffer_start, &outlen);
+				if (outlen != PAGE_SIZE) {
+					printk("Decompression yielded %ld bytes instead of %d.\n", PAGE_SIZE, outlen);
+					ret = -EIO;
+				} else
+					ret = 0;
+			}
+			position += len;
+		}
+		position += 2 + sizeof(int);
+	} else
+		printk("Compress_read returned %d.", ret);
+	kunmap(buffer_page);
+	return ret;
+}
+
+/* read_cleanup()
+ *
+ * Description:	Clean up after reading part or all of a stream of data.
+ * Returns:	int: Always zero. Never fails.
+ */
+
+static int s2_compress_read_cleanup(void)
+{ 
+	suspend2_crypto_cleanup();
+	free_local_buffer();
+	return 0;
+}
+
+/* s2_compress_print_debug_stats
+ *
+ * Description:	Print information to be recorded for debugging purposes into a
+ * 		buffer.
+ * Arguments:	buffer: Pointer to a buffer into which the debug info will be
+ * 			printed.
+ * 		size:	Size of the buffer.
+ * Returns:	Number of characters written to the buffer.
+ */
+
+static int s2_compress_print_debug_stats(char * buffer, int size)
+{
+	int pages_in = bytes_in >> PAGE_SHIFT, 
+		pages_out = bytes_out >> PAGE_SHIFT;
+	int len;
+	
+	/* Output the compression ratio achieved. */
+	len = suspend_snprintf(buffer, size, "- Compressor %s enabled.\n",
+			s2_compressor_name);
+	if (pages_in)
+		len+= suspend_snprintf(buffer+len, size - len,
+		  "  Compressed %ld bytes into %ld (%d percent compression).\n",
+		  bytes_in, bytes_out, (pages_in - pages_out) * 100 / pages_in);
+	return len;
+}
+
+/* compression_memory_needed
+ *
+ * Description:	Tell the caller how much memory we need to operate during
+ * 		suspend/resume.
+ * Returns:	Unsigned long. Maximum number of bytes of memory required for
+ * 		operation.
+ */
+
+static unsigned long s2_compress_memory_needed(void)
+{
+	return PAGE_SIZE;
+}
+
+static unsigned long s2_compress_storage_needed(void)
+{
+	return 2 * sizeof(unsigned long) + sizeof(int);
+}
+
+/* s2_compress_save_config_info
+ *
+ * Description:	Save informaton needed when reloading the image at resume time.
+ * Arguments:	Buffer:		Pointer to a buffer of size PAGE_SIZE.
+ * Returns:	Number of bytes used for saving our data.
+ */
+
+static int s2_compress_save_config_info(char * buffer)
+{
+	int namelen = strlen(s2_compressor_name) + 1;
+	int total_len;
+	
+	*((unsigned long *) buffer) = bytes_in;
+	*((unsigned long *) (buffer + sizeof(unsigned long))) = bytes_out;
+	*((int *) (buffer + 2 * sizeof(unsigned long))) = s2_expected_compression;
+	*((int *) (buffer + 3 * sizeof(unsigned long))) = namelen;
+	strncpy(buffer + 4 * sizeof(unsigned long), s2_compressor_name, namelen);
+	total_len = 2 * sizeof(unsigned long) + 2 * sizeof(int) + namelen;
+	return total_len;
+}
+
+/* s2_compress_load_config_info
+ *
+ * Description:	Reload information needed for decompressing the image at 
+ * 		resume time.
+ * Arguments:	Buffer:		Pointer to the start of the data.
+ *		Size:		Number of bytes that were saved.
+ */
+
+static void s2_compress_load_config_info(char * buffer, int size)
+{
+	int namelen;
+	
+	bytes_in = *((unsigned long *) buffer);
+	bytes_out = *((unsigned long *) (buffer + sizeof(unsigned long)));
+	s2_expected_compression = *((int *) (buffer + 2 * sizeof(unsigned long)));
+	namelen = *((int *) (buffer + 3 * sizeof(unsigned long)));
+	strncpy(s2_compressor_name, buffer + 4 * sizeof(unsigned long), namelen);
+	return;
+}
+
+/* s2_compress_get_expected_compression
+ * 
+ * Description:	Returns the expected ratio between data passed into this plugin
+ * 		and the amount of data output when writing.
+ * Returns:	100 if the plugin is disabled. Otherwise the value set by the
+ * 		user via our proc entry.
+ */
+
+static int s2_compress_get_expected_compression(void)
+{
+	return 100 - s2_expected_compression;
+}
+
+static void s2_compressor_disable_if_empty(void)
+{
+	s2_compression_ops.disabled = !(*s2_compressor_name);
+}
+
+static int s2_compress_initialise(int starting_cycle)
+{
+	if (starting_cycle)
+		s2_compressor_disable_if_empty();
+
+	return 0;
+}
+/*
+ * data for our proc entries.
+ */
+
+static struct suspend_proc_data proc_params[] = {
+	{
+		.filename			= "expected_compression",
+		.permissions			= PROC_RW,
+		.type				= SUSPEND_PROC_DATA_INTEGER,
+		.data = {
+			.integer = {
+				.variable	= &s2_expected_compression,
+				.minimum	= 0,
+				.maximum	= 99,
+			}
+		}
+	},
+
+	{
+		.filename			= "disable_compression",
+		.permissions			= PROC_RW,
+		.type				= SUSPEND_PROC_DATA_INTEGER,
+		.data = {
+			.integer = {
+				.variable	= &s2_compression_ops.disabled,
+				.minimum	= 0,
+				.maximum	= 1,
+			}
+		}
+	},
+
+	{
+		.filename			= "compressor",
+		.permissions			= PROC_RW,
+		.type				= SUSPEND_PROC_DATA_STRING,
+		.data = {
+			.string = {
+				.variable	= s2_compressor_name,
+				.max_length	= 31,
+			}
+		},
+		.write_proc			= &s2_compressor_disable_if_empty,
+	}
+};
+
+/*
+ * Ops structure.
+ */
+
+static struct suspend_plugin_ops s2_compression_ops = {
+	.type			= FILTER_PLUGIN,
+	.name			= "Suspend2 Compressor",
+	.module			= THIS_MODULE,
+	.memory_needed 		= s2_compress_memory_needed,
+	.print_debug_info	= s2_compress_print_debug_stats,
+	.save_config_info	= s2_compress_save_config_info,
+	.load_config_info	= s2_compress_load_config_info,
+	.storage_needed		= s2_compress_storage_needed,
+	
+	.initialise		= s2_compress_initialise,
+	
+	.write_init		= s2_compress_write_init,
+	.write_cleanup		= s2_compress_write_cleanup,
+	.read_init		= s2_compress_read_init,
+	.read_cleanup		= s2_compress_read_cleanup,
+
+	.ops = {
+		.filter = {
+			.write_chunk		= s2_compress_write_chunk,
+			.read_chunk		= s2_compress_read_chunk,
+			.expected_compression	= s2_compress_get_expected_compression,
+		}
+	}
+};
+
+/* ---- Registration ---- */
+
+static __init int s2_compress_load(void)
+{
+	int result;
+	int i, numfiles = sizeof(proc_params) / sizeof(struct suspend_proc_data);
+
+	printk("Software Suspend Compression Driver loading.\n");
+	if (!(result = suspend_register_plugin(&s2_compression_ops))) {
+		for (i=0; i< numfiles; i++)
+			suspend_register_procfile(&proc_params[i]);
+	} else
+		printk("Software Suspend Compression Driver unable to register!\n");
+	return result;
+}
+
+#ifdef MODULE
+static __exit void s2_compress_unload(void)
+{
+	printk("Software Suspend Compression Driver unloading.\n");
+	for (i=0; i< numfiles; i++)
+		suspend_unregister_procfile(&proc_params[i]);
+	suspend_unregister_plugin(&s2_compression_ops);
+}
+
+
+module_init(s2_compress_load);
+module_exit(s2_compress_unload);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nigel Cunningham");
+MODULE_DESCRIPTION("Compression Support for Suspend2");
+#else
+late_initcall(s2_compress_load);
+#endif
#99 lore raw

Re: [PATCH] [30/48] Suspend2 2.1.9.8 for 2.6.12: 607-atomic-copy.patch

Hi!

Quoted 3 lines

--- 608-compression.patch-old/kernel/power/suspend2_core/compression.c 1970-01-01 10:00:00.000000000 +1000
+++
608-compression.patch-new/kernel/power/suspend2_core/compression.c

                                         ~~~~~~~~~~~~~

suspend2_core looks like an extremely bad name for a directory... And this is really plugin, not a core, no? Plus it would be nice to drop non-essential stuff for initial submit, so that it is not *that* big to review.
Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#100 lore raw

Re: [PATCH] [30/48] Suspend2 2.1.9.8 for 2.6.12: 607-atomic-copy.patch

Hi.

Quoted 11 lines · Pavel Machek

Hi!

Quoted 3 lines

--- 608-compression.patch-old/kernel/power/suspend2_core/compression.c 1970-01-01 10:00:00.000000000 +1000
+++
608-compression.patch-new/kernel/power/suspend2_core/compression.c

                                         ~~~~~~~~~~~~~

suspend2_core looks like an extremely bad name for a directory... And this is really plugin, not a core, no? Plus it would be nice to drop non-essential stuff for initial submit, so that it is not *that* big to review.

Suspend2_core was just to keep things nicely separated for the moment. I've already shifted everything into kernel/power after Pekka's email.

Regarding non essential stuff, the compression and encryption parts are really quite small. LZF Compression doubles the speed, and encryption is considered important by people who care about security. It also helps you see why the plugin stuff is useful. Of course plugin isn't really the right name anymore - it's more of an internal api.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#101 lore raw

PATCH 31/48 Suspend2 2.1.9.8 for 2.6.12: 608-compression.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/driver_model.c +95 -0
diff -ruNp 609-driver-model.patch-old/kernel/power/suspend2_core/driver_model.c 609-driver-model.patch-new/kernel/power/suspend2_core/driver_model.c
@@ -0,0 +1,95 @@
+/*
+ * kernel/power/suspend2_core/driver_model.c
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Support for the driver model and ACPI sleep states.
+ */
+
+#include <linux/pm.h>
+#include "driver_model.h"
+#include "power_off.h"
+
+extern struct pm_ops * pm_ops;
+static u32 pm_disk_mode_save;
+
+#ifdef CONFIG_ACPI
+static int suspend_pm_state_used = 0;
+extern u32 acpi_leave_sleep_state (u8 sleep_state);
+#endif
+
+/* suspend_drivers_init
+ *
+ * Store the original pm ops settings.
+ */
+int suspend_drivers_init(void)
+{
+	if (pm_ops) {
+		pm_disk_mode_save = pm_ops->pm_disk_mode;
+		pm_ops->pm_disk_mode = PM_DISK_PLATFORM;
+	}
+			
+	return 0;
+}
+
+/* suspend_drivers_cleanup
+ *
+ * Restore the original pm disk mode.
+ */
+void suspend_drivers_cleanup(void)
+{
+	if (pm_ops)
+		pm_ops->pm_disk_mode = pm_disk_mode_save;
+}
+
+/* suspend_drivers_suspend
+ *
+ * Suspend the drivers after an atomic copy.
+ */
+int suspend_drivers_suspend(int stage)
+{
+	int result = 0;
+	const pm_message_t state = PMSG_FREEZE;
+
+	switch (stage) {
+		case SUSPEND_DRIVERS_IRQS_DISABLED:
+			BUG_ON(!irqs_disabled());
+			result = device_power_down(state);
+			BUG_ON(!irqs_disabled());
+			break;
+
+		case SUSPEND_DRIVERS_IRQS_ENABLED:
+			BUG_ON(irqs_disabled());
+			result = device_suspend(state);
+			BUG_ON(irqs_disabled());
+			break;
+	}
+	return result;
+}
+
+/* suspend_drivers_resume
+ *
+ * Resume the drivers after an atomic copy (save or restore)
+ */
+void suspend_drivers_resume(int stage)
+{
+	switch (stage) {
+		case SUSPEND_DRIVERS_IRQS_DISABLED:
+			BUG_ON(!irqs_disabled());
+			device_power_up();
+			BUG_ON(!irqs_disabled());
+			break;
+
+		case SUSPEND_DRIVERS_IRQS_ENABLED:
+			BUG_ON(irqs_disabled());
+#ifdef CONFIG_ACPI
+			if (suspend_pm_state_used)
+				acpi_leave_sleep_state(suspend_pm_state_used);
+#endif
+			suspend_pm_state_finish();
+			BUG_ON(irqs_disabled());
+			break;
+	}
+}
kernel/power/suspend2_core/driver_model.h +24 -0
diff -ruNp 609-driver-model.patch-old/kernel/power/suspend2_core/driver_model.h 609-driver-model.patch-new/kernel/power/suspend2_core/driver_model.h
@@ -0,0 +1,24 @@
+/*
+ * kernel/power/driver_model.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Support for the driver model.
+ */
+
+/*	suspend_drivers_resume
+ *	@stage - One of...
+ */
+
+enum {
+	SUSPEND_DRIVERS_IRQS_DISABLED,
+	SUSPEND_DRIVERS_IRQS_ENABLED,
+};
+
+extern int suspend_drivers_init(void);
+extern void suspend_drivers_cleanup(void);
+
+extern int suspend_drivers_suspend(int stage);
+extern void suspend_drivers_resume(int stage);
#102 lore raw

Re: [PATCH] [31/48] Suspend2 2.1.9.8 for 2.6.12: 608-compression.patch

Hi!

Quoted 29 lines

diff -ruNp 609-driver-model.patch-old/kernel/power/suspend2_core/driver_model.c 609-driver-model.patch-new/kernel/power/suspend2_core/driver_model.c

kernel/power/suspend2_core/driver_model.c +25 -0
@@ -0,0 +1,95 @@
+/*
+ * kernel/power/suspend2_core/driver_model.c
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Support for the driver model and ACPI sleep states.
+ */
+
+#include <linux/pm.h>
+#include "driver_model.h"
+#include "power_off.h"
+
+extern struct pm_ops * pm_ops;
+static u32 pm_disk_mode_save;
+
+#ifdef CONFIG_ACPI
+static int suspend_pm_state_used = 0;
+extern u32 acpi_leave_sleep_state (u8 sleep_state);
+#endif
+
+/* suspend_drivers_init
+ *
+ * Store the original pm ops settings.

kernel/power/suspend2_core/driver_model.c line 35

Quoted 10 lines
kernel/power/suspend2_core/driver_model.c +10 -0
+ */
+int suspend_drivers_init(void)
+{
+	if (pm_ops) {
+		pm_disk_mode_save = pm_ops->pm_disk_mode;
+		pm_ops->pm_disk_mode = PM_DISK_PLATFORM;
+	}
+			
+	return 0;
+}

That seems like quite an ugly hack.

Quoted 24 lines
kernel/power/suspend2_core/driver_model.c +24 -0
+/* suspend_drivers_cleanup
+ *
+ * Restore the original pm disk mode.
+ */
+void suspend_drivers_cleanup(void)
+{
+	if (pm_ops)
+		pm_ops->pm_disk_mode = pm_disk_mode_save;
+}
+
+/* suspend_drivers_suspend
+ *
+ * Suspend the drivers after an atomic copy.
+ */
+int suspend_drivers_suspend(int stage)
+{
+	int result = 0;
+	const pm_message_t state = PMSG_FREEZE;
+
+	switch (stage) {
+		case SUSPEND_DRIVERS_IRQS_DISABLED:
+			BUG_ON(!irqs_disabled());
+			result = device_power_down(state);
+			BUG_ON(!irqs_disabled());

kernel/power/suspend2_core/driver_model.c line 70

Quoted 10 lines
kernel/power/suspend2_core/driver_model.c +10 -0
+			break;
+
+		case SUSPEND_DRIVERS_IRQS_ENABLED:
+			BUG_ON(irqs_disabled());
+			result = device_suspend(state);
+			BUG_ON(irqs_disabled());
+			break;
+	}
+	return result;
+}

Can't you just inline these?

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#103 lore raw

Re: [PATCH] [31/48] Suspend2 2.1.9.8 for 2.6.12: 608-compression.patch

Howdy.

Quoted 35 lines · Pavel Machek

Hi!

Quoted 33 lines

diff -ruNp 609-driver-model.patch-old/kernel/power/suspend2_core/driver_model.c 609-driver-model.patch-new/kernel/power/suspend2_core/driver_model.c

kernel/power/suspend2_core/driver_model.c +29 -0
@@ -0,0 +1,95 @@
+/*
+ * kernel/power/suspend2_core/driver_model.c
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Support for the driver model and ACPI sleep states.
+ */
+
+#include <linux/pm.h>
+#include "driver_model.h"
+#include "power_off.h"
+
+extern struct pm_ops * pm_ops;
+static u32 pm_disk_mode_save;
+
+#ifdef CONFIG_ACPI
+static int suspend_pm_state_used = 0;
+extern u32 acpi_leave_sleep_state (u8 sleep_state);
+#endif
+
+/* suspend_drivers_init
+ *
+ * Store the original pm ops settings.
+ */
+int suspend_drivers_init(void)
+{
+	if (pm_ops) {
Quoted 8 lines

kernel/power/suspend2_core/driver_model.c line 35

Quoted 6 lines
kernel/power/suspend2_core/driver_model.c +6 -0
+		pm_disk_mode_save = pm_ops->pm_disk_mode;
+		pm_ops->pm_disk_mode = PM_DISK_PLATFORM;
+	}
+			
+	return 0;
+}

That seems like quite an ugly hack.

Mmm. Adam and I have been discussing a more generic mechanism for powering down, switching between states and so on. Hopefully that will take care of these issues.

Quoted 28 lines
Quoted 28 lines
kernel/power/suspend2_core/driver_model.c +28 -0
+/* suspend_drivers_cleanup
+ *
+ * Restore the original pm disk mode.
+ */
+void suspend_drivers_cleanup(void)
+{
+	if (pm_ops)
+		pm_ops->pm_disk_mode = pm_disk_mode_save;
+}
+
+/* suspend_drivers_suspend
+ *
+ * Suspend the drivers after an atomic copy.
+ */
+int suspend_drivers_suspend(int stage)
+{
+	int result = 0;
+	const pm_message_t state = PMSG_FREEZE;
+
+	switch (stage) {
+		case SUSPEND_DRIVERS_IRQS_DISABLED:
+			BUG_ON(!irqs_disabled());
+			result = device_power_down(state);
+			BUG_ON(!irqs_disabled());
+			break;
+
+		case SUSPEND_DRIVERS_IRQS_ENABLED:
+			BUG_ON(irqs_disabled());
Quoted 8 lines

kernel/power/suspend2_core/driver_model.c line 70

Quoted 6 lines
kernel/power/suspend2_core/driver_model.c +6 -0
+			result = device_suspend(state);
+			BUG_ON(irqs_disabled());
+			break;
+	}
+	return result;
+}

Can't you just inline these?

Yes, I could. Just trying to keep driver model stuff separate.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#104 lore raw

PATCH 32/48 Suspend2 2.1.9.8 for 2.6.12: 609-driver-model.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/encryption.c +598 -0
diff -ruNp 610-encryption.patch-old/kernel/power/suspend2_core/encryption.c 610-encryption.patch-new/kernel/power/suspend2_core/encryption.c
@@ -0,0 +1,598 @@
+/*
+ * kernel/power/suspend2_core/encryption.c
+ *
+ * Copyright (C) 2003-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * This file contains data encryption routines for suspend,
+ * using cryptoapi transforms.
+ *
+ * ToDo:
+ * - Apply min/max_keysize the cipher changes.
+ * - Test.
+ */
+
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/highmem.h>
+#include <linux/vmalloc.h>
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
+
+#include "suspend.h"
+#include "plugins.h"
+#include "proc.h"
+#include "suspend2_common.h"
+#include "utility.h"
+#include "io.h"
+
+#define S2C_WRITE 0
+#define S2C_READ 1
+
+static struct suspend_plugin_ops s2_encryption_ops;
+static struct suspend_plugin_ops * next_driver;
+
+static char s2_encryptor_name[32];
+static struct crypto_tfm * s2_encryptor_transform;
+static char s2_encryptor_key[256];
+static int s2_key_len;
+static char s2_encryptor_iv[256];
+static int s2_encryptor_mode;
+static int s2_encryptor_save_key_and_iv;
+
+static u8 *page_buffer = NULL;
+static unsigned int bufofs;
+
+static struct scatterlist s2_crypt_sg[PAGE_SIZE/8];
+
+/* ---- Local buffer management ---- */
+
+/* allocate_local_buffer
+ *
+ * Description:	Allocates a page of memory for buffering output.
+ * Returns:	Int: Zero if successful, -ENONEM otherwise.
+ */
+
+static int allocate_local_buffer(void)
+{
+	if (!page_buffer) {
+		int i;
+		
+		page_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	
+		if (!page_buffer) {
+			printk(KERN_ERR
+				"Failed to allocate the page buffer for "
+				"suspend2 encryption driver.\n");
+			return -ENOMEM;
+		}
+
+		for (i=0; i < (PAGE_SIZE / s2_key_len); i++) {
+			s2_crypt_sg[i].page = virt_to_page(page_buffer);
+			s2_crypt_sg[i].offset = s2_key_len * i;
+			s2_crypt_sg[i].length = s2_key_len;
+		}
+	}
+
+	return 0;
+}
+
+/* free_local_buffer
+ *
+ * Description:	Frees memory allocated for buffering output.
+ */
+
+static inline void free_local_buffer(void)
+{
+	if (page_buffer)
+		free_pages((unsigned long) page_buffer, 0);
+
+	page_buffer = NULL;
+}
+
+/* suspend2_crypto_cleanup
+ *
+ * Description:	Frees memory allocated for our labours.
+ */
+
+static void suspend2_crypto_cleanup(void)
+{
+	if (s2_encryptor_transform) {
+		crypto_free_tfm(s2_encryptor_transform);
+		s2_encryptor_transform = NULL;
+	}
+}
+
+/* suspend2_crypto_prepare
+ *
+ * Description:	Prepare to do some work by allocating buffers and transforms.
+ * Returns:	Int: Zero if successful, -ENONEM otherwise.
+ */
+
+static int s2_encrypt_crypto_prepare(int mode)
+{
+	if (!*s2_encryptor_name) {
+		printk("Suspend2: Encryptor enabled but no name set.\n");
+		return 1;
+	}
+
+	if (!(s2_encryptor_transform = crypto_alloc_tfm(s2_encryptor_name,
+					1 << s2_encryptor_mode))) {
+		printk("Suspend2: Failed to initialise the encryption transform (%s, mode %d).\n",
+				s2_encryptor_name, s2_encryptor_mode);
+		return 1;
+	}
+
+	if (mode)
+		bufofs = PAGE_SIZE;
+	else
+		bufofs = 0;
+
+	s2_key_len = strlen(s2_encryptor_key);
+
+	if (crypto_cipher_setkey(s2_encryptor_transform, s2_encryptor_key, 
+				s2_key_len)) {
+		printk("%d is an invalid key length for cipher %s.\n",
+					s2_key_len,
+					s2_encryptor_name);
+		return 1;
+	}
+	
+	if (!mode) {
+		crypto_cipher_set_iv(s2_encryptor_transform,
+				s2_encryptor_iv,
+				crypto_tfm_alg_ivsize(s2_encryptor_transform));
+	}
+		
+	return 0;
+}
+
+/* ---- Exported functions ---- */
+
+/* write_init()
+ *
+ * Description:	Allocate buffers and prepare to encrypt data.
+ * Arguments:	Stream_number:	Ignored.
+ * Returns:	Zero on success, -ENOMEM if unable to vmalloc.
+ */
+
+static int s2_encrypt_write_init(int stream_number)
+{
+	int result;
+	
+	next_driver = get_next_filter(&s2_encryption_ops);
+
+	if (!next_driver) {
+		printk("Encryption Driver: Argh! No one wants my output!");
+		return -ECHILD;
+	}
+
+	if ((result = s2_encrypt_crypto_prepare(S2C_WRITE))) {
+		SET_RESULT_STATE(SUSPEND_ENCRYPTION_SETUP_FAILED);
+		suspend2_crypto_cleanup();
+		return result;
+	}
+	
+	if ((result = allocate_local_buffer()))
+		return result;
+
+	/* Only reset the stats if starting to write an image */
+	if (stream_number == 2)
+		bytes_in = bytes_out = 0;
+	
+	bufofs = 0;
+
+	return 0;
+}
+
+/* s2_encrypt_write_chunk()
+ *
+ * Description:	Encrypt a page of data, buffering output and passing on
+ * 		filled pages to the next plugin in the pipeline.
+ * Arguments:	Buffer_page:	Pointer to a buffer of size PAGE_SIZE, 
+ * 				containing data to be encrypted.
+ * Returns:	0 on success. Otherwise the error is that returned by later
+ * 		plugins, -ECHILD if we have a broken pipeline or -EIO if
+ * 		zlib errs.
+ */
+
+static int s2_encrypt_write_chunk(struct page * buffer_page)
+{
+	int ret; 
+	unsigned int len;
+	u16 len_written;
+	char * buffer_start;
+	
+	if (!s2_encryptor_transform)
+		return next_driver->ops.filter.write_chunk(buffer_page);
+
+	buffer_start = kmap(buffer_page);
+	memcpy(page_buffer, buffer_start, PAGE_SIZE);
+	kunmap(buffer_page);
+	
+	bytes_in += PAGE_SIZE;
+
+	len = PAGE_SIZE;
+
+	ret = crypto_cipher_encrypt(s2_encryptor_transform,
+			s2_crypt_sg, s2_crypt_sg, PAGE_SIZE);
+	
+	if (ret) {
+		printk("Encryption failed.\n");
+		return -EIO;
+	}
+	
+	len_written = (u16) len;
+
+	ret = next_driver->ops.filter.write_chunk(virt_to_page(page_buffer));
+
+	return ret;
+}
+
+/* write_cleanup()
+ *
+ * Description: Write unflushed data and free workspace.
+ * Returns:	Result of writing last page.
+ */
+
+static int s2_encrypt_write_cleanup(void)
+{
+	suspend2_crypto_cleanup();
+	free_local_buffer();
+
+	return 0;
+}
+
+/* read_init()
+ *
+ * Description:	Prepare to read a new stream of data.
+ * Arguments:	int: Section of image about to be read.
+ * Returns:	int: Zero on success, error number otherwise.
+ */
+
+static int s2_encrypt_read_init(int stream_number)
+{
+	int result;
+
+	next_driver = get_next_filter(&s2_encryption_ops);
+
+	if (!next_driver) {
+		printk("Encryption Driver: Argh! No one wants "
+				"to feed me data!");
+		return -ECHILD;
+	}
+	
+	if ((result = s2_encrypt_crypto_prepare(S2C_READ))) {
+		SET_RESULT_STATE(SUSPEND_ENCRYPTION_SETUP_FAILED);
+		suspend2_crypto_cleanup();
+		return result;
+	}
+	
+	if ((result = allocate_local_buffer()))
+		return result;
+
+	bufofs = PAGE_SIZE;
+
+	return 0;
+}
+
+/* s2_encrypt_read_chunk()
+ *
+ * Description:	Retrieve data from later plugins and deencrypt it until the
+ * 		input buffer is filled.
+ * Arguments:	Buffer_start: 	Pointer to a buffer of size PAGE_SIZE.
+ * 		Sync:		Whether the previous plugin (or core) wants its
+ * 				data synchronously.
+ * Returns:	Zero if successful. Error condition from me or from downstream
+ * 		on failure.
+ */
+
+static int s2_encrypt_read_chunk(struct page * buffer_page, int sync)
+{
+	int ret; 
+	char * buffer_start;
+
+	if (!s2_encryptor_transform)
+		return next_driver->ops.filter.read_chunk(buffer_page, sync);
+
+	/* 
+	 * All our reads must be synchronous - we can't deencrypt
+	 * data that hasn't been read yet.
+	 */
+
+	if ((ret = next_driver->ops.filter.read_chunk(
+			virt_to_page(page_buffer), SUSPEND_SYNC)) < 0) {
+		printk("Failed to read an encrypted block.\n");
+		return ret;
+	}
+
+	ret = crypto_cipher_decrypt(s2_encryptor_transform,
+			s2_crypt_sg, s2_crypt_sg, PAGE_SIZE);
+
+	if (ret)
+		printk("Decrypt function returned %d.\n", ret);
+
+	buffer_start = kmap(buffer_page);
+	memcpy(buffer_start, page_buffer, PAGE_SIZE);
+	kunmap(buffer_page);
+	return ret;
+}
+
+/* read_cleanup()
+ *
+ * Description:	Clean up after reading part or all of a stream of data.
+ * Returns:	int: Always zero. Never fails.
+ */
+
+static int s2_encrypt_read_cleanup(void)
+{
+	suspend2_crypto_cleanup();
+	free_local_buffer();
+	return 0;
+}
+
+/* s2_encrypt_print_debug_stats
+ *
+ * Description:	Print information to be recorded for debugging purposes into a
+ * 		buffer.
+ * Arguments:	buffer: Pointer to a buffer into which the debug info will be
+ * 			printed.
+ * 		size:	Size of the buffer.
+ * Returns:	Number of characters written to the buffer.
+ */
+
+static int s2_encrypt_print_debug_stats(char * buffer, int size)
+{
+	int len;
+	
+	len = suspend_snprintf(buffer, size, "- Encryptor %s enabled.\n",
+			s2_encryptor_name);
+	return len;
+}
+
+/* encryption_memory_needed
+ *
+ * Description:	Tell the caller how much memory we need to operate during
+ * 		suspend/resume.
+ * Returns:	Unsigned long. Maximum number of bytes of memory required for
+ * 		operation.
+ */
+
+static unsigned long s2_encrypt_memory_needed(void)
+{
+	return PAGE_SIZE;
+}
+
+static unsigned long s2_encrypt_storage_needed(void)
+{
+	return 2 * sizeof(unsigned long) + sizeof(int);
+}
+
+/* s2_encrypt_save_config_info
+ *
+ * Description:	Save informaton needed when reloading the image at resume time.
+ * Arguments:	Buffer:		Pointer to a buffer of size PAGE_SIZE.
+ * Returns:	Number of bytes used for saving our data.
+ */
+
+static int s2_encrypt_save_config_info(char * buffer)
+{
+	int buf_offset, str_size;
+
+	str_size = strlen(s2_encryptor_name);
+	*buffer = (char) str_size;
+	strncpy(buffer + 1, s2_encryptor_name, str_size + 1);
+	buf_offset = str_size + 2;
+
+	*(buffer + buf_offset) = (char) s2_encryptor_mode;
+	buf_offset++;
+
+	*(buffer + buf_offset) = (char) s2_encryptor_save_key_and_iv;
+	buf_offset++;
+
+	if (s2_encryptor_save_key_and_iv) {
+		
+		str_size = strlen(s2_encryptor_key);
+		*(buffer + buf_offset) = (char) str_size;
+		strncpy(buffer + buf_offset + 1, s2_encryptor_key, str_size + 1);
+
+		buf_offset+= str_size + 2;
+
+		str_size = strlen(s2_encryptor_iv);
+		*(buffer + buf_offset) = (char) str_size;
+		strncpy(buffer + buf_offset + 1, s2_encryptor_iv, str_size + 1);
+
+		buf_offset += str_size + 2;
+	}
+
+	return buf_offset;
+}
+
+/* s2_encrypt_load_config_info
+ *
+ * Description:	Reload information needed for deencrypting the image at 
+ * 		resume time.
+ * Arguments:	Buffer:		Pointer to the start of the data.
+ *		Size:		Number of bytes that were saved.
+ */
+
+static void s2_encrypt_load_config_info(char * buffer, int size)
+{
+	int buf_offset, str_size;
+
+	str_size = (int) *buffer;
+	strncpy(s2_encryptor_name, buffer + 1, str_size + 1);
+	buf_offset = str_size + 2;
+	
+	s2_encryptor_mode = (int) *(buffer + buf_offset);
+	buf_offset++;
+
+	s2_encryptor_save_key_and_iv = (int) *(buffer + buf_offset);
+	buf_offset++;
+
+	if (s2_encryptor_save_key_and_iv) {
+		str_size = (int) *(buffer + buf_offset);
+		strncpy(s2_encryptor_key, buffer + buf_offset + 1, str_size + 1);
+
+		buf_offset+= str_size + 2;
+
+		str_size = (int) *(buffer + buf_offset);
+		strncpy(s2_encryptor_iv, buffer + buf_offset + 1, str_size + 1);
+
+		buf_offset += str_size + 2;
+	} else {
+		*s2_encryptor_key = 0;
+		*s2_encryptor_iv = 0;
+	}
+	
+	if (buf_offset != size) {
+		printk("Suspend Encryptor config info size mismatch (%d != %d): settings ignored.\n",
+				buf_offset, size);
+		*s2_encryptor_key = 0;
+		*s2_encryptor_iv = 0;
+	}
+	return;
+}
+
+static void s2_encryptor_disable_if_empty(void)
+{
+	s2_encryption_ops.disabled = !(*s2_encryptor_name);
+}
+
+static int s2_encrypt_initialise(int starting_cycle)
+{
+	if (starting_cycle)
+		s2_encryptor_disable_if_empty();
+
+	return 0;
+}
+/*
+ * data for our proc entries.
+ */
+
+static struct suspend_proc_data proc_params[] = {
+	{
+		.filename			= "encryptor",
+		.permissions			= PROC_RW,
+		.type				= SUSPEND_PROC_DATA_STRING,
+		.data = {
+			.string = {
+				.variable	= s2_encryptor_name,
+				.max_length	= 31,
+			}
+		},
+		.write_proc			= s2_encryptor_disable_if_empty,
+	},
+
+	{
+		.filename			= "encryption_mode",
+		.permissions			= PROC_RW,
+		.type				= SUSPEND_PROC_DATA_INTEGER,
+		.data = {
+			.integer = {
+				.variable	= &s2_encryptor_mode,
+				.minimum	= 0,
+				.maximum	= 3,
+			}
+		}
+	},
+
+	{
+		.filename			= "encryption_save_key_and_iv",
+		.permissions			= PROC_RW,
+		.type				= SUSPEND_PROC_DATA_INTEGER,
+		.data = {
+			.integer = {
+				.variable	= &s2_encryptor_save_key_and_iv,
+				.minimum	= 0,
+				.maximum	= 1,
+			}
+		}
+	},
+
+	{
+		.filename			= "encryption_key",
+		.permissions			= PROC_RW,
+		.type				= SUSPEND_PROC_DATA_STRING,
+		.data = {
+			.string = {
+				.variable	= s2_encryptor_key,
+				.max_length	= 255,
+			}
+		}
+	},
+
+	{
+		.filename			= "encryption_iv",
+		.permissions			= PROC_RW,
+		.type				= SUSPEND_PROC_DATA_STRING,
+		.data = {
+			.string = {
+				.variable	= s2_encryptor_iv,
+				.max_length	= 255,
+			}
+		}
+	},
+
+	{
+		.filename			= "disable_encryption",
+		.permissions			= PROC_RW,
+		.type				= SUSPEND_PROC_DATA_INTEGER,
+		.data = {
+			.integer = {
+				.variable	= &s2_encryption_ops.disabled,
+				.minimum	= 0,
+				.maximum	= 1,
+			}
+		}
+	},
+	
+};
+
+/*
+ * Ops structure.
+ */
+
+static struct suspend_plugin_ops s2_encryption_ops = {
+	.type			= FILTER_PLUGIN,
+	.name			= "Encryptor",
+	.module			= THIS_MODULE,
+	.memory_needed 		= s2_encrypt_memory_needed,
+	.print_debug_info	= s2_encrypt_print_debug_stats,
+	.save_config_info	= s2_encrypt_save_config_info,
+	.load_config_info	= s2_encrypt_load_config_info,
+	.storage_needed		= s2_encrypt_storage_needed,
+	
+	.initialise		= s2_encrypt_initialise,
+	
+	.write_init		= s2_encrypt_write_init,
+	.write_cleanup		= s2_encrypt_write_cleanup,
+	.read_init		= s2_encrypt_read_init,
+	.read_cleanup		= s2_encrypt_read_cleanup,
+
+	.ops = {
+		.filter = {
+			.write_chunk		= s2_encrypt_write_chunk,
+			.read_chunk		= s2_encrypt_read_chunk,
+		}
+	}
+};
+
+/* ---- Registration ---- */
+
+static __init int s2_encrypt_load(void)
+{
+	int result;
+	int i, numfiles = sizeof(proc_params) / sizeof(struct suspend_proc_data);
+
+	printk("Software Suspend Encryption Driver loading.\n");
+	if (!(result = suspend_register_plugin(&s2_encryption_ops))) {
+		for (i=0; i< numfiles; i++)
+			suspend_register_procfile(&proc_params[i]);
+	} else
+		printk("Software Suspend Encryption Driver unable to register!\n");
+	return result;
+}
+
+late_initcall(s2_encrypt_load);
#105 lore raw

Re: [PATCH] [32/48] Suspend2 2.1.9.8 for 2.6.12: 609-driver-model.patch

kernel/power/suspend2_core/encryption.c 2005-07-05 23:54:31.000000000 +1000

Quoted 7 lines · Nigel Cunningham

diff -ruNp 610-encryption.patch-old/kernel/power/suspend2_core/encryption.c 610-encryption.patch-new/kernel/power/suspend2_core/encryption.c

kernel/power/suspend2_core/encryption.c 2005-07-05 23:54:31.000000000 +1000 renamed from kernel/power/suspend2_core/encryption.c 1970-01-01 10:00:00.000000000 +1000 +4 -0
+static inline void free_local_buffer(void)
+{
+       if (page_buffer)
+               free_pages((unsigned long) page_buffer, 0);

Use free_page(), please.

#106 lore raw

Re: [PATCH] [32/48] Suspend2 2.1.9.8 for 2.6.12: 609-driver-model.patch

Hi again.

Quoted 10 lines · Pekka Enberg

kernel/power/suspend2_core/encryption.c 2005-07-05 23:54:31.000000000 +1000

Quoted 7 lines · Nigel Cunningham

diff -ruNp 610-encryption.patch-old/kernel/power/suspend2_core/encryption.c 610-encryption.patch-new/kernel/power/suspend2_core/encryption.c

kernel/power/suspend2_core/encryption.c 2005-07-05 23:54:31.000000000 +1000 renamed from kernel/power/suspend2_core/encryption.c 1970-01-01 10:00:00.000000000 +1000 +4 -0
+static inline void free_local_buffer(void)
+{
+       if (page_buffer)
+               free_pages((unsigned long) page_buffer, 0);

Use free_page(), please.

Found more grepping the patches - take them as fixed too.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#107 lore raw

Re: [PATCH] [32/48] Suspend2 2.1.9.8 for 2.6.12: 609-driver-model.patch

In reply to Pekka Enberg

Hi.

Quoted 10 lines · Pekka Enberg

kernel/power/suspend2_core/encryption.c 2005-07-05 23:54:31.000000000 +1000

Quoted 7 lines · Nigel Cunningham

diff -ruNp 610-encryption.patch-old/kernel/power/suspend2_core/encryption.c 610-encryption.patch-new/kernel/power/suspend2_core/encryption.c

kernel/power/suspend2_core/encryption.c 2005-07-05 23:54:31.000000000 +1000 renamed from kernel/power/suspend2_core/encryption.c 1970-01-01 10:00:00.000000000 +1000 +4 -0
+static inline void free_local_buffer(void)
+{
+       if (page_buffer)
+               free_pages((unsigned long) page_buffer, 0);

Use free_page(), please.

Done. Thanks!

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#108 lore raw

PATCH 33/48 Suspend2 2.1.9.8 for 2.6.12: 610-encryption.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/extent.c +206 -0
diff -ruNp 610-extent.patch-old/kernel/power/suspend2_core/extent.c 610-extent.patch-new/kernel/power/suspend2_core/extent.c
@@ -0,0 +1,206 @@
+/*
+ * kernel/power/suspend2_core/extent.c
+ * 
+ * Suspend2 routines for manipulating extents.
+ *
+ * (C) 2003-2005 Nigel Cunningham <[email protected]>
+ *
+ * Distributed under GPLv2.
+ * 
+ * These functions encapsulate the manipulation of extents.
+ * They work like this:
+ *
+ * A lot of the data that suspend saves involves continguous extents of memory
+ * or storage. Let's say that we're storing data on disk in blocks 1-32768 and
+ * 49152-49848 of a swap partition. Rather than recording 1, 2, 3... in arrays
+ * pointing to the locations, we simply use:
+ *
+ * struct extent {
+ * 	unsigned long min;
+ * 	unsigned long max;
+ * 	struct extent * next;
+ * }
+ *
+ * We can then store 1-32768 and 49152-49848 in 2 struct extents, using 24 bytes
+ * instead of something like 133,860. This is of course inefficient where a extent
+ * covers only one or two values, but the benefits gained by the much larger
+ * extents more than outweigh these instances.
+ *
+ * When _all_ the metadata was stored in extents, we used to have fancier code that
+ * stored them in pages and was optimised for our usage. Nowadays they are only
+ * used for storage information. We therefore kmalloc them as required, and
+ * provide a far simpler routine to serialise them in the image header.
+ */
+
+#include <linux/module.h>
+#include <linux/suspend.h>
+#include "plugins.h"
+#include "extent.h"
+#include "ui.h"
+
+int extents_allocated = 0, max_extents_used = 0;
+
+/* get_extent
+ *
+ * Returns a free extent.
+ * May fail, returning NULL instead.
+ */
+
+static struct extent * get_extent(void)
+{
+	struct extent * result;
+	
+	if (!(result = kmalloc(sizeof(struct extent), GFP_ATOMIC)))
+		return NULL;
+
+	extents_allocated++;
+	if (extents_allocated > max_extents_used)
+		max_extents_used++;
+	result->minimum = result->maximum = 0;
+	result->next = NULL;
+	return result;
+}
+
+/*
+ * put_extent.
+ *
+ * Frees an extent.
+ *
+ * Assumes unlinking is done by the caller.
+ */
+void put_extent(struct extent * extent)
+{
+	if (!extent) {
+		printk("Error! put_extent called with NULL extent.\n");
+		return;
+	}
+	kfree(extent);
+	extents_allocated--;
+}
+
+/*
+ * put_extent_chain.
+ *
+ * Frees a whole chain of extents.
+ */
+void put_extent_chain(struct extentchain * chain)
+{
+	struct extent * this;
+
+	this = chain->first;
+
+	if (!this)
+		return;
+
+	while(this) {
+		struct extent * next = this->next;
+		kfree(this);
+		chain->frees++;
+		extents_allocated --;
+		this = next;
+	}
+	
+	BUG_ON(chain->frees != chain->allocs);
+	chain->first = chain->last = NULL;
+	chain->size = chain->allocs = chain->frees = 0;
+}
+
+/* 
+ * append_extent_to_extent_chain
+ *
+ * Used where we know a extent is to be added to the end of the list
+ * and does not need merging with the current last extent.
+ */
+
+int append_extent_to_extent_chain(struct extentchain * chain, 
+		unsigned long minimum, unsigned long maximum)
+{
+	struct extent * newextent = NULL;
+
+	newextent = get_extent();
+	if (!newextent) {
+		printk("Error unable to append a new extent to the chain.\n");
+		return 2;
+	}
+
+	chain->allocs++;
+	chain->size+= (maximum - minimum + 1);
+	newextent->minimum = minimum;
+	newextent->maximum = maximum;
+	newextent->next = NULL;
+
+	if (chain->last) {
+		chain->last->next = newextent;
+		chain->last = newextent;
+	} else 
+		chain->last = chain->first = newextent;
+
+	/* No need to reset optimisation info since added to end */
+	return 0;
+}
+
+/* 
+ * serialise_extent_chain
+ *
+ * Write a chain in the image.
+ */
+int serialise_extent_chain(struct extentchain * chain)
+{
+	struct extent * this;
+	int ret, i = 1;
+	
+	if ((ret = active_writer->ops.writer.write_header_chunk((char *) chain,
+		sizeof(struct extentchain) - 2 * sizeof(struct extent *)))) {
+		printk("Write header chunk returned %d - aborting serialising chain.\n",
+				ret);
+		return ret;
+	}
+
+	this = chain->first;
+	while (this) {
+		if ((ret = active_writer->ops.writer.write_header_chunk((char *) this,
+				2 * sizeof(unsigned long)))) {
+			printk("Failed to write extent.\n");
+			return ret;
+		}
+		this = this->next;
+		i++;
+	}
+	return ret;
+}
+
+/* 
+ * load_extent_chain
+ *
+ * Read back a chain saved in the image.
+ */
+int load_extent_chain(struct extentchain * chain)
+{
+	struct extent * this, * last = NULL;
+	int i, ret;
+
+	if (!(ret = active_writer->ops.writer.read_header_chunk((char *) chain,
+		sizeof(struct extentchain) - 2 * sizeof(struct extent *)))) {
+		printk("Read header chunk returned %d - aborting serialising chain.\n",
+				ret);
+		return ret;
+	}
+
+	for (i = 0; i < (chain->allocs - chain->frees); i++) {
+		this = kmalloc(sizeof(struct extent), GFP_ATOMIC);
+		BUG_ON(!this); /* Shouldn't run out of memory trying this! */
+		this->next = NULL;
+		if (!(ret = active_writer->ops.writer.read_header_chunk((char *) this,
+				2 * sizeof(unsigned long)))) {
+			printk("Failed to read extent.\n");
+			return ret;
+		}
+		if (last)
+			last->next = this;
+		else
+			chain->first = this;
+		last = this;
+	}
+	chain->last = last;
+	return ret;
+}
kernel/power/suspend2_core/extent.h +84 -0

84 lines not on this page · raw message

#109 lore raw

Re: [PATCH] [33/48] Suspend2 2.1.9.8 for 2.6.12: 610-encryption.patch

Hi!

kernel/power/suspend2_core/extent.c line 86

Quoted 6 lines
kernel/power/suspend2_core/extent.c +6 -0
+/*
+ * put_extent_chain.
+ *
+ * Frees a whole chain of extents.
+ */
+void put_extent_chain(struct extentchain * chain)

This probably should be extent_chain.

kernel/power/suspend2_core/extent.h line 21

Quoted 8 lines
kernel/power/suspend2_core/extent.h +8 -0
+#ifndef EXTENT_H
+#define EXTENT_H
+struct extentchain {
+	int size; /* size of the extent ie sum (max-min+1) */
+	int allocs;
+	int frees;
+	int debug;
+	int timesusedoptimisation;

time_suse_d_optimisation? ;-).

Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#110 lore raw

Re: [PATCH] [33/48] Suspend2 2.1.9.8 for 2.6.12: 610-encryption.patch

'ello!

Quoted 11 lines · Pavel Machek

Hi!

kernel/power/suspend2_core/extent.c line 86

Quoted 6 lines
kernel/power/suspend2_core/extent.c +6 -0
+/*
+ * put_extent_chain.
+ *
+ * Frees a whole chain of extents.
+ */
+void put_extent_chain(struct extentchain * chain)

This probably should be extent_chain.

Quoted 10 lines

kernel/power/suspend2_core/extent.h line 21

Quoted 8 lines
kernel/power/suspend2_core/extent.h +8 -0
+#ifndef EXTENT_H
+#define EXTENT_H
+struct extentchain {
+	int size; /* size of the extent ie sum (max-min+1) */
+	int allocs;
+	int frees;
+	int debug;
+	int timesusedoptimisation;

time_suse_d_optimisation? ;-).

Fixed up!

Thanks, once again!

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#111 lore raw

PATCH 34/48 Suspend2 2.1.9.8 for 2.6.12: 610-extent.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/io.c +1006 -0
diff -ruNp 611-io.patch-old/kernel/power/suspend2_core/io.c 611-io.patch-new/kernel/power/suspend2_core/io.c
@@ -0,0 +1,1006 @@
+/*
+ * kernel/power/io.c
+ *
+ * Copyright (C) 1998-2001 Gabor Kuti <[email protected]>
+ * Copyright (C) 1998,2001,2002 Pavel Machek <[email protected]>
+ * Copyright (C) 2002-2003 Florent Chabaud <[email protected]>
+ * Copyright (C) 2002-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * It contains high level IO routines for suspending.
+ *
+ */
+
+#include <linux/suspend.h>
+#include <linux/version.h>
+#include <linux/utsname.h>
+
+#include "version.h"
+#include "plugins.h"
+#include "pageflags.h"
+#include "io.h"
+#include "ui.h"
+#include "suspend2_common.h"
+#include "suspend.h"
+
+/* attempt_to_parse_resume_device
+ *
+ * Can we suspend, using the current resume2= parameter?
+ */
+void attempt_to_parse_resume_device(void)
+{
+	struct list_head *writer;
+	struct suspend_plugin_ops * this_writer;
+	int result = 0;
+
+	active_writer = NULL;
+	clear_suspend_state(SUSPEND_RESUME_DEVICE_OK);
+	set_suspend_state(SUSPEND_DISABLED);
+	CLEAR_RESULT_STATE(SUSPEND_ABORTED);
+
+	if (!num_writers) {
+		printk(name_suspend "No writers have been registered. Suspending will be disabled.\n");
+		return;
+	}
+	
+	if (!resume2_file[0]) {
+		printk(name_suspend "Resume2 parameter is empty. Suspending will be disabled.\n");
+		return;
+	}
+
+	list_for_each(writer, &suspend_writers) {
+		this_writer = list_entry(writer, struct suspend_plugin_ops,
+				ops.writer.writer_list);
+
+		/* 
+		 * Not sure why you'd want to disable a writer, but
+		 * we should honour the flag if we're providing it
+		 */
+		if (this_writer->disabled) {
+			printk(name_suspend
+					"Writer '%s' is disabled. Ignoring it.\n",
+					this_writer->name);
+			continue;
+		}
+
+		result = this_writer->ops.writer.parse_image_location(
+				resume2_file, (num_writers == 1));
+
+		switch (result) {
+			case -EINVAL:
+				/* 
+				 * For this writer, but not a valid 
+				 * configuration. Error already printed.
+				 */
+
+				return;
+
+			case 0:
+				/*
+				 * For this writer and valid.
+				 */
+
+				active_writer = this_writer;
+
+				set_suspend_state(SUSPEND_RESUME_DEVICE_OK);
+				clear_suspend_state(SUSPEND_DISABLED);
+				printk(name_suspend "Suspending enabled.\n");
+
+				return;
+		}
+	}
+	printk(name_suspend "No matching enabled writer found. Suspending disabled.\n");
+}
+
+/* suspend2_cleanup_finished_io
+ *
+ * Description:	Very simple helper function to save #including all the
+ * 		suspend code in fs/buffer.c and anywhere else we might
+ * 		want to wait on suspend I/O in future.
+ */
+
+void suspend2_cleanup_finished_io(void)
+{
+	active_writer->ops.writer.wait_on_io(0);
+}
+
+/* noresume_reset_plugins
+ *
+ * Description:	When we read the start of an image, plugins (and especially the
+ * 		active writer) might need to reset data structures if we decide
+ * 		to invalidate the image rather than resuming from it.
+ */
+
+static void noresume_reset_plugins(void)
+{
+	struct suspend_plugin_ops * this_filter;
+	
+	list_for_each_entry(this_filter, &suspend_filters, ops.filter.filter_list) {
+		if (this_filter->ops.filter.noresume_reset)
+			this_filter->ops.filter.noresume_reset();
+	}
+
+	if (active_writer && active_writer->ops.writer.noresume_reset)
+		active_writer->ops.writer.noresume_reset();
+}
+
+/* fill_suspend_header()
+ * 
+ * Description:	Fill the suspend header structure.
+ * Arguments:	struct suspend_header: Header data structure to be filled.
+ */
+
+static void fill_suspend_header(struct suspend_header *sh)
+{
+	int i;
+	
+	memset((char *)sh, 0, sizeof(*sh));
+
+	sh->version_code = LINUX_VERSION_CODE;
+	sh->num_physpages = num_physpages;
+	sh->orig_mem_free = suspend2_orig_mem_free;
+	strncpy(sh->machine, system_utsname.machine, 65);
+	strncpy(sh->version, system_utsname.version, 65);
+	sh->num_cpus = num_online_cpus();
+	sh->page_size = PAGE_SIZE;
+	sh->pagedir = pagedir1;
+	sh->pageset_2_size = pagedir2.pageset_size;
+	sh->param0 = suspend_result;
+	sh->param1 = suspend_action;
+	sh->param2 = suspend_debug_state;
+	sh->param3 = console_loglevel;
+	for (i = 0; i < 4; i++)
+		sh->io_time[i/2][i%2] =
+		       suspend_io_time[i/2][i%2];
+}
+
+/* write_pageset()
+ *
+ * Description:	Write a pageset to disk.
+ * Arguments:	pagedir:	Pointer to the pagedir to be saved.
+ * 		whichtowrite:	Controls what debugging output is printed.
+ * Returns:	Zero on success or -1 on failure.
+ */
+
+int write_pageset(struct pagedir * pagedir, int whichtowrite)
+{
+	int nextupdate = 0, size, ret = 0, i, base = 0;
+	int barmax = pagedir1.pageset_size + pagedir2.pageset_size;
+	int start_time, end_time, pc, step = 1;
+	long error = 0;
+	struct suspend_plugin_ops * this_plugin, * first_filter = get_next_filter(NULL);
+	dyn_pageflags_t *pageflags;
+	int current_page_index = -1;
+
+	size = pagedir->pageset_size;
+	if (!size)
+		return 0;
+
+	if (whichtowrite == 1) {
+		suspend2_prepare_status(1, 0, "Writing kernel & process data...");
+		base = pagedir2.pageset_size;
+		if (TEST_ACTION_STATE(SUSPEND_TEST_FILTER_SPEED))
+			pageflags = &pageset1_map;
+		else
+			pageflags = &pageset1_copy_map;
+	} else {
+		suspend2_prepare_status(1, 1, "Writing caches...");
+		pageflags = &pageset2_map;
+		bytes_in = bytes_out = 0;
+	}	
+	
+	start_time = jiffies;
+
+	/* Initialise page transformers */
+	list_for_each_entry(this_plugin, &suspend_filters, ops.filter.filter_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->write_init)
+			if (this_plugin->write_init(whichtowrite)) {
+				SET_RESULT_STATE(SUSPEND_ABORTED);
+				goto write_pageset_free_buffers;
+			}
+	}
+
+	/* Initialise writer */
+	active_writer->write_init(whichtowrite);
+
+	/* Initialise other plugins */
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (this_plugin->disabled)
+			continue;
+		if ((this_plugin->type == FILTER_PLUGIN) ||
+		    (this_plugin->type == WRITER_PLUGIN))
+			continue;
+		if (this_plugin->write_init)
+			if (this_plugin->write_init(whichtowrite)) {
+				SET_RESULT_STATE(SUSPEND_ABORTED);
+				goto write_pageset_free_buffers;
+			}
+	}
+
+	current_page_index = __get_next_bit_on(*pageflags, -1);
+
+	pc = size / 5;
+
+	/* Write the data */
+	for (i=0; i<size; i++) {
+		int was_mapped = 0;
+		struct page * page = pfn_to_page(current_page_index);
+
+		/* Status update */
+		if ((i+base) >= nextupdate)
+			nextupdate = suspend2_update_status(i + base, barmax, 
+				" %d/%d MB ", MB(base+i+1), MB(barmax));
+
+		if ((i + 1) == pc) {
+			printk("%d%%...", 20 * step);
+			step++;
+			pc = size * step / 5;
+		}
+
+		/* Write */
+		was_mapped = suspend_map_kernel_page(page, 1);
+		ret = first_filter->ops.filter.write_chunk(page);
+		if (!was_mapped)
+			suspend_map_kernel_page(page, 0);
+
+		if (ret) {
+			printk("Write chunk returned %d.\n", ret);
+			abort_suspend("Failed to write a chunk of the "
+					"image.");
+			error = -1;
+			goto write_pageset_free_buffers;
+		}
+
+		/* Interactivity */
+		check_shift_keys(0, NULL);
+
+		if (TEST_RESULT_STATE(SUSPEND_ABORTED)) {
+			abort_suspend("Aborting as requested.");
+			error = -1;
+			goto write_pageset_free_buffers;
+		}
+
+		/* Prepare next */
+		current_page_index = __get_next_bit_on(*pageflags, current_page_index);
+	}
+
+	printk("done.\n");
+
+	suspend2_update_status(base+size, barmax, " %d/%d MB ",
+			MB(base+size), MB(barmax));
+
+write_pageset_free_buffers:
+	
+	/* Cleanup other plugins */
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (this_plugin->disabled)
+			continue;
+		if ((this_plugin->type == FILTER_PLUGIN) ||
+		    (this_plugin->type == WRITER_PLUGIN))
+			continue;
+		if (this_plugin->write_cleanup)
+			this_plugin->write_cleanup();
+	}
+
+	/* Flush data and cleanup */
+	list_for_each_entry(this_plugin, &suspend_filters, ops.filter.filter_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->write_cleanup)
+			this_plugin->write_cleanup();
+	}
+	active_writer->write_cleanup();
+
+	/* Statistics */
+	end_time = jiffies;
+	
+	if ((end_time - start_time) && (!TEST_RESULT_STATE(SUSPEND_ABORTED))) {
+		suspend_io_time[0][0] += size,
+		suspend_io_time[0][1] += (end_time - start_time);
+	}
+
+	return error;
+}
+
+/* read_pageset()
+ *
+ * Description:	Read a pageset from disk.
+ * Arguments:	pagedir:	Pointer to the pagedir to be saved.
+ * 		whichtowrite:	Controls what debugging output is printed.
+ * 		overwrittenpagesonly: Whether to read the whole pageset or
+ * 		only part.
+ * Returns:	Zero on success or -1 on failure.
+ */
+
+static int read_pageset(struct pagedir * pagedir, int whichtoread,
+		int overwrittenpagesonly)
+{
+	int nextupdate = 0, result = 0, base = 0;
+	int start_time, end_time, finish_at = pagedir->pageset_size;
+	int barmax = pagedir1.pageset_size + pagedir2.pageset_size;
+	int i, pc, step = 1;
+	struct suspend_plugin_ops * this_plugin, * first_filter = get_next_filter(NULL);
+	dyn_pageflags_t *pageflags;
+	int current_page_index;
+
+	if (whichtoread == 1) {
+		suspend2_prepare_status(1, 1, "Reading kernel & process data...");
+		pageflags = &pageset1_copy_map;
+	} else {
+		suspend2_prepare_status(1, 0, "Reading caches...");
+		if (overwrittenpagesonly)
+			barmax = finish_at = min(pageset1_size, pageset2_size);
+		else {
+			base = pagedir1.pageset_size;
+		}
+		pageflags = &pageset2_map;
+	}	
+	
+	start_time=jiffies;
+
+	/* Initialise page transformers */
+	list_for_each_entry(this_plugin, &suspend_filters, ops.filter.filter_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->read_init && 
+				this_plugin->read_init(whichtoread)) {
+			abort_suspend("Failed to initialise a filter.");
+			result = 1;
+			goto read_pageset_free_buffers;
+		}
+	}
+
+	/* Initialise writer */
+	if (active_writer->read_init(whichtoread)) {
+		abort_suspend("Failed to initialise the writer."); 
+		result = 1;
+		goto read_pageset_free_buffers;
+	}
+
+	/* Initialise other plugins */
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (this_plugin->disabled)
+			continue;
+		if ((this_plugin->type == FILTER_PLUGIN) ||
+		    (this_plugin->type == WRITER_PLUGIN))
+			continue;
+		if (this_plugin->read_init)
+			if (this_plugin->read_init(whichtoread)) {
+				SET_RESULT_STATE(SUSPEND_ABORTED);
+				goto read_pageset_free_buffers;
+			}
+	}
+
+	current_page_index = __get_next_bit_on(*pageflags, -1);
+
+	pc = finish_at / 5;
+
+	/* Read the pages */
+	for (i=0; i< finish_at; i++) {
+		int was_mapped = 0;
+		struct page * page = pfn_to_page(current_page_index);
+
+		/* Status */
+		if ((i+base) >= nextupdate)
+			nextupdate = suspend2_update_status(i+base, barmax,
+				" %d/%d MB ", MB(base+i+1), MB(barmax));
+
+		if ((i + 1) == pc) {
+			printk("%d%%...", 20 * step);
+			step++;
+			pc = finish_at * step / 5;
+		}
+		
+		was_mapped = suspend_map_kernel_page(page, 1);
+		result = first_filter->ops.filter.read_chunk(page, SUSPEND_ASYNC);
+		if (!was_mapped)
+			suspend_map_kernel_page(page, 0);
+
+		if (result) {
+			panic("Failed to read chunk %d/%d of the image. (%d)",
+					i, finish_at, result);
+			goto read_pageset_free_buffers;
+		}
+
+		/* Interactivity*/
+		check_shift_keys(0, NULL);
+
+		/* Prepare next */
+		current_page_index = __get_next_bit_on(*pageflags, current_page_index);
+	}
+
+	printk("done.\n");
+
+	suspend2_update_status(base+finish_at, barmax, " %d/%d MB ",
+			MB(base+finish_at), MB(barmax));
+
+read_pageset_free_buffers:
+
+	/* Cleanup other plugins */
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (this_plugin->disabled)
+			continue;
+		if ((this_plugin->type == FILTER_PLUGIN) ||
+		    (this_plugin->type == WRITER_PLUGIN))
+			continue;
+		if (this_plugin->read_cleanup)
+			this_plugin->read_cleanup();
+	}
+
+	/* Finish I/O, flush data and cleanup reads. */
+	list_for_each_entry(this_plugin, &suspend_filters, ops.filter.filter_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->read_cleanup &&
+				this_plugin->read_cleanup()) {
+			abort_suspend("Failed to cleanup a filter.");
+			result = 1;
+		}
+	}
+
+	if (active_writer->read_cleanup()) {
+		abort_suspend("Failed to cleanup the writer.");
+		result = 1;
+	}
+
+	/* Statistics */
+	end_time=jiffies;
+	if ((end_time - start_time) && (!TEST_RESULT_STATE(SUSPEND_ABORTED))) {
+		suspend_io_time[1][0] += finish_at,
+		suspend_io_time[1][1] += (end_time - start_time);
+	}
+
+	return result;
+}
+
+/* write_plugin_configs()
+ *
+ * Description:	Store the configuration for each plugin in the image header.
+ * Returns:	Int: Zero on success, Error value otherwise.
+ */
+static int write_plugin_configs(void)
+{
+	struct suspend_plugin_ops * this_plugin;
+	char * buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	int len, index = 1;
+	struct plugin_header plugin_header;
+
+	if (!buffer) {
+		printk("Failed to allocate a buffer for saving "
+				"plugin configuration info.\n");
+		return -ENOMEM;
+	}
+		
+	/* 
+	 * We have to know which data goes with which plugin, so we at
+	 * least write a length of zero for a plugin. Note that we are
+	 * also assuming every plugin's config data takes <= PAGE_SIZE.
+	 */
+
+	/* For each plugin (in registration order) */
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+
+		/* Get the data from the plugin */
+		len = 0;
+		if (this_plugin->save_config_info)
+			len = this_plugin->save_config_info(buffer);
+
+		/* Save the details of the plugin */
+		plugin_header.disabled = this_plugin->disabled;
+		plugin_header.type = this_plugin->type;
+		plugin_header.index = index++;
+		strncpy(plugin_header.name, this_plugin->name, 
+					sizeof(plugin_header.name));
+		active_writer->ops.writer.write_header_chunk(
+				(char *) &plugin_header,
+				sizeof(plugin_header));
+
+		/* Save the size of the data and any data returned */
+		active_writer->ops.writer.write_header_chunk((char *) &len,
+				sizeof(int));
+		if (len)
+			active_writer->ops.writer.write_header_chunk(
+					buffer, len);
+	}
+
+	/* Write a blank header to terminate the list */
+	plugin_header.name[0] = '\0';
+	active_writer->ops.writer.write_header_chunk(
+			(char *) &plugin_header,
+			sizeof(plugin_header));
+
+	free_pages((unsigned long) buffer, 0);
+	return 0;
+}
+
+/* read_plugin_configs()
+ *
+ * Description:	Reload plugin configurations from the image header.
+ * Returns:	Int. Zero on success, error value otherwise.
+ */
+
+static int read_plugin_configs(void)
+{
+	struct suspend_plugin_ops * this_plugin;
+	char * buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	int len, result = 0;
+	struct plugin_header plugin_header;
+
+	if (!buffer) {
+		printk("Failed to allocate a buffer for reloading plugin "
+				"configuration info.\n");
+		return -ENOMEM;
+	}
+		
+	/* All plugins are initially disabled. That way, if we have a plugin
+	 * loaded now that wasn't loaded when we suspended, it won't be used
+	 * in trying to read the data.
+	 */
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list)
+		this_plugin->disabled = 1;
+	
+	/* Get the first plugin header */
+	result = active_writer->ops.writer.read_header_chunk(
+			(char *) &plugin_header, sizeof(plugin_header));
+	if (!result) {
+		printk("Failed to read the next plugin header.\n");
+		free_pages((unsigned long) buffer, 0);
+		return -EINVAL;
+	}
+
+	/* For each plugin (in registration order) */
+	while (plugin_header.name[0]) {
+		
+		/* Find the plugin */
+		this_plugin = find_plugin_given_name(plugin_header.name);
+		
+		if (!this_plugin) {
+			/* 
+			 * Is it used? Only need to worry about filters. The active
+			 * writer must be loaded!
+			 */
+			if ((!plugin_header.disabled) &&
+			    (plugin_header.type == FILTER_PLUGIN)) {
+				suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+					"It looks like we need plugin %s for "
+					"reading the image but it hasn't been "
+					"registered.\n",
+					plugin_header.name);
+				if (!(test_suspend_state(SUSPEND_CONTINUE_REQ))) {
+					active_writer->ops.writer.invalidate_image();
+					result = -EINVAL;
+					noresume_reset_plugins();
+					free_pages((unsigned long) buffer, 0);
+					return -EINVAL;
+				}
+			} else
+				printk("Plugin %s configuration data found, but the plugin "
+					"hasn't registered. Looks like it was disabled, so "
+					"we're ignoring it's data.",
+					plugin_header.name);
+		}
+		
+		/* Get the length of the data (if any) */
+		result = active_writer->ops.writer.read_header_chunk(
+				(char *) &len, sizeof(int));
+		if (!result) {
+			printk("Failed to read the length of the plugin %s's"
+					" configuration data.\n",
+					plugin_header.name);
+			free_pages((unsigned long) buffer, 0);
+			return -EINVAL;
+		}
+
+		/* Read any data and pass to the plugin (if we found one) */
+		if (len) {
+			active_writer->ops.writer.read_header_chunk(buffer, len);
+			if (this_plugin) {
+				if (!this_plugin->save_config_info) {
+					printk("Huh? Plugin %s appears to have a "
+						"save_config_info, but not a "
+						"load_config_info function!\n",
+						this_plugin->name);
+				} else
+					this_plugin->load_config_info(buffer, len);
+			}
+		}
+
+		if (this_plugin) {
+			/* Now move this plugin to the tail of its lists. This will put it
+			 * in order. Any new plugins will end up at the top of the lists.
+			 * They should have been set to disabled when loaded (people will
+			 * normally not edit an initrd to load a new module and then
+			 * suspend without using it!).
+			 */
+
+			suspend_move_plugin_tail(this_plugin);
+
+			/* 
+			 * We apply the disabled state; plugins don't need to save whether they
+			 * were disabled and if they do, we override them anyway.
+			 */
+			this_plugin->disabled = plugin_header.disabled;
+		}
+
+		/* Get the next plugin header */
+		result = active_writer->ops.writer.read_header_chunk(
+				(char *) &plugin_header, sizeof(plugin_header));
+
+		if (!result) {
+			printk("Failed to read the next plugin header.\n");
+			free_pages((unsigned long) buffer, 0);
+			return -EINVAL;
+		}
+
+	}
+
+	free_pages((unsigned long) buffer, 0);
+	return 0;
+}
+
+/* write_image_header()
+ *
+ * Description:	Write the image header after write the image proper.
+ * Returns:	Int. Zero on success or -1 on failure.
+ */
+
+int write_image_header(void)
+{
+	int ret;
+	int total = pagedir1.pageset_size + pagedir2.pageset_size+2;
+	char * header_buffer = NULL;
+
+	/* Now prepare to write the header */
+	if ((ret = active_writer->ops.writer.write_header_init())) {
+		abort_suspend("Active writer's write_header_init"
+				" function failed.");
+		goto write_image_header_abort;
+	}
+
+	/* Get a buffer */
+	header_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	if (!header_buffer) {
+		abort_suspend("Out of memory when trying to get page "
+				"for header!");
+		goto write_image_header_abort;
+	}
+
+	/* Write suspend header */
+	fill_suspend_header((struct suspend_header *) header_buffer);
+	active_writer->ops.writer.write_header_chunk(header_buffer,
+			sizeof(struct suspend_header));
+
+	free_pages((unsigned long) header_buffer, 0);
+
+	/* Write plugin configurations */
+	if ((ret = write_plugin_configs())) {
+		abort_suspend("Failed to write plugin configs.");
+		goto write_image_header_abort;
+	}
+
+	save_dyn_pageflags(pageset1_map);
+
+	if ((ret = active_writer->ops.writer.serialise_extents())) {
+		abort_suspend("Active writer's prepare_save_extents "
+				"function failed.");
+		goto write_image_header_abort;
+	}
+
+	/* Flush data and let writer cleanup */
+	if (active_writer->ops.writer.write_header_cleanup()) {
+		abort_suspend("Failed to cleanup writing header.");
+		goto write_image_header_abort_no_cleanup;
+	}
+
+	if (TEST_RESULT_STATE(SUSPEND_ABORTED))
+		goto write_image_header_abort_no_cleanup;
+
+	suspend_message(SUSPEND_IO, SUSPEND_VERBOSE, 1, "|\n");
+	suspend2_update_status(total, total, NULL);
+
+	return 0;
+
+write_image_header_abort:
+	active_writer->ops.writer.write_header_cleanup();
+write_image_header_abort_no_cleanup:
+	return -1;
+}
+
+/* sanity_check()
+ *
+ * Description:	Perform a few checks, seeking to ensure that the kernel being
+ * 		booted matches the one suspended. They need to match so we can
+ * 		be _sure_ things will work. It is not absolutely impossible for
+ * 		resuming from a different kernel to work, just not assured.
+ * Arguments:	Struct suspend_header. The header which was saved at suspend
+ * 		time.
+ */
+static int sanity_check(struct suspend_header *sh)
+{
+	if (sh->version_code != LINUX_VERSION_CODE)
+		return suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+				"Incorrect kernel version");
+	
+	if (sh->num_physpages != num_physpages)
+		return suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+				"Incorrect memory size");
+
+	if (strncmp(sh->machine, system_utsname.machine, 65))
+		return suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+				"Incorrect machine type");
+
+	if (strncmp(sh->version, system_utsname.version, 65))
+		return suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+			      "Incorrect version");
+
+	if (sh->num_cpus != num_online_cpus())
+		return suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,  
+				"Incorrect number of cpus");
+
+	if (sh->page_size != PAGE_SIZE)
+		return suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+				"Incorrect PAGE_SIZE");
+
+	return 0;
+}
+
+/* __read_pageset1
+ *
+ * Description:	Test for the existence of an image and attempt to load it.
+ * Returns:	Int. Zero if image found and pageset1 successfully loaded.
+ * 		Error if no image found or loaded.
+ */
+static int __read_pageset1(void)
+{			
+	int i, result = 0;
+	char * header_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	struct suspend_header * suspend_header;
+
+	if (!header_buffer)
+		return -ENOMEM;
+	
+	/* Check for an image */
+	if (!(result = active_writer->ops.writer.image_exists())) {
+		result = -ENODATA;
+		noresume_reset_plugins();
+		goto out;
+	}
+
+	/* Check for noresume command line option */
+	if (test_suspend_state(SUSPEND_NORESUME_SPECIFIED)) {
+		active_writer->ops.writer.invalidate_image();
+		result = -EINVAL;
+		noresume_reset_plugins();
+		goto out;
+	}
+
+#ifdef CONFIG_SOFTWARE_SUSPEND_CHECK_RESUME_SAFE
+	/* Check whether we've got filesystems mounted that make
+	 * resuming unsafe */
+
+	suspend_check_mounts();
+
+	if (!test_suspend_state(SUSPEND_CONTINUE_REQ)) {
+		active_writer->ops.writer.invalidate_image();
+		result = -EINVAL;
+		noresume_reset_plugins();
+		goto out;
+	}
+
+	clear_suspend_state(SUSPEND_CONTINUE_REQ);
+#endif
+
+	/* Check whether we've resumed before */
+	if (test_suspend_state(SUSPEND_RESUMED_BEFORE)) {
+		int resumed_before_default = 0;
+		if (test_suspend_state(SUSPEND_RETRY_RESUME))
+			resumed_before_default = SUSPEND_CONTINUE_REQ;
+		suspend_early_boot_message(1, resumed_before_default, NULL);
+		clear_suspend_state(SUSPEND_RETRY_RESUME);
+		if (!(test_suspend_state(SUSPEND_CONTINUE_REQ))) {
+			active_writer->ops.writer.invalidate_image();
+			result = -EINVAL;
+			noresume_reset_plugins();
+			goto out;
+		}
+	}
+
+	clear_suspend_state(SUSPEND_CONTINUE_REQ);
+
+	/* 
+	 * Prepare the active writer for reading the image header. The
+	 * activate writer might read its own configuration or set up
+	 * a network connection here.
+	 * 
+	 * NB: This call may never return because there might be a signature
+	 * for a different image such that we warn the user and they choose
+	 * to reboot. (If the device ids look erroneous (2.4 vs 2.6) or the
+	 * location of the image might be unavailable if it was stored on a
+	 * network connection.
+	 */
+
+	if ((result = active_writer->ops.writer.read_header_init())) {
+		noresume_reset_plugins();
+		goto out;
+	}
+	
+	/* Read suspend header */
+	if ((result = active_writer->ops.writer.read_header_chunk(
+			header_buffer, sizeof(struct suspend_header))) < 0) {
+		noresume_reset_plugins();
+		goto out;
+	}
+	
+	suspend_header = (struct suspend_header *) header_buffer;
+
+	/*
+	 * NB: This call may also result in a reboot rather than returning.
+	 */
+
+	if (sanity_check(suspend_header)) { /* Is this the same machine? */
+		active_writer->ops.writer.invalidate_image();
+		result = -EINVAL;
+		noresume_reset_plugins();
+		goto out;
+	}
+
+	/*
+	 * ---------------------------------------------------- 
+	 * We have an image and it looks like it will load okay.
+	 * ---------------------------------------------------- 
+	 */
+
+	/* Get metadata from header. Don't override commandline parameters.
+	 *
+	 * We don't need to save the image size limit because it's not used
+	 * during resume and will be restored with the image anyway.
+	 */
+	
+	suspend2_orig_mem_free = suspend_header->orig_mem_free;
+	memcpy((char *) &pagedir1,
+		(char *) &suspend_header->pagedir, sizeof(pagedir1));
+	suspend_result = suspend_header->param0;
+	if (!test_suspend_state(SUSPEND_ACT_USED))
+		suspend_action = suspend_header->param1;
+	if (!test_suspend_state(SUSPEND_DBG_USED))
+		suspend_debug_state = suspend_header->param2;
+	if (!test_suspend_state(SUSPEND_LVL_USED))
+		suspend_default_console_level = suspend_header->param3;
+	clear_suspend_state(SUSPEND_IGNORE_LOGLEVEL);
+	pagedir2.pageset_size = suspend_header->pageset_2_size;
+	for (i = 0; i < 4; i++)
+		suspend_io_time[i/2][i%2] =
+			suspend_header->io_time[i/2][i%2];
+
+	set_suspend_state(SUSPEND_NOW_RESUMING);
+
+	/* Read plugin configurations */
+	if ((result = read_plugin_configs())) {
+		noresume_reset_plugins();
+		pagedir1.pageset_size =
+			pagedir2.pageset_size = 0;
+		goto out;
+	}
+
+	suspend2_prepare_console();
+
+	check_shift_keys(1, "About to read original pageset1 locations.");
+	/* Read original pageset1 locations. These are the addresses we can't use for
+	 * the data to be restored */
+	suspend_allocate_dyn_pageflags(&pageset1_map);
+	load_dyn_pageflags(pageset1_map);
+
+	/* Relocate it so that it's not overwritten while we're using it to
+	 * copy the original contents back */
+	relocate_dyn_pageflags(&pageset1_map);
+	
+	suspend_allocate_dyn_pageflags(&pageset1_copy_map);
+	relocate_dyn_pageflags(&pageset1_copy_map);
+
+	/* Read extent pages */
+	if ((result = active_writer->ops.writer.load_extents())) {
+		noresume_reset_plugins();
+		abort_suspend("Active writer's load_extents "
+				"function failed.");
+		goto out;
+	}
+
+	/* Clean up after reading the header */
+	if ((result = active_writer->ops.writer.read_header_cleanup())) {
+		noresume_reset_plugins();
+		goto out;
+	}
+
+	check_shift_keys(1, "About to read pagedir.");
+
+	/* 
+	 * Get the addresses of pages into which we will load the kernel to
+	 * be copied back
+	 */
+	if (suspend2_get_pageset1_load_addresses()) {
+		result = -ENOMEM;
+		noresume_reset_plugins();
+		goto out;
+	}
+
+	/* Read the original kernel back */
+	check_shift_keys(1, "About to read pageset 1.");
+
+	if (read_pageset(&pagedir1, 1, 0)) {
+		suspend2_prepare_status(1, 1, "Failed to read pageset 1.");
+		result = -EPERM;
+		noresume_reset_plugins();
+		goto out;
+	}
+
+	check_shift_keys(1, "About to restore original kernel.");
+	result = 0;
+
+	if (active_writer->ops.writer.mark_resume_attempted)
+		active_writer->ops.writer.mark_resume_attempted();
+
+out:
+	free_pages((unsigned long) header_buffer, 0);
+	return result;
+}
+
+/* read_pageset1()
+ *
+ * Description:	Attempt to read the header and pageset1 of a suspend image.
+ * 		Handle the outcome, complaining where appropriate.
+ */
+int read_pageset1(void)
+{
+	int error;
+
+	error = __read_pageset1();
+
+	switch (error) {
+		case 0:
+		case -ENODATA:
+		case -EINVAL:	/* non fatal error */
+			return error;
+		case -EIO:
+			printk(KERN_CRIT name_suspend "I/O error\n");
+			break;
+		case -ENOENT:
+			printk(KERN_CRIT name_suspend "No such file or directory\n");
+			break;
+		case -EPERM:
+			printk(KERN_CRIT name_suspend "Sanity check error\n");
+			break;
+		default:
+			printk(KERN_CRIT name_suspend "Error %d resuming\n", error);
+			break;
+	}
+	abort_suspend("Error %d in read_pageset1",error);
+	return error;
+}
+
+/* read_pageset2()
+ *
+ * Description:	Read in part or all of pageset2 of an image, depending upon
+ * 		whether we are suspending and have only overwritten a portion
+ * 		with pageset1 pages, or are resuming and need to read them 
+ * 		all.
+ * Arguments:	Int. Boolean. Read only pages which would have been
+ * 		overwritten by pageset1?
+ * Returns:	Int. Zero if no error, otherwise the error value.
+ */
+int read_pageset2(int overwrittenpagesonly)
+{
+	int result = 0;
+
+	if (!pageset2_size)
+		return 0;
+
+	result = read_pageset(&pagedir2, 2, overwrittenpagesonly);
+
+	suspend2_update_status(100, 100, NULL);
+	check_shift_keys(1, "Pagedir 2 read.");
+
+	return result;
+}
kernel/power/suspend2_core/io.h +44 -0

44 lines not on this page · raw message

#112 lore raw

Re: [PATCH] [34/48] Suspend2 2.1.9.8 for 2.6.12: 610-extent.patch

kernel/power/suspend2_core/io.c 2005-07-05 23:48:59.000000000 +1000 line 5

Quoted 9 lines · Nigel Cunningham

diff -ruNp 611-io.patch-old/kernel/power/suspend2_core/io.c 611-io.patch-new/kernel/power/suspend2_core/io.c

kernel/power/suspend2_core/io.c 2005-07-05 23:48:59.000000000 +1000 renamed from kernel/power/suspend2_core/io.c 1970-01-01 10:00:00.000000000 +1000 +5 -0
@@ -0,0 +1,1006 @@
+/*
+ * kernel/power/io.c
+ *
+ * Copyright (C) 1998-2001 Gabor Kuti <[email protected]>
+ * Copyright (C) 1998,2001,2002 Pavel Machek <[email protected]>
                                           ^

Whitespace damage (appears elsewhere too).

Quoted 3 lines
kernel/power/suspend2_core/io.c 2005-07-05 23:48:59.000000000 +1000 renamed from kernel/power/suspend2_core/io.c 1970-01-01 10:00:00.000000000 +1000 +3 -0
+ * Copyright (C) 2002-2003 Florent Chabaud <[email protected]>
+ * Copyright (C) 2002-2005 Nigel Cunningham <[email protected]>
+ *

[snip]

Quoted 26 lines
kernel/power/suspend2_core/io.c 2005-07-05 23:48:59.000000000 +1000 renamed from kernel/power/suspend2_core/io.c 1970-01-01 10:00:00.000000000 +1000 +26 -0
+       pc = size / 5;
+
+       /* Write the data */
+       for (i=0; i<size; i++) {
+               int was_mapped = 0;
+               struct page * page = pfn_to_page(current_page_index);
+
+               /* Status update */
+               if ((i+base) >= nextupdate)
+                       nextupdate = suspend2_update_status(i + base, barmax,
+                               " %d/%d MB ", MB(base+i+1), MB(barmax));
+
+               if ((i + 1) == pc) {
+                       printk("%d%%...", 20 * step);
+                       step++;
+                       pc = size * step / 5;
+               }
+
+               /* Write */
+               was_mapped = suspend_map_kernel_page(page, 1);
+               ret = first_filter->ops.filter.write_chunk(page);
+               if (!was_mapped)
+                       suspend_map_kernel_page(page, 0);
+
+               if (ret) {
+                       printk("Write chunk returned %d.\n", ret);

kernel/power/suspend2_core/io.c 2005-07-05 23:48:59.000000000 +1000

Quoted 10 lines
kernel/power/suspend2_core/io.c 2005-07-05 23:48:59.000000000 +1000 renamed from kernel/power/suspend2_core/io.c 1970-01-01 10:00:00.000000000 +1000 +10 -0
+                       abort_suspend("Failed to write a chunk of the "
+                                       "image.");
+                       error = -1;
+                       goto write_pageset_free_buffers;
+               }
+
+               /* Interactivity */
+               check_shift_keys(0, NULL);
+
+               if (TEST_RESULT_STATE(SUSPEND_ABORTED)) {

Why is the above in upper case but test_action_state is in lower case?

Quoted 109 lines
kernel/power/suspend2_core/io.c 2005-07-05 23:48:59.000000000 +1000 renamed from kernel/power/suspend2_core/io.c 1970-01-01 10:00:00.000000000 +1000 +109 -0
+                       abort_suspend("Aborting as requested.");
+                       error = -1;
+                       goto write_pageset_free_buffers;
+               }
+
+               /* Prepare next */
+               current_page_index = __get_next_bit_on(*pageflags, current_page_index);
+       }
+
+       printk("done.\n");
+
+       suspend2_update_status(base+size, barmax, " %d/%d MB ",
+                       MB(base+size), MB(barmax));
+
+write_pageset_free_buffers:
+
+       /* Cleanup other plugins */
+       list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+               if (this_plugin->disabled)
+                       continue;
+               if ((this_plugin->type == FILTER_PLUGIN) ||
+                   (this_plugin->type == WRITER_PLUGIN))
+                       continue;
+               if (this_plugin->write_cleanup)
+                       this_plugin->write_cleanup();
+       }
+
+       /* Flush data and cleanup */
+       list_for_each_entry(this_plugin, &suspend_filters, ops.filter.filter_list) {
+               if (this_plugin->disabled)
+                       continue;
+               if (this_plugin->write_cleanup)
+                       this_plugin->write_cleanup();
+       }
+       active_writer->write_cleanup();
+
+       /* Statistics */
+       end_time = jiffies;
+
+       if ((end_time - start_time) && (!TEST_RESULT_STATE(SUSPEND_ABORTED))) {
+               suspend_io_time[0][0] += size,
+               suspend_io_time[0][1] += (end_time - start_time);
+       }
+
+       return error;
+}
+
+/* read_pageset()
+ *
+ * Description:        Read a pageset from disk.
+ * Arguments:  pagedir:        Pointer to the pagedir to be saved.
+ *             whichtowrite:   Controls what debugging output is printed.
+ *             overwrittenpagesonly: Whether to read the whole pageset or
+ *             only part.
+ * Returns:    Zero on success or -1 on failure.
+ */
+
+static int read_pageset(struct pagedir * pagedir, int whichtoread,
+               int overwrittenpagesonly)
+{
+       int nextupdate = 0, result = 0, base = 0;
+       int start_time, end_time, finish_at = pagedir->pageset_size;
+       int barmax = pagedir1.pageset_size + pagedir2.pageset_size;
+       int i, pc, step = 1;
+       struct suspend_plugin_ops * this_plugin, * first_filter = get_next_filter(NULL);
+       dyn_pageflags_t *pageflags;
+       int current_page_index;
+
+       if (whichtoread == 1) {
+               suspend2_prepare_status(1, 1, "Reading kernel & process data...");
+               pageflags = &pageset1_copy_map;
+       } else {
+               suspend2_prepare_status(1, 0, "Reading caches...");
+               if (overwrittenpagesonly)
+                       barmax = finish_at = min(pageset1_size, pageset2_size);
+               else {
+                       base = pagedir1.pageset_size;
+               }
+               pageflags = &pageset2_map;
+       }
+
+       start_time=jiffies;
+
+       /* Initialise page transformers */
+       list_for_each_entry(this_plugin, &suspend_filters, ops.filter.filter_list) {
+               if (this_plugin->disabled)
+                       continue;
+               if (this_plugin->read_init &&
+                               this_plugin->read_init(whichtoread)) {
+                       abort_suspend("Failed to initialise a filter.");
+                       result = 1;
+                       goto read_pageset_free_buffers;
+               }
+       }
+
+       /* Initialise writer */
+       if (active_writer->read_init(whichtoread)) {
+               abort_suspend("Failed to initialise the writer.");
+               result = 1;
+               goto read_pageset_free_buffers;
+       }
+
+       /* Initialise other plugins */
+       list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+               if (this_plugin->disabled)
+                       continue;
+               if ((this_plugin->type == FILTER_PLUGIN) ||
+                   (this_plugin->type == WRITER_PLUGIN))
+                       continue;

kernel/power/suspend2_core/io.c 2005-07-05 23:48:59.000000000 +1000

Quoted 10 lines
kernel/power/suspend2_core/io.c 2005-07-05 23:48:59.000000000 +1000 renamed from kernel/power/suspend2_core/io.c 1970-01-01 10:00:00.000000000 +1000 +10 -0
+               if (this_plugin->read_init)
+                       if (this_plugin->read_init(whichtoread)) {
+                               SET_RESULT_STATE(SUSPEND_ABORTED);
+                               goto read_pageset_free_buffers;
+                       }
+       }
+
+       current_page_index = __get_next_bit_on(*pageflags, -1);
+
+       pc = finish_at / 5;

What's the magic number 5 that pops up everywhere?

#113 lore raw

PATCH 35/48 Suspend2 2.1.9.8 for 2.6.12: 611-io.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/pagedir.c +336 -0
diff -ruNp 612-pagedir.patch-old/kernel/power/suspend2_core/pagedir.c 612-pagedir.patch-new/kernel/power/suspend2_core/pagedir.c
@@ -0,0 +1,336 @@
+/*
+ * kernel/power/pagedir.c
+ *
+ * Copyright (C) 1998-2001 Gabor Kuti <[email protected]>
+ * Copyright (C) 1998,2001,2002 Pavel Machek <[email protected]>
+ * Copyright (C) 2002-2003 Florent Chabaud <[email protected]>
+ * Copyright (C) 2002-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Routines for handling pagesets.
+ * Note that pbes aren't actually stored as such. They're stored as
+ * bitmaps and extents.
+ */
+
+#include <linux/suspend.h>
+#include <linux/highmem.h>
+#include <linux/bootmem.h>
+
+#include "pageflags.h"
+#include "ui.h"
+#include "pagedir.h"
+
+int extra_pagedir_pages_allocated = 0;
+static LIST_HEAD(conflicting_pages);
+
+/* suspend2_free_pagedir_data
+ *
+ * Description:	Free a previously pagedir metadata.
+ */
+void suspend2_free_pagedir_data(void)
+{
+	int pagenumber;
+
+	free_dyn_pageflags(&pageset1_map);
+	free_dyn_pageflags(&pageset2_map);
+	free_dyn_pageflags(&pageset1_copy_map);
+
+	/* Free allocated pages */
+	if (allocd_pages_map) {
+		BITMAP_FOR_EACH_SET(allocd_pages_map, pagenumber) {
+			struct page * page = pfn_to_page(pagenumber);
+			ClearPageNosave(page);
+			__free_pages(page, 0);
+			extra_pagedir_pages_allocated--;
+		}
+		free_dyn_pageflags(&allocd_pages_map);
+	}
+
+	pagedir1.pageset_size = pagedir2.pageset_size = 0;
+}
+
+/* suspend2_allocate_extra_pagedir_memory
+ *
+ * Description:	Allocate memory for making the atomic copy of pagedir1 in the
+ * 		case where it is bigger than pagedir2.
+ * Arguments:	struct pagedir *: 	The pagedir for which we should 
+ * 					allocate memory.
+ * 		int:			Size of pageset 1.
+ * 		int:			Size of pageset 2.
+ * Result:	int. Zero on success. One if unable to allocate enough memory.
+ */
+int suspend2_allocate_extra_pagedir_memory(struct pagedir * p, int pageset_size,
+		int alloc_from)
+{
+	int num_to_alloc = pageset_size - alloc_from - extra_pagedir_pages_allocated;
+	int j, order;
+
+	if (num_to_alloc < 1)
+		num_to_alloc = 0;
+
+	if (num_to_alloc) {
+		int num_added = 0;
+	
+		order = generic_fls(num_to_alloc);
+		if (order >= MAX_ORDER)
+			order = MAX_ORDER - 1;
+
+		while (num_added < num_to_alloc) {
+			struct page * newpage;
+			unsigned long virt;
+			
+			while ((1 << order) > (num_to_alloc - num_added))
+				order--;
+
+			virt = __get_free_pages(GFP_ATOMIC, order);
+			while ((!virt) && (order > 0)) {
+				order--;
+				virt = __get_free_pages(GFP_ATOMIC, order);
+			}
+
+			if (!virt) {
+				p->pageset_size += num_added;
+				return 1;
+			}
+
+			newpage = virt_to_page(virt);
+			for (j = 0; j < (1 << order); j++) {
+				SetPageNosave(newpage + j);
+				/* Pages will be freed one at a time. */
+				set_page_count(newpage + j, 1);
+				SetPageAllocd(newpage + j);
+				extra_pagedir_pages_allocated++;
+			}
+			num_added+= (1 << order);
+		}
+	}
+
+	//p->pageset_size = pageset_size;
+	return 0;
+}
+
+/*
+ * suspend2_mark_task_as_pageset1
+ * Functionality   : Marks all the pages belonging to a given process as
+ *                   pageset 1 pages.
+ * Called From     : pagedir.c - mark_pages_for_pageset2
+ *
+ * This is a builtin to avoid exporting follow_page.
+ */
+void suspend2_mark_task_as_pageset1(struct task_struct *t)
+{
+	struct vm_area_struct *vma;
+	struct mm_struct *mm;
+
+	mm = t->active_mm;
+
+	if (!mm || !mm->mmap) return;
+
+	down_read(&mm->mmap_sem);
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
+		unsigned long posn;
+
+		if (!vma->vm_start)
+			continue;
+
+		for (posn = vma->vm_start; posn < vma->vm_end; posn += PAGE_SIZE) {
+			struct page *page = follow_page(mm, posn, 0);
+			if (page)
+				ClearPagePageset2(page);
+		}
+	}
+	up_read(&mm->mmap_sem);
+}
+
+/* mark_pages_for_pageset2
+ *
+ * Description:	Mark unshared pages in processes not needed for suspend as
+ * 		being able to be written out in a separate pagedir.
+ * 		HighMem pages are simply marked as pageset2. They won't be
+ * 		needed during suspend.
+ */
+
+void suspend2_mark_pages_for_pageset2(void)
+{
+	struct zone * zone;
+	struct task_struct *p, *g;
+	unsigned long flags;
+	int i;
+
+	clear_dyn_pageflags(pageset2_map);
+
+	/* 
+	 * Note that we don't clear the map to begin with!
+	 * This is because if we eat memory, we loose track
+	 * of LRU pages that are still in use but taken off
+	 * the LRU. If I can figure out how the VM keeps
+	 * track of them, I might be able to tweak this a
+	 * little further and decrease pageset one's size
+	 * further.
+	 *
+	 * (Memory grabbing clears the pageset2 flag on
+	 * pages that are really freed!).
+	 */
+	
+	/* Add LRU pages */
+	for_each_zone(zone) {
+		spin_lock_irqsave(&zone->lru_lock, flags);
+		if (zone->nr_inactive) {
+			struct page * page;
+			list_for_each_entry(page, &zone->inactive_list, lru)
+				SetPagePageset2(page);
+		}
+		if (zone->nr_active) {
+			struct page * page;
+			list_for_each_entry(page, &zone->active_list, lru)
+				SetPagePageset2(page);
+		}
+		spin_unlock_irqrestore(&zone->lru_lock, flags);
+	}
+
+	/* Now we find all userspace process (with task->mm) marked PF_NOFREEZE
+	 * and move them into pageset1.
+	 */
+	read_lock(&tasklist_lock);
+	do_each_thread(g, p) {
+		if ((p->mm || p->active_mm) && (p->flags & PF_NOFREEZE))
+			suspend2_mark_task_as_pageset1(p);
+	} while_each_thread(g, p);
+	read_unlock(&tasklist_lock);
+
+	for (i = 0; i < max_pfn; i++) {
+		struct page * page = pfn_to_page(i);
+		BUG_ON(PagePageset2(page) && PageSlab(page));
+	}
+}
+
+/* suspend2_get_nonconflicting_pages
+ *
+ * Description: Gets higher-order pages that won't be overwritten
+ *		while copying the original pages.
+ *
+ *		Note that if only one of the allocated pages overlaps
+ *		with the pages that overlap, another set must be
+ *		tried. Therefore, you shouldn't use this function
+ *		much, and not with high orders.
+ */
+
+unsigned long suspend2_get_nonconflicting_pages(const int order)
+{
+	struct page * page;
+	unsigned long new_page;
+	int more = 0;
+	unsigned long pgcount;
+
+	do {
+		new_page = __get_free_pages(GFP_ATOMIC | __GFP_NOWARN, order);
+		if (!new_page)
+			return 0;
+		more = 0;
+		for (pgcount = 0; pgcount < (1UL << order); pgcount++) {
+			page = virt_to_page(new_page + PAGE_SIZE * pgcount);
+			if (PagePageset1(page)) {
+				more = 1;
+				break;
+			}
+		}
+		if (more) {
+			page = virt_to_page(new_page);
+			list_add(&page->lru, &conflicting_pages);
+
+			/* since this page is technically free, we can abuse it to
+			 * store the order. When we resume it'll just be overwritten,
+			 * but we need this value when freeing it in
+			 * suspend2_release_conflicting_pages. */
+			*((int*)new_page) = order;
+		}
+	}
+	while (more);
+
+	memset((void*)new_page, 0, PAGE_SIZE * (1<<order));
+	return new_page;
+}
+
+/* suspend2_get_nonconflicting_page
+ *
+ * Description: Gets a page that will not be overwritten as we copy the
+ * 		original kernel page.
+ */
+
+unsigned long suspend2_get_nonconflicting_page(void)
+{
+	return suspend2_get_nonconflicting_pages(0);
+}
+
+/* suspend2_release_conflicting_pages
+ *
+ * Description: Release conflicting pages. If we resume, we don't care (their
+ * 		status will not matter), but if we abort for some reason, they
+ * 		should not leak.
+ */
+
+void suspend2_release_conflicting_pages(void)
+{
+	struct page *this_page, *next;
+	int order;
+
+	list_for_each_entry_safe(this_page, next, &conflicting_pages, lru)
+	{
+		order = *((int*)(page_address(this_page)));
+		__free_pages(virt_to_page(this_page), order);
+	}
+}
+
+/* relocate_page_if_required
+ *
+ * Description: Given the address of a pointer to a page, we check if the page
+ * 		needs relocating and do so if needs be, adjusting the pointer
+ * 		too.
+ */
+
+void suspend2_relocate_page_if_required(void ** page_pointer_addr)
+{
+	void * current_value = *page_pointer_addr;
+	if PagePageset1(virt_to_page(current_value)) {
+		unsigned long * new_page = (unsigned long *) suspend2_get_nonconflicting_page();
+		memcpy(new_page, current_value, PAGE_SIZE);
+		free_pages((unsigned long) current_value, 0);
+		*page_pointer_addr = new_page;
+	}
+}
+
+/* get_pageset1_load_addresses
+ * 
+ * Description: We check here that pagedir & pages it points to won't collide
+ * 		with pages where we're going to restore from the loaded pages
+ * 		later.
+ * Returns:	Zero on success, one if couldn't find enough pages (shouldn't
+ * 		happen).
+ */
+
+int suspend2_get_pageset1_load_addresses(void)
+{
+	int i, nrdone = 0, result = 0;
+	void *this;
+
+	/*
+	 * Because we're trying to make this work when we're saving as much
+	 * memory as possible we need to remember the pages we reject here
+	 * and then free them when we're done.
+	 */
+	
+	for(i=0; i < pagedir1.pageset_size; i++) {
+		this = (void *) suspend2_get_nonconflicting_page();
+		if (!this) {
+			abort_suspend("Error: Ran out of memory seeking locations for reloading data.");
+			result = 1;
+			break;
+		}
+		SetPagePageset1Copy(virt_to_page(this));
+		nrdone++;
+	}
+	suspend2_release_conflicting_pages();
+
+	return result;
+}
kernel/power/suspend2_core/pagedir.h +55 -0

55 lines not on this page · raw message

#114 lore raw

Re: [PATCH] [35/48] Suspend2 2.1.9.8 for 2.6.12: 611-io.patch

Hi!

kernel/power/suspend2_core/pagedir.c line 109

Quoted 1 line
kernel/power/suspend2_core/pagedir.c +1 -0
+	//p->pageset_size = pageset_size;

Please don't leave commented code in.

Quoted 36 lines
kernel/power/suspend2_core/pagedir.c +36 -0
+unsigned long suspend2_get_nonconflicting_pages(const int order)
+{
+	struct page * page;
+	unsigned long new_page;
+	int more = 0;
+	unsigned long pgcount;
+
+	do {
+		new_page = __get_free_pages(GFP_ATOMIC | __GFP_NOWARN, order);
+		if (!new_page)
+			return 0;
+		more = 0;
+		for (pgcount = 0; pgcount < (1UL << order); pgcount++) {
+			page = virt_to_page(new_page + PAGE_SIZE * pgcount);
+			if (PagePageset1(page)) {
+				more = 1;
+				break;
+			}
+		}
+		if (more) {
+			page = virt_to_page(new_page);
+			list_add(&page->lru, &conflicting_pages);
+
+			/* since this page is technically free, we can abuse it to
+			 * store the order. When we resume it'll just be overwritten,
+			 * but we need this value when freeing it in
+			 * suspend2_release_conflicting_pages. */
+			*((int*)new_page) = order;
+		}
+	}
+	while (more);
+
+	memset((void*)new_page, 0, PAGE_SIZE * (1<<order));
+	return new_page;
+}
+

kernel/power/suspend2_core/pagedir.c line 264

Quoted 10 lines
kernel/power/suspend2_core/pagedir.c +10 -0
+/* suspend2_get_nonconflicting_page
+ *
+ * Description: Gets a page that will not be overwritten as we copy the
+ * 		original kernel page.
+ */
+
+unsigned long suspend2_get_nonconflicting_page(void)
+{
+	return suspend2_get_nonconflicting_pages(0);
+}

Can you just replace it in callers?

kernel/power/suspend2_core/pagedir.h line 24

Quoted 2 lines
kernel/power/suspend2_core/pagedir.h +2 -0
+#define pageset1_size (pagedir1.pageset_size)
+#define pageset2_size (pagedir2.pageset_size)

This only makes reading code harder...

Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#115 lore raw

Re: [PATCH] [35/48] Suspend2 2.1.9.8 for 2.6.12: 611-io.patch

Hi.

Quoted 5 lines · Pavel Machek

Hi!

kernel/power/suspend2_core/pagedir.c line 109

Quoted 1 line
kernel/power/suspend2_core/pagedir.c +1 -0
+	//p->pageset_size = pageset_size;

Please don't leave commented code in.

Fixed.

Quoted 40 lines
Quoted 40 lines
kernel/power/suspend2_core/pagedir.c +40 -0
+unsigned long suspend2_get_nonconflicting_pages(const int order)
+{
+	struct page * page;
+	unsigned long new_page;
+	int more = 0;
+	unsigned long pgcount;
+
+	do {
+		new_page = __get_free_pages(GFP_ATOMIC | __GFP_NOWARN, order);
+		if (!new_page)
+			return 0;
+		more = 0;
+		for (pgcount = 0; pgcount < (1UL << order); pgcount++) {
+			page = virt_to_page(new_page + PAGE_SIZE * pgcount);
+			if (PagePageset1(page)) {
+				more = 1;
+				break;
+			}
+		}
+		if (more) {
+			page = virt_to_page(new_page);
+			list_add(&page->lru, &conflicting_pages);
+
+			/* since this page is technically free, we can abuse it to
+			 * store the order. When we resume it'll just be overwritten,
+			 * but we need this value when freeing it in
+			 * suspend2_release_conflicting_pages. */
+			*((int*)new_page) = order;
+		}
+	}
+	while (more);
+
+	memset((void*)new_page, 0, PAGE_SIZE * (1<<order));
+	return new_page;
+}
+
+/* suspend2_get_nonconflicting_page
+ *
+ * Description: Gets a page that will not be overwritten as we copy the
+ * 		original kernel page.
Quoted 8 lines

kernel/power/suspend2_core/pagedir.c line 264

Quoted 6 lines

+ */

kernel/power/suspend2_core/pagedir.c +5 -0
+
+unsigned long suspend2_get_nonconflicting_page(void)
+{
+	return suspend2_get_nonconflicting_pages(0);
+}

Can you just replace it in callers?

Done.

Quoted 4 lines

kernel/power/suspend2_core/pagedir.h line 24

Quoted 2 lines
kernel/power/suspend2_core/pagedir.h +2 -0
+#define pageset1_size (pagedir1.pageset_size)
+#define pageset2_size (pagedir2.pageset_size)

This only makes reading code harder...

Removed.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#116 lore raw

PATCH 36/48 Suspend2 2.1.9.8 for 2.6.12: 612-pagedir.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/pageflags.c +126 -0
diff -ruNp 613-pageflags.patch-old/kernel/power/suspend2_core/pageflags.c 613-pageflags.patch-new/kernel/power/suspend2_core/pageflags.c
@@ -0,0 +1,126 @@
+/*
+ * kernel/power/suspend2_core/pageflags.c
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <[email protected]>
+ * 
+ * This file is released under the GPLv2.
+ *
+ * Routines for dynamically allocating and releasing bitmaps
+ * used as pseudo-pageflags.
+ *
+ * Arrays are not contiguous. The first sizeof(void *) bytes are
+ * the pointer to the next page in the bitmap. This allows us to
+ * 1) work under low memory conditions where order 0 might be all
+ *    that's available
+ * 2) save the pages at suspend time, reload and relocate them as
+ *    necessary at resume time without breaking anything (cf
+ *    extent pages).
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/list.h>
+#include <linux/suspend.h>
+#include "pageflags.h"
+#include "plugins.h"
+#include "pagedir.h"
+
+/* Maps used in copying the image back are in builtin.c */
+dyn_pageflags_t pageset1_map;
+dyn_pageflags_t pageset1_copy_map;
+dyn_pageflags_t pageset2_map;
+dyn_pageflags_t in_use_map;
+dyn_pageflags_t allocd_pages_map;
+#ifdef CONFIG_DEBUG_PAGEALLOC
+dyn_pageflags_t unmap_map;
+#endif
+
+/* suspend_allocate_dyn_pageflags
+ *
+ * Description:	Allocate a bitmap for local page flags.
+ * Arguments:	dyn_pageflags_t *:	Pointer to the bitmap.
+ *
+ * A version of allocate_dyn_pageflags that saves us then having
+ * to relocate the flags when resuming.
+ */
+int suspend_allocate_dyn_pageflags(dyn_pageflags_t *pagemap)
+{
+	int i;
+
+	BUG_ON(*pagemap);
+
+	if (test_suspend_state(SUSPEND_NOW_RESUMING)) {
+		/* 
+		 * We use kfree unconditionally below. That's not a problem
+		 * because we only use this path when reloading pageset1.
+		 */
+		*pagemap = (dyn_pageflags_t) suspend2_get_nonconflicting_page();
+		if (! *pagemap) {
+			printk("Failed to allocate a non-conflicting page for pageflags.\n");
+			return 1;
+		}
+	} else 
+		*pagemap = kmalloc(sizeof(void *) * PAGES_PER_BITMAP, GFP_ATOMIC);
+
+	for (i = 0; i < PAGES_PER_BITMAP; i++) {
+		(*pagemap)[i] = (unsigned long *) get_zeroed_page(GFP_ATOMIC);
+		if (!(*pagemap)[i]) {
+			printk("Error. Unable to allocate memory for "
+					"local page flags.");
+			free_dyn_pageflags(pagemap);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/* savepageflags
+ *
+ * Description: Save a set of pageflags.
+ * Arguments:   dyn_pageflags_t *: Pointer to the bitmap being saved.
+ */
+
+void save_dyn_pageflags(dyn_pageflags_t pagemap)
+{
+	int i;
+
+	if (!*pagemap)
+		return;
+
+	for (i = 0; i < PAGES_PER_BITMAP; i++)
+		active_writer->ops.writer.write_header_chunk((char *) pagemap[i], PAGE_SIZE);
+}
+
+/* loadpageflags
+ *
+ * Description: Load a set of pageflags.
+ * Arguments:   dyn_pageflags_t *: Pointer to the bitmap being loaded.
+ *              (It must be allocated before calling this routine).
+ */
+
+void load_dyn_pageflags(dyn_pageflags_t pagemap)
+{
+	int i;
+
+	if (!pagemap)
+		return;
+
+	for (i = 0; i < PAGES_PER_BITMAP; i++)
+		active_writer->ops.writer.read_header_chunk((char *) pagemap[i], PAGE_SIZE);
+}
+
+void relocate_dyn_pageflags(dyn_pageflags_t *pagemap)
+{
+	int i;
+	LIST_HEAD(rejected_pages);
+
+	if (!*pagemap)
+		return;
+
+	suspend2_relocate_page_if_required((void *) pagemap);
+
+	for (i = 0; i < PAGES_PER_BITMAP; i++)
+		suspend2_relocate_page_if_required((void *) &((*pagemap)[i]));
+}
kernel/power/suspend2_core/pageflags.h +84 -0

84 lines not on this page · raw message

#117 lore raw

PATCH 37/48 Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/plugins.c +341 -0
diff -ruNp 614-plugins.patch-old/kernel/power/suspend2_core/plugins.c 614-plugins.patch-new/kernel/power/suspend2_core/plugins.c
@@ -0,0 +1,341 @@
+/*
+ * kernel/power/plugins.c
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <[email protected]>
+ *
+ */
+
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include "suspend.h"
+#include "plugins.h"
+
+struct list_head suspend_filters, suspend_writers, suspend_plugins;
+struct suspend_plugin_ops * active_writer = NULL;
+static int num_filters = 0, num_ui = 0;
+int num_writers = 0, num_plugins = 0;
+
+/*
+ * header_storage_for_plugins
+ *
+ * Returns the amount of space needed to store configuration
+ * data needed by the plugins prior to copying back the original
+ * kernel. We can exclude data for pageset2 because it will be
+ * available anyway once the kernel is copied back.
+ */
+unsigned long header_storage_for_plugins(void)
+{
+	struct suspend_plugin_ops * this_plugin;
+	unsigned long bytes = 0;
+	
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->storage_needed)
+			bytes += this_plugin->storage_needed();
+	}
+
+	return bytes;
+}
+
+/*
+ * expected_compression_ratio
+ *
+ * Returns the expected ratio between the amount of memory
+ * to be saved and the amount of space required on the
+ * storage device.
+ */
+int expected_compression_ratio(void)
+{
+	struct suspend_plugin_ops * this_filter;
+	unsigned long ratio = 100;
+	
+	list_for_each_entry(this_filter, &suspend_filters, ops.filter.filter_list) {
+		if (this_filter->disabled)
+			continue;
+		if (this_filter->ops.filter.expected_compression)
+			ratio = ratio * this_filter->ops.filter.expected_compression() / 100;
+	}
+
+	return (int) ratio;
+}
+
+/*
+ * memory_for_plugins
+ *
+ * Returns the amount of memory requested by plugins for
+ * doing their work during the cycle.
+ */
+
+unsigned long memory_for_plugins(void)
+{
+	unsigned long bytes = 0;
+	struct suspend_plugin_ops * this_plugin;
+
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->memory_needed)
+			bytes += this_plugin->memory_needed();
+	}
+
+	return ((bytes + PAGE_SIZE - 1) >> PAGE_SHIFT);
+}
+
+/* find_plugin_given_name
+ * Functionality :	Return a plugin (if found), given a pointer
+ * 			to its name
+ */
+
+struct suspend_plugin_ops * find_plugin_given_name(char * name)
+{
+	struct suspend_plugin_ops * this_plugin, * found_plugin = NULL;
+	
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (!strcmp(name, this_plugin->name)) {
+			found_plugin = this_plugin;
+			break;
+		}			
+	}
+
+	return found_plugin;
+}
+
+/*
+ * print_plugin_debug_info
+ * Functionality   : Get debugging info from plugins into a buffer.
+ */
+int print_plugin_debug_info(char * buffer, int buffer_size)
+{
+	struct suspend_plugin_ops *this_plugin;
+	int len = 0;
+
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->print_debug_info) {
+			int result;
+			result = this_plugin->print_debug_info(buffer + len, 
+					buffer_size - len);
+			len += result;
+		}
+	}
+
+	return len;
+}
+
+/*
+ * suspend_register_plugin
+ *
+ * Register a plugin.
+ */
+int suspend_register_plugin(struct suspend_plugin_ops * plugin)
+{
+	if (find_plugin_given_name(plugin->name))
+		return -EBUSY;
+
+	switch (plugin->type) {
+		case FILTER_PLUGIN:
+			list_add_tail(&plugin->ops.filter.filter_list,
+					&suspend_filters);
+			num_filters++;
+			break;
+
+		case WRITER_PLUGIN:
+			list_add_tail(&plugin->ops.writer.writer_list,
+					&suspend_writers);
+			num_writers++;
+			break;
+
+		case MISC_PLUGIN:
+			break;
+
+		default:
+			printk("Hmmm. Plugin '%s' has an invalid type."
+				" It has been ignored.\n", plugin->name);
+			return -EINVAL;
+	}
+	list_add_tail(&plugin->plugin_list, &suspend_plugins);
+	num_plugins++;
+
+	return 0;	
+}
+
+/*
+ * suspend_unregister_plugin
+ *
+ * Remove a plugin.
+ */
+void suspend_unregister_plugin(struct suspend_plugin_ops * plugin)
+{
+	switch (plugin->type) {
+		case FILTER_PLUGIN:
+			list_del(&plugin->ops.filter.filter_list);
+			num_filters--;
+			break;
+
+		case WRITER_PLUGIN:
+			list_del(&plugin->ops.writer.writer_list);
+			num_writers--;
+			if (active_writer == plugin) {
+				active_writer = NULL;
+				set_suspend_state(SUSPEND_DISABLED);
+			}
+			break;
+		
+		case MISC_PLUGIN:
+			break;
+
+		default:
+			printk("Hmmm. Plugin '%s' has an invalid type."
+				" It has been ignored.\n", plugin->name);
+			return;
+	}
+	list_del(&plugin->plugin_list);
+	num_plugins--;
+}
+
+/*
+ * suspend_move_plugin_tail
+ *
+ * Rearrange plugins when reloading the config.
+ */
+void suspend_move_plugin_tail(struct suspend_plugin_ops * plugin)
+{
+	switch (plugin->type) {
+		case FILTER_PLUGIN:
+			if (num_filters > 1)
+				list_move_tail(&plugin->ops.filter.filter_list,
+						&suspend_filters);
+			break;
+
+		case WRITER_PLUGIN:
+			if (num_writers > 1)
+				list_move_tail(&plugin->ops.writer.writer_list,
+						&suspend_writers);
+			break;
+		
+		case MISC_PLUGIN:
+			break;
+		default:
+			printk("Hmmm. Plugin '%s' has an invalid type."
+				" It has been ignored.\n", plugin->name);
+			return;
+	}
+	if ((num_filters + num_writers + num_ui) > 1)
+		list_move_tail(&plugin->plugin_list, &suspend_plugins);
+}
+
+/*
+ * suspend2_initialise_plugins
+ *
+ * Get ready to do some work!
+ */
+int suspend2_initialise_plugins(int starting_cycle)
+{
+	struct suspend_plugin_ops * this_plugin;
+	int result;
+	
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->type == WRITER_PLUGIN && 
+				this_plugin != active_writer)
+			continue;
+		if (this_plugin->initialise) {
+			suspend_message(SUSPEND_MEMORY, SUSPEND_MEDIUM, 1,
+				"Initialising plugin %s.\n",
+				this_plugin->name);
+			if ((result = this_plugin->initialise(starting_cycle))) {
+				printk("%s didn't initialise okay.\n",
+						this_plugin->name);
+				return result;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* 
+ * suspend2_cleanup_plugins
+ *
+ * Tell plugins the work is done.
+ */
+void suspend2_cleanup_plugins(int finishing_cycle)
+{
+	struct suspend_plugin_ops * this_plugin;
+	
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->type == WRITER_PLUGIN && 
+				this_plugin != active_writer)
+			continue;
+		if (this_plugin->cleanup) {
+			suspend_message(SUSPEND_MEMORY, SUSPEND_MEDIUM, 1,
+				"Cleaning up plugin %s.\n",
+				this_plugin->name);
+			this_plugin->cleanup(finishing_cycle);
+		}
+	}
+}
+
+/*
+ * get_next_filter
+ *
+ * Get the next filter in the pipeline.
+ */
+struct suspend_plugin_ops * 
+get_next_filter(struct suspend_plugin_ops * filter_sought)
+{
+	struct suspend_plugin_ops * last_filter = NULL, *this_filter = NULL;
+
+	list_for_each_entry(this_filter, &suspend_filters, ops.filter.filter_list) {
+		if (this_filter->disabled)
+			continue;
+		if ((last_filter == filter_sought) || (!filter_sought))
+			return this_filter;
+		last_filter = this_filter;
+	}
+
+	return active_writer;
+}
+
+/* suspend2_get_modules
+ * 
+ * Take a reference to modules so they can't go away under us.
+ */
+
+int suspend2_get_modules(void)
+{
+	struct suspend_plugin_ops * this_plugin;
+	
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (!try_module_get(this_plugin->module)) {
+			/* Failed! Reverse gets and return error */
+			struct suspend_plugin_ops * this_plugin2;
+			list_for_each_entry(this_plugin2, &suspend_plugins, plugin_list) {
+				if (this_plugin == this_plugin2)
+					return -EINVAL;
+				module_put(this_plugin2->module);
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* suspend2_put_modules
+ *
+ * Release our references to modules we used.
+ */
+
+void suspend2_put_modules(void)
+{
+	struct suspend_plugin_ops * this_plugin;
+	
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		module_put(this_plugin->module);
+	}
+}
kernel/power/suspend2_core/plugins.h +172 -0

172 lines not on this page · raw message

#118 lore raw

Re: [PATCH] [37/48] Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch

kernel/power/suspend2_core/plugins.c 2005-07-04 23:14:19.000000000 +1000 line 7

Quoted 11 lines · Nigel Cunningham

diff -ruNp 614-plugins.patch-old/kernel/power/suspend2_core/plugins.c 614-plugins.patch-new/kernel/power/suspend2_core/plugins.c

kernel/power/suspend2_core/plugins.c 2005-07-04 23:14:19.000000000 +1000 renamed from kernel/power/suspend2_core/plugins.c 1970-01-01 10:00:00.000000000 +1000 +7 -0
@@ -0,0 +1,341 @@
+#define FILTER_PLUGIN 1
+#define WRITER_PLUGIN 2
+#define MISC_PLUGIN 4 // Block writer, eg.
+#define CHECKSUM_PLUGIN 5
+
+#define SUSPEND_ASYNC 0
+#define SUSPEND_SYNC  1

Enums are preferred.

kernel/power/suspend2_core/plugins.c 2005-07-04 23:14:19.000000000 +1000 line 17

Quoted 10 lines
kernel/power/suspend2_core/plugins.c 2005-07-04 23:14:19.000000000 +1000 renamed from kernel/power/suspend2_core/plugins.c 1970-01-01 10:00:00.000000000 +1000 +10 -0
+
+#define SUSPEND_COMMON_IO_OPS \
+       /* Writing the image proper */ \
+       int (*write_chunk) (struct page * buffer_page); \
+\
+       /* Reading the image proper */ \
+       int (*read_chunk) (struct page * buffer_page, int sync); \
+\
+       /* Reset plugin if image exists but reading aborted */ \
+       void (*noresume_reset) (void);

Please remove the above macro obfuscation.

#119 lore raw

Re: [PATCH] [37/48] Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch

Hi.

Quoted 15 lines · Pekka Enberg

kernel/power/suspend2_core/plugins.c 2005-07-04 23:14:19.000000000 +1000 line 7

Quoted 11 lines · Nigel Cunningham

diff -ruNp 614-plugins.patch-old/kernel/power/suspend2_core/plugins.c 614-plugins.patch-new/kernel/power/suspend2_core/plugins.c

kernel/power/suspend2_core/plugins.c 2005-07-04 23:14:19.000000000 +1000 renamed from kernel/power/suspend2_core/plugins.c 1970-01-01 10:00:00.000000000 +1000 +7 -0
@@ -0,0 +1,341 @@
+#define FILTER_PLUGIN 1
+#define WRITER_PLUGIN 2
+#define MISC_PLUGIN 4 // Block writer, eg.
+#define CHECKSUM_PLUGIN 5
+
+#define SUSPEND_ASYNC 0
+#define SUSPEND_SYNC  1

Enums are preferred.

Quoted 12 lines

kernel/power/suspend2_core/plugins.c 2005-07-04 23:14:19.000000000 +1000 line 17

Quoted 10 lines
kernel/power/suspend2_core/plugins.c 2005-07-04 23:14:19.000000000 +1000 renamed from kernel/power/suspend2_core/plugins.c 1970-01-01 10:00:00.000000000 +1000 +10 -0
+
+#define SUSPEND_COMMON_IO_OPS \
+       /* Writing the image proper */ \
+       int (*write_chunk) (struct page * buffer_page); \
+\
+       /* Reading the image proper */ \
+       int (*read_chunk) (struct page * buffer_page, int sync); \
+\
+       /* Reset plugin if image exists but reading aborted */ \
+       void (*noresume_reset) (void);

Please remove the above macro obfuscation.

Done. Thanks!

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#120 lore raw

Re: [PATCH] [37/48] Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch

In reply to Nigel Cunningham

Hi!

You know what I think about plugins, right? There are already plugins at block device level, like raid5, LVM, device mapper... I do not see why you should need another one.

Quoted 11 lines
kernel/power/suspend2_core/plugins.c +11 -0
+/*
+ * expected_compression_ratio
+ *
+ * Returns the expected ratio between the amount of memory
+ * to be saved and the amount of space required on the
+ * storage device.
+ */
+int expected_compression_ratio(void)
+{
+	struct suspend_plugin_ops * this_filter;
+	unsigned long ratio = 100;

kernel/power/suspend2_core/plugins.c line 61

Quoted 10 lines
kernel/power/suspend2_core/plugins.c +10 -0
+	
+	list_for_each_entry(this_filter, &suspend_filters, ops.filter.filter_list) {
+		if (this_filter->disabled)
+			continue;
+		if (this_filter->ops.filter.expected_compression)
+			ratio = ratio * this_filter->ops.filter.expected_compression() / 100;
+	}
+
+	return (int) ratio;
+}

Why the cast and why long in the first place?

kernel/power/suspend2_core/plugins.c line 102

Quoted 13 lines
kernel/power/suspend2_core/plugins.c +13 -0
+struct suspend_plugin_ops * find_plugin_given_name(char * name)
+{
+	struct suspend_plugin_ops * this_plugin, * found_plugin = NULL;
+	
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (!strcmp(name, this_plugin->name)) {
+			found_plugin = this_plugin;
+			break;
+		}			
+	}
+
+	return found_plugin;
+}

How often are you doing this? Would hash table be prefered? How many plugins do you have? Maybe statical registration is right solution?

Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#121 lore raw

Re: [PATCH] [37/48] Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch

Hi.

Quoted 21 lines · Pavel Machek

Hi!

You know what I think about plugins, right? There are already plugins at block device level, like raid5, LVM, device mapper... I do not see why you should need another one.

Quoted 15 lines
kernel/power/suspend2_core/plugins.c +15 -0
+/*
+ * expected_compression_ratio
+ *
+ * Returns the expected ratio between the amount of memory
+ * to be saved and the amount of space required on the
+ * storage device.
+ */
+int expected_compression_ratio(void)
+{
+	struct suspend_plugin_ops * this_filter;
+	unsigned long ratio = 100;
+	
+	list_for_each_entry(this_filter, &suspend_filters, ops.filter.filter_list) {
+		if (this_filter->disabled)
+			continue;
Quoted 8 lines

kernel/power/suspend2_core/plugins.c line 61

Quoted 6 lines
kernel/power/suspend2_core/plugins.c +6 -0
+		if (this_filter->ops.filter.expected_compression)
+			ratio = ratio * this_filter->ops.filter.expected_compression() / 100;
+	}
+
+	return (int) ratio;
+}

Why the cast and why long in the first place?

My bad. Actually, since I recently switched to cryptoapi support, I can get rid of this function.

Quoted 8 lines
Quoted 8 lines
kernel/power/suspend2_core/plugins.c +8 -0
+struct suspend_plugin_ops * find_plugin_given_name(char * name)
+{
+	struct suspend_plugin_ops * this_plugin, * found_plugin = NULL;
+	
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (!strcmp(name, this_plugin->name)) {
+			found_plugin = this_plugin;
+			break;
Quoted 8 lines

kernel/power/suspend2_core/plugins.c line 102

Quoted 5 lines
kernel/power/suspend2_core/plugins.c +5 -0
+		}			
+	}
+
+	return found_plugin;
+}

How often are you doing this? Would hash table be prefered? How many plugins do you have? Maybe statical registration is right solution?

There would only be half a dozen tops.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#122 lore raw

PATCH 38/48 Suspend2 2.1.9.8 for 2.6.12: 614-plugins.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/power_off.c +148 -0
diff -ruNp 615-poweroff.patch-old/kernel/power/suspend2_core/power_off.c 615-poweroff.patch-new/kernel/power/suspend2_core/power_off.c
@@ -0,0 +1,148 @@
+/*
+ * kernel/power/suspend2_core/power_off.c
+ *
+ * Copyright (C) 2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Support for powering down.
+ */
+
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <linux/mm.h>
+#include <linux/pm.h>
+#include <linux/reboot.h>
+#include "suspend2_common.h"
+#include "suspend.h"
+#include "ui.h"
+
+unsigned long suspend2_powerdown_method = 5; /* S5 = off */
+static int suspend_pm_state_used = 0;
+
+extern struct pm_ops * pm_ops;
+
+#ifdef CONFIG_ACPI
+extern u32 acpi_leave_sleep_state (u8 sleep_state);
+#endif
+
+/* suspend_power_off
+ *
+ * Power off the machine.
+ */
+static void suspend_power_off(void)
+{
+	machine_power_off();
+	suspend2_prepare_status(1, 0, "Probably not capable for powerdown.");
+	while (1)
+		cpu_relax();
+	/* NOTREACHED */
+}
+
+/* suspend_pm_state_prepare
+ *
+ * Prepare to enter the sleep state.
+ */
+static int suspend_pm_state_prepare(void)
+{
+	int ret = 0;
+	
+	if (suspend2_powerdown_method == 3 ||
+	    suspend2_powerdown_method == 4)
+		if (pm_ops && pm_ops->prepare)
+			ret = pm_ops->prepare(suspend2_powerdown_method);
+
+	return ret;
+}
+
+/* suspend_pm_sleep_state_enter
+ * 
+ * Enter the sleep state requested.
+ */
+static int suspend_pm_state_enter(u32 state)
+{
+	int ret = 0;
+	unsigned long flags;
+	suspend_pm_state_used = state;
+
+	local_irq_save(flags);
+	device_power_down(PMSG_SUSPEND);
+	if (pm_ops && pm_ops->enter)
+		ret = pm_ops->enter(state);
+	else 
+		printk("Failed to enter state.\n");
+
+	device_power_up();
+	local_irq_restore(flags);
+
+	return ret;
+}
+
+/* suspend_pm_state_finish
+ *
+ * Finish the sleep state.
+ */
+int suspend_pm_state_finish(void)
+{
+	int ret = 0;
+
+	if (suspend2_powerdown_method == 3 ||
+	    suspend2_powerdown_method == 4)
+		if (pm_ops && pm_ops->finish)
+			ret = pm_ops->finish(suspend2_powerdown_method);
+
+	device_resume();
+
+	return ret;
+}
+
+/*
+ * suspend_power_down
+ * Functionality   : Powers down or reboots the computer once the image
+ *                   has been written to disk.
+ * Key Assumptions : Able to reboot/power down via code called or that
+ *                   the warning emitted if the calls fail will be visible
+ *                   to the user (ie printk resumes devices).
+ * Called From     : do_suspend2_suspend_2
+ */
+
+void suspend_power_down(void)
+{
+	if (TEST_ACTION_STATE(SUSPEND_REBOOT)) {
+		suspend2_prepare_status(1, 0, "Ready to reboot.");
+		device_shutdown();
+		machine_restart(NULL);
+	}
+
+	if (suspend2_powerdown_method == 3 ||
+	    suspend2_powerdown_method == 4) {
+		suspend2_prepare_status(1, 0, "Seeking to enter ACPI state");
+		if (suspend_pm_state_prepare()) {
+			suspend2_prepare_status(1, 0, "Preparing to enter ACPI state failed. Using normal powerdown.");
+			goto abort_ACPI_sleep;
+		}
+		if (device_suspend(PMSG_SUSPEND)) {
+			suspend2_prepare_status(1, 0, "Suspending devices failed. Using normal powerdown.");
+			suspend_pm_state_finish();
+			goto abort_ACPI_sleep;
+		}
+		if (suspend_pm_state_enter(suspend2_powerdown_method)) {
+			suspend2_prepare_status(1, 0, "Entering ACPI state failed. Using normal powerdown.");
+			suspend_pm_state_finish();
+			goto abort_ACPI_sleep;
+		}
+		suspend_pm_state_finish();
+		return;
+	} else
+		suspend2_prepare_status(1, 0, "Powering down.");
+	
+abort_ACPI_sleep:
+	/* 
+	 * FIXME: At resume, we'll still think we used S4 if we tried it.
+	 * Does it matter?
+	 */
+	suspend_pm_state_used = 0;
+	device_shutdown();
+	suspend_power_off();
+}
+
kernel/power/suspend2_core/power_off.h +13 -0
diff -ruNp 615-poweroff.patch-old/kernel/power/suspend2_core/power_off.h 615-poweroff.patch-new/kernel/power/suspend2_core/power_off.h
@@ -0,0 +1,13 @@
+/*
+ * kernel/power/suspend2_core/power_off.h
+ *
+ * Copyright (C) 2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Support for the powering down.
+ */
+
+int suspend_pm_state_finish(void);
+void suspend_power_down(void);
+extern unsigned long suspend2_powerdown_method;
#123 lore raw

Re: [PATCH] [38/48] Suspend2 2.1.9.8 for 2.6.12: 614-plugins.patch

Hi!

Quoted 1 line

+unsigned long suspend2_powerdown_method = 5; /* S5 = off */

Constants.....

Review

Quoted 2 lines
(quoted diff) +2 -0
+	if (suspend2_powerdown_method == 3 ||
+	    suspend2_powerdown_method == 4)

Constants...

Review

Quoted 2 lines
(quoted diff) +2 -0
+	if (suspend2_powerdown_method == 3 ||
+	    suspend2_powerdown_method == 4)

Constants...

kernel/power/suspend2_core/power_off.c line 137

Quoted 6 lines
kernel/power/suspend2_core/power_off.c +6 -0
+		suspend2_prepare_status(1, 0, "Ready to reboot.");
+		suspend2_prepare_status(1, 0, "Seeking to enter ACPI state");
+			suspend2_prepare_status(1, 0, "Preparing to enter ACPI state failed. Using normal powerdown.");
+			suspend2_prepare_status(1, 0, "Suspending devices failed. Using normal powerdown.");
+			suspend2_prepare_status(1, 0, "Entering ACPI state failed. Using normal powerdown.");
+		suspend2_prepare_status(1, 0, "Powering down.");

Too many magical constants here... Plus I don't really like your own logging subsystem.
Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#124 lore raw

Re: [PATCH] [38/48] Suspend2 2.1.9.8 for 2.6.12: 614-plugins.patch

Hi.

Quoted 11 lines · Pavel Machek

Hi!

Quoted 1 line

+unsigned long suspend2_powerdown_method = 5; /* S5 = off */

Constants.....

Review

Quoted 2 lines
(quoted diff) +2 -0
+	if (suspend2_powerdown_method == 3 ||
+	    suspend2_powerdown_method == 4)

Constants...

Quoted 4 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+	if (suspend2_powerdown_method == 3 ||
+	    suspend2_powerdown_method == 4)

Constants...

Once per file is enough :>

Quoted 9 lines

kernel/power/suspend2_core/power_off.c line 137

Quoted 6 lines
kernel/power/suspend2_core/power_off.c +6 -0
+		suspend2_prepare_status(1, 0, "Ready to reboot.");
+		suspend2_prepare_status(1, 0, "Seeking to enter ACPI state");
+			suspend2_prepare_status(1, 0, "Preparing to enter ACPI state failed. Using normal powerdown.");
+			suspend2_prepare_status(1, 0, "Suspending devices failed. Using normal powerdown.");
+			suspend2_prepare_status(1, 0, "Entering ACPI state failed. Using normal powerdown.");
+		suspend2_prepare_status(1, 0, "Powering down.");

Too many magical constants here... Plus I don't really like your own logging subsystem.

The first parameter isn't needed anymore - gone. Second one changed to an enum DONT_CLEAR_BAR | CLEAR_BAR.

Not liking it - that's alright there's some code you've written that I don't like either :>

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#125 lore raw

PATCH 39/48 Suspend2 2.1.9.8 for 2.6.12: 615-poweroff.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/prepare_image.c +585 -0
diff -ruNp 616-prepare_image.patch-old/kernel/power/suspend2_core/prepare_image.c 616-prepare_image.patch-new/kernel/power/suspend2_core/prepare_image.c
@@ -0,0 +1,585 @@
+/*
+ * kernel/power/prepare_image.c
+ *
+ * Copyright (C) 2003-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * We need to eat memory until we can:
+ * 1. Perform the save without changing anything (RAM_NEEDED < max_mapnr)
+ * 2. Fit it all in available space (active_writer->available_space() >= STORAGE_NEEDED)
+ * 3. Reload the pagedir and pageset1 to places that don't collide with their
+ *    final destinations, not knowing to what extent the resumed kernel will
+ *    overlap with the one loaded at boot time. I think the resumed kernel should overlap
+ *    completely, but I don't want to rely on this as it is an unproven assumption. We
+ *    therefore assume there will be no overlap at all (worse case).
+ * 4. Meet the user's requested limit (if any) on the size of the image.
+ *    The limit is in MB, so pages/256 (assuming 4K pages).
+ *
+ *    (Final test in save_image doesn't use EATEN_ENOUGH_MEMORY)
+ */
+
+#include <linux/highmem.h>
+
+#include "suspend.h"
+#include "pageflags.h"
+#include "plugins.h"
+#include "suspend2_common.h"
+#include "io.h"
+#include "ui.h"
+#include "extent.h"
+#include "prepare_image.h"
+
+#define EATEN_ENOUGH_MEMORY() (amount_needed(1) < 1)
+static int arefrozen = 0, numnosave = 0;
+static int header_space_allocated = 0;
+static int storage_allocated = 0;
+static int storage_available = 0;
+
+static int num_pcp_pages(void)
+{
+	struct zone *zone;
+	int result = 0, i = 0;
+
+	/* PCP lists */
+	for_each_zone(zone) {
+		struct per_cpu_pageset *pset;
+		int cpu;
+		
+		if (!zone->present_pages)
+			continue;
+		
+		for (cpu = 0; cpu < NR_CPUS; cpu++) {
+			if (!cpu_possible(cpu))
+				continue;
+
+			pset = &zone->pageset[cpu];
+
+			for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
+				struct per_cpu_pages *pcp;
+
+				pcp = &pset->pcp[i];
+				result += pcp->count;
+			}
+		}
+	}
+	return result;
+}
+
+int real_nr_free_pages(void)
+{
+	return nr_free_pages() + num_pcp_pages();
+}
+
+/* generate_free_page_map
+ *
+ * Description:	This routine generates a bitmap of free pages from the
+ * 		lists used by the memory manager. We then use the bitmap
+ * 		to quickly calculate which pages to save and in which
+ * 		pagesets.
+ */
+static void generate_free_page_map(void) 
+{
+	int i, order, loop, cpu;
+	struct page * page;
+	unsigned long flags;
+	struct zone *zone;
+	struct per_cpu_pageset *pset;
+
+	for(i=0; i < max_mapnr; i++)
+		SetPageInUse(pfn_to_page(i));
+	
+	for_each_zone(zone) {
+		if (!zone->present_pages)
+			continue;
+		spin_lock_irqsave(&zone->lock, flags);
+		for (order = MAX_ORDER - 1; order >= 0; --order) {
+			list_for_each_entry(page, &zone->free_area[order].free_list, lru)
+				for(loop=0; loop < (1 << order); loop++) {
+					ClearPageInUse(page+loop);
+					ClearPagePageset2(page+loop);
+				}
+		}
+
+		
+		for (cpu = 0; cpu < NR_CPUS; cpu++) {
+			if (!cpu_possible(cpu))
+				continue;
+
+			pset = &zone->pageset[cpu];
+
+			for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
+				struct per_cpu_pages *pcp;
+				struct page * page;
+
+				pcp = &pset->pcp[i];
+				list_for_each_entry(page, &pcp->list, lru) {
+					ClearPageInUse(page);
+					ClearPagePageset2(page);
+				}
+			}
+		}
+		
+		spin_unlock_irqrestore(&zone->lock, flags);
+	}
+}
+
+/* size_of_free_region
+ * 
+ * Description:	Return the number of pages that are free, beginning with and 
+ * 		including this one.
+ */
+static int size_of_free_region(struct page * page)
+{
+	struct page * posn = page;
+
+	while (((page_to_pfn(posn)) < max_mapnr) && (!PageInUse(posn))) 
+		posn++;
+	return (posn - page);
+}
+
+/* count_data_pages
+ *
+ * This routine generates our lists of pages to be stored in each
+ * pageset. Since we store the data using extents, and adding new
+ * extents might allocate a new extent page, this routine may well
+ * be called more than once.
+ */
+static struct pageset_sizes_result count_data_pages(void)
+{
+	int chunk_size, loop, numfree = 0;
+	int usepagedir2;
+	struct pageset_sizes_result result;
+
+	result.size1 = 0;
+	result.size1low = 0;
+	result.size2 = 0;
+	result.size2low = 0;
+
+	numnosave = 0;
+
+	clear_dyn_pageflags(pageset1_map);
+	clear_dyn_pageflags(pageset1_copy_map);
+
+	generate_free_page_map();
+
+	if (TEST_RESULT_STATE(SUSPEND_ABORTED))
+		return result;
+
+	if (max_mapnr != num_physpages) {
+		abort_suspend("Max_mapnr is not equal to num_physpages.");
+		return result;
+	}
+		
+	/*
+	 * Pages not to be saved are marked Nosave irrespective of being reserved
+	 */
+	for (loop = 0; loop < max_mapnr; loop++) {
+		struct page * page = pfn_to_page(loop);
+		if (PageNosave(page)) {
+			numnosave++;
+			continue;
+		}
+
+		if (!PageReserved(page)) {
+			if ((chunk_size=size_of_free_region(page))!=0) {
+				numfree += chunk_size;
+				loop += chunk_size - 1;
+				continue;
+			}
+		} else {
+			if (PageHighMem(page)) {
+				/* HighMem pages may be marked Reserved. We ignore them. */
+				numnosave++;
+				continue;
+			}
+		};
+
+		usepagedir2 = PagePageset2(page);
+
+		if (usepagedir2) {
+			result.size2++;
+			if (!PageHighMem(page))
+				result.size2low++;
+			SetPagePageset1Copy(page);
+		} else {
+			result.size1++;
+			SetPagePageset1(page);
+			if (!PageHighMem(page))
+				result.size1low++;
+		}
+	}
+	
+	suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_MEDIUM, 0,
+		"Count data pages: Set1 (%d) + Set2 (%d) + Nosave (%d) + NumFree (%d) = %d.\n",
+		result.size1, result.size2, numnosave, numfree,
+		result.size1 + result.size2 + numnosave + numfree);
+	BITMAP_FOR_EACH_SET(allocd_pages_map, loop)
+		SetPagePageset1Copy(pfn_to_page(loop));
+	return result;
+}
+
+/* amount_needed
+ *
+ * Calculates the amount by which the image size needs to be reduced to meet
+ * our constraints.
+ */
+static int amount_needed(int use_image_size_limit)
+{
+
+	int max1 = max( (int) (RAM_TO_SUSPEND - real_nr_free_pages() - 
+			  nr_free_highpages()),
+			((int) (STORAGE_NEEDED(1) -  
+			  storage_available)));
+	if (use_image_size_limit)
+		return max( max1,
+			    (image_size_limit > 0) ? 
+			    ((int) (STORAGE_NEEDED(1) - (image_size_limit << 8))) : 0);
+	return max1;
+}
+
+/* display_stats
+ *
+ * Display the vital statistics.of the image.
+ */
+#ifdef CONFIG_PM_DEBUG
+static void display_stats(void)
+{ 
+	storage_allocated = active_writer->ops.writer.storage_allocated();
+	suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_MEDIUM, 1,
+		"Free:%d(%d). Sets:%d(%d),%d(%d). Nosave:%d-%d=%d. Storage:%d/%d+%d=%d(%lu). Needed:%d|%d|%d.\n", 
+		
+		/* Free */
+		real_nr_free_pages(),
+		real_nr_free_pages() - nr_free_highpages(),
+		
+		/* Sets */
+		pageset1_size, pageset1_sizelow,
+		pageset2_size, pageset2_sizelow,
+
+		/* Nosave */
+		numnosave, extra_pagedir_pages_allocated,
+		numnosave - extra_pagedir_pages_allocated,
+
+		/* Storage */
+		storage_allocated,
+		MAIN_STORAGE_NEEDED(1), HEADER_STORAGE_NEEDED,
+		STORAGE_NEEDED(1),
+		storage_available,
+
+		/* Needed */
+		RAM_TO_SUSPEND - real_nr_free_pages() - nr_free_highpages(),
+		STORAGE_NEEDED(1) - storage_available, 
+		(image_size_limit > 0) ? (STORAGE_NEEDED(1) - (image_size_limit << 8)) : 0);
+}
+#else
+#define display_stats() do { } while(0)
+#endif
+
+/* suspend2_recalculate_stats
+ *
+ * Eaten is the number of pages which have been eaten.
+ * Pagedirincluded is the number of pages which have been allocated for the pagedir.
+ */
+struct pageset_sizes_result suspend2_recalculate_stats(void) 
+{
+	struct pageset_sizes_result result;
+
+	suspend2_mark_pages_for_pageset2();  /* Need to call this before getting pageset1_size! */
+	result = count_data_pages();
+	pageset1_sizelow = result.size1low;
+	pageset2_sizelow = result.size2low;
+	pagedir1.lastpageset_size = pageset1_size = result.size1;
+	pagedir2.lastpageset_size = pageset2_size = result.size2;
+	storage_available = active_writer->ops.writer.storage_available();
+	return result;
+}
+
+/* update_image
+ *
+ * Allocate [more] memory and storage for the image.
+ */
+static int update_image(void) 
+{ 
+	struct pageset_sizes_result result;
+	int result2, param_used;
+
+	result = suspend2_recalculate_stats();
+
+	/* Include allowance for growth in pagedir1 while writing pagedir 2 */
+	if (suspend2_allocate_extra_pagedir_memory(&pagedir1,
+				pageset1_size + EXTRA_PD1_PAGES_ALLOWANCE,
+				pageset2_sizelow)) {
+		suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
+			"Still need to get more pages for pagedir 1.\n");
+		return 1;
+	}
+
+	thaw_processes(FREEZER_KERNEL_THREADS);
+
+	param_used = MAIN_STORAGE_NEEDED(1);
+	if ((result2 = active_writer->ops.writer.allocate_storage(param_used))) {
+		suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
+			"Still need to get more storage space for the image proper.\n");
+		storage_allocated = active_writer->ops.writer.storage_allocated();
+		freeze_processes(1);
+		return 1;
+	}
+
+	param_used = HEADER_STORAGE_NEEDED;
+	if ((result2 = active_writer->ops.writer.allocate_header_space(HEADER_STORAGE_NEEDED))) {
+		suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
+			"Still need to get more storage space for header.\n");
+		freeze_processes(1);
+		storage_allocated = active_writer->ops.writer.storage_allocated();
+		return 1;
+	}
+
+	header_space_allocated = HEADER_STORAGE_NEEDED;
+
+	/* 
+	 * Allocate remaining storage space, if possible, up to the
+	 * maximum we know we'll need. It's okay to allocate the
+	 * maximum if the writer is the swapwriter, but
+	 * we don't want to grab all available space on an NFS share.
+	 * We therefore ignore the expected compression ratio here,
+	 * thereby trying to allocate the maximum image size we could
+	 * need (assuming compression doesn't expand the image), but
+	 * don't complain if we can't get the full amount we're after.
+	 */
+
+	active_writer->ops.writer.allocate_storage(
+		min(storage_available,
+		    MAIN_STORAGE_NEEDED(0) + 100));
+
+	storage_allocated = active_writer->ops.writer.storage_allocated();
+
+	freeze_processes(1);
+
+	suspend2_recalculate_stats();
+	display_stats();
+
+	suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
+		"Amount still needed (%d) > 0:%d. Header: %d < %d: %d,"
+		" Storage allocd: %d < %d + %d: %d.\n",
+			amount_needed(0),
+			(amount_needed(0) > 0),
+			header_space_allocated, HEADER_STORAGE_NEEDED,
+			header_space_allocated < HEADER_STORAGE_NEEDED,
+		 	storage_allocated,
+			HEADER_STORAGE_NEEDED, MAIN_STORAGE_NEEDED(1),
+			storage_allocated <
+			(HEADER_STORAGE_NEEDED + MAIN_STORAGE_NEEDED(1)));
+
+	check_shift_keys(0, NULL);
+
+	return ((amount_needed(0) > 0) ||
+		header_space_allocated < HEADER_STORAGE_NEEDED ||
+		 storage_allocated < 
+		 (HEADER_STORAGE_NEEDED + MAIN_STORAGE_NEEDED(1)));
+}
+
+/* --------------------------------------------------------------------------- */
+
+/* attempt_to_freeze
+ * 
+ * Try to freeze processes.
+ */
+
+static int attempt_to_freeze(void)
+{
+	int result;
+	
+	/* Stop processes before checking again */
+	thaw_processes(FREEZER_ALL_THREADS);
+	suspend2_prepare_status(1, 1, "Freezing processes");
+	result = freeze_processes(0);
+
+	if (result) {
+		SET_RESULT_STATE(SUSPEND_ABORTED);
+		SET_RESULT_STATE(SUSPEND_FREEZING_FAILED);
+	} else
+		arefrozen = 1;
+
+	return result;
+}
+
+/* eat_memory
+ *
+ * Try to free some memory, either to meet hard or soft constraints on the image
+ * characteristics.
+ * 
+ * Hard constraints:
+ * - Pageset1 must be < half of memory;
+ * - We must have enough memory free at resume time to have pageset1
+ *   be able to be loaded in pages that don't conflict with where it has to
+ *   be restored.
+ * Soft constraints
+ * - User specificied image size limit.
+ */
+static int eat_memory(void)
+{
+	int orig_memory_still_to_eat, last_amount_needed = 0, times_criteria_met = 0;
+	int free_flags = 0, did_eat_memory = 0;
+	
+	/*
+	 * Note that if we have enough storage space and enough free memory, we may
+	 * exit without eating anything. We give up when the last 10 iterations ate
+	 * no extra pages because we're not going to get much more anyway, but
+	 * the few pages we get will take a lot of time.
+	 *
+	 * We freeze processes before beginning, and then unfreeze them if we
+	 * need to eat memory until we think we have enough. If our attempts
+	 * to freeze fail, we give up and abort.
+	 */
+
+	/* ----------- Stage 1: Freeze Processes ------------- */
+
+	
+	suspend2_recalculate_stats();
+	display_stats();
+
+	orig_memory_still_to_eat = amount_needed(1);
+	last_amount_needed = orig_memory_still_to_eat;
+
+	switch (image_size_limit) {
+		case -1: /* Don't eat any memory */
+			if (orig_memory_still_to_eat) {
+				SET_RESULT_STATE(SUSPEND_ABORTED);
+				SET_RESULT_STATE(SUSPEND_WOULD_EAT_MEMORY);
+			}
+			break;
+		case -2:  /* Free caches only */
+			free_flags = GFP_NOIO | __GFP_HIGHMEM;
+			break;
+		default:
+			free_flags = GFP_ATOMIC | __GFP_HIGHMEM;
+	}
+		
+	/* ----------- Stage 2: Eat memory ------------- */
+
+	while (((!EATEN_ENOUGH_MEMORY()) || (image_size_limit == -2)) && 
+		(!TEST_RESULT_STATE(SUSPEND_ABORTED)) && 
+		(times_criteria_met < 10)) {
+		int amount_freed;
+		int amount_wanted = orig_memory_still_to_eat - amount_needed(1);
+
+		suspend2_prepare_status(0, 1, "Seeking to free %dMB of memory.", MB(amount_needed(1)));
+
+		if (amount_wanted < 1)
+			amount_wanted = 1; /* image_size_limit == -2 */
+
+		if (orig_memory_still_to_eat)
+			suspend2_update_status(orig_memory_still_to_eat - amount_needed(1),
+				orig_memory_still_to_eat,
+				" Image size %d ",
+				MB(STORAGE_NEEDED(1)));
+		else
+			suspend2_update_status(0, 1, "Image size %d ", MB(STORAGE_NEEDED(1)));
+		
+		if ((last_amount_needed - amount_needed(1)) < 10)
+			times_criteria_met++;
+		else
+			times_criteria_met = 0;
+		last_amount_needed = amount_needed(1);
+		amount_freed = shrink_all_memory(last_amount_needed);
+		suspend2_recalculate_stats();
+		display_stats();
+
+		did_eat_memory = 1;
+
+		check_shift_keys(0, NULL);
+	}
+
+	if (did_eat_memory) {
+		unsigned long orig_state = get_suspend_state();
+		thaw_processes(FREEZER_KERNEL_THREADS);
+		/* Freeze_processes will call sys_sync too */
+		freeze_processes(1);
+		restore_suspend_state(orig_state);
+		suspend2_recalculate_stats();
+		display_stats();
+	}
+
+	/* Blank out image size display */
+	suspend2_update_status(100, 100, NULL);
+
+	if (!TEST_RESULT_STATE(SUSPEND_ABORTED)) {
+		/* Include image size limit when checking what to report */
+		if (amount_needed(1) > 0) 
+			SET_RESULT_STATE(SUSPEND_UNABLE_TO_FREE_ENOUGH_MEMORY);
+
+		/* But don't include it when deciding whether to abort (soft limit) */
+		if ((amount_needed(0) > 0)) {
+			printk("Unable to free sufficient memory to suspend. Still need %d pages.\n",
+				amount_needed(1));
+			SET_RESULT_STATE(SUSPEND_ABORTED);
+		}
+		
+		check_shift_keys(1, "Memory eating completed.");
+	}
+
+	return 0;
+}
+
+/* prepare_image
+ *
+ * Entry point to the whole image preparation section.
+ *
+ * We do four things:
+ * - Freeze processes;
+ * - Ensure image size constraints are met;
+ * - Complete all the preparation for saving the image,
+ *   including allocation of storage. The only memory
+ *   that should be needed when we're finished is that
+ *   for actually storing the image (and we know how
+ *   much is needed for that because the plugins tell
+ *   us).
+ * - Make sure that all dirty buffers are written out.
+ */
+
+#define MAX_TRIES 4
+int suspend2_prepare_image(void)
+{
+	int result = 1, sizesought, tries = 0;
+
+	arefrozen = 0;
+
+	header_space_allocated = 0;
+
+	sizesought = 100 + memory_for_plugins();
+
+	if (attempt_to_freeze())
+		return 0;
+
+	storage_available = active_writer->ops.writer.storage_available();
+
+	if (!storage_available) {
+		printk(KERN_ERR "You need some storage available to be able to suspend.\n");
+		SET_RESULT_STATE(SUSPEND_ABORTED);
+		SET_RESULT_STATE(SUSPEND_NOSTORAGE_AVAILABLE);
+		return 0;
+	}
+
+	do {
+		suspend2_prepare_status(0, 1, "Preparing Image.");
+	
+		if (eat_memory() || TEST_RESULT_STATE(SUSPEND_ABORTED))
+			break;
+
+		result = update_image();
+
+		check_shift_keys(0, NULL);
+		
+		tries++;
+
+	} while ((result) && (tries < MAX_TRIES) && (!TEST_RESULT_STATE(SUSPEND_ABORTED)) &&
+		(!TEST_RESULT_STATE(SUSPEND_UNABLE_TO_FREE_ENOUGH_MEMORY)));
+
+	if (tries == MAX_TRIES)
+		abort_suspend("Unable to get sufficient storage for the image.\n");
+
+	check_shift_keys(1, "Image preparation complete.");
+
+	return !result;
+}
kernel/power/suspend2_core/prepare_image.h +44 -0

44 lines not on this page · raw message

#126 lore raw

Re: [PATCH] [39/48] Suspend2 2.1.9.8 for 2.6.12: 615-poweroff.patch

Hi!

Quoted 11 lines
kernel/power/suspend2_core/prepare_image.c +10 -0
@@ -0,0 +1,585 @@
+/*
+ * kernel/power/prepare_image.c
+ *
+ * Copyright (C) 2003-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * We need to eat memory until we can:
+ * 1. Perform the save without changing anything (RAM_NEEDED < max_mapnr)
+ * 2. Fit it all in available space (active_writer->available_space() >= STORAGE_NEEDED)

kernel/power/suspend2_core/prepare_image.c line 20

Quoted 10 lines
kernel/power/suspend2_core/prepare_image.c +10 -0
+ * 3. Reload the pagedir and pageset1 to places that don't collide with their
+ *    final destinations, not knowing to what extent the resumed kernel will
+ *    overlap with the one loaded at boot time. I think the resumed kernel should overlap
+ *    completely, but I don't want to rely on this as it is an unproven assumption. We
+ *    therefore assume there will be no overlap at all (worse case).
+ * 4. Meet the user's requested limit (if any) on the size of the image.
+ *    The limit is in MB, so pages/256 (assuming 4K pages).
+ *
+ *    (Final test in save_image doesn't use EATEN_ENOUGH_MEMORY)
+ */

Can you just fix/use shrink_all_memory().

kernel/power/suspend2_core/prepare_image.c line 33

Quoted 1 line
kernel/power/suspend2_core/prepare_image.c +1 -0
+#define EATEN_ENOUGH_MEMORY() (amount_needed(1) < 1)

Hmm...

kernel/power/suspend2_core/prepare_image.c line 34

Quoted 1 line
kernel/power/suspend2_core/prepare_image.c +1 -0
+static int arefrozen = 0, numnosave = 0;

Missing _s.

Quoted 27 lines
kernel/power/suspend2_core/prepare_image.c +27 -0
+/* display_stats
+ *
+ * Display the vital statistics.of the image.
+ */
+#ifdef CONFIG_PM_DEBUG
+static void display_stats(void)
+{ 
+	storage_allocated = active_writer->ops.writer.storage_allocated();
+	suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_MEDIUM, 1,
+		"Free:%d(%d). Sets:%d(%d),%d(%d). Nosave:%d-%d=%d. Storage:%d/%d+%d=%d(%lu). Needed:%d|%d|%d.\n", 
+		
+		/* Free */
+		real_nr_free_pages(),
+		real_nr_free_pages() - nr_free_highpages(),
+		
+		/* Sets */
+		pageset1_size, pageset1_sizelow,
+		pageset2_size, pageset2_sizelow,
+
+		/* Nosave */
+		numnosave, extra_pagedir_pages_allocated,
+		numnosave - extra_pagedir_pages_allocated,
+
+		/* Storage */
+		storage_allocated,
+		MAIN_STORAGE_NEEDED(1), HEADER_STORAGE_NEEDED,
+		STORAGE_NEEDED(1),

kernel/power/suspend2_core/prepare_image.c line 277

Quoted 10 lines
kernel/power/suspend2_core/prepare_image.c +10 -0
+		storage_available,
+
+		/* Needed */
+		RAM_TO_SUSPEND - real_nr_free_pages() - nr_free_highpages(),
+		STORAGE_NEEDED(1) - storage_available, 
+		(image_size_limit > 0) ? (STORAGE_NEEDED(1) - (image_size_limit << 8)) : 0);
+}
+#else
+#define display_stats() do { } while(0)
+#endif

Is this kind of debugging neccessary any more?

Quoted 15 lines
kernel/power/suspend2_core/prepare_image.h +15 -0
+#define MIN_FREE_RAM (max_low_pfn >> 7)
+
+#define EXTRA_PD1_PAGES_ALLOWANCE 100
+
+#define MAIN_STORAGE_NEEDED(USE_ECR) \
+	((pageset1_size + pageset2_size + 100 + \
+	  EXTRA_PD1_PAGES_ALLOWANCE) * \
+	 (USE_ECR ? expected_compression_ratio() : 100) / 100)
+
+#define HEADER_BYTES_NEEDED \
+	((extents_allocated * 2 * sizeof(unsigned long)) + \
+	 sizeof(struct suspend_header) + \
+	 sizeof(struct plugin_header) + \
+	 (int) header_storage_for_plugins() + \
+	 (PAGES_PER_BITMAP << PAGE_SHIFT) + \

kernel/power/suspend2_core/prepare_image.h line 43

Quoted 10 lines
kernel/power/suspend2_core/prepare_image.h +10 -0
+	 num_plugins * \
+	 	(sizeof(struct plugin_header) + sizeof(int)))
+	
+#define HEADER_STORAGE_NEEDED ((int) ((HEADER_BYTES_NEEDED + (int) PAGE_SIZE - 1) >> PAGE_SHIFT))
+
+#define STORAGE_NEEDED(USE_ECR) \
+	(MAIN_STORAGE_NEEDED(USE_ECR) + HEADER_STORAGE_NEEDED)
+
+#define RAM_TO_SUSPEND (1 + max((pageset1_size + EXTRA_PD1_PAGES_ALLOWANCE - pageset2_sizelow), 0) + \
+		MIN_FREE_RAM + memory_for_plugins())

Can we convert this to inline functions or something?

Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#127 lore raw

Re: [PATCH] [39/48] Suspend2 2.1.9.8 for 2.6.12: 615-poweroff.patch

Hi.

Quoted 17 lines · Pavel Machek

Hi!

Quoted 15 lines
kernel/power/suspend2_core/prepare_image.c +14 -0
@@ -0,0 +1,585 @@
+/*
+ * kernel/power/prepare_image.c
+ *
+ * Copyright (C) 2003-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * We need to eat memory until we can:
+ * 1. Perform the save without changing anything (RAM_NEEDED < max_mapnr)
+ * 2. Fit it all in available space (active_writer->available_space() >= STORAGE_NEEDED)
+ * 3. Reload the pagedir and pageset1 to places that don't collide with their
+ *    final destinations, not knowing to what extent the resumed kernel will
+ *    overlap with the one loaded at boot time. I think the resumed kernel should overlap
+ *    completely, but I don't want to rely on this as it is an unproven assumption. We
Quoted 8 lines

kernel/power/suspend2_core/prepare_image.c line 20

Quoted 6 lines
kernel/power/suspend2_core/prepare_image.c +6 -0
+ *    therefore assume there will be no overlap at all (worse case).
+ * 4. Meet the user's requested limit (if any) on the size of the image.
+ *    The limit is in MB, so pages/256 (assuming 4K pages).
+ *
+ *    (Final test in save_image doesn't use EATEN_ENOUGH_MEMORY)
+ */

Can you just fix/use shrink_all_memory().

We are using shrink_all_memory now. We just try to be intelligent about how much memory gets freed. Most of the time, very little needs to be released in order to suspend, and you get a more responsive system than if you free all and sundry and then have to swap it back in post-resume. If the use really wants to emulate swsusp and free everything they can, they can just set the imagesize limit to 1MB. (It's a soft limit).

Quoted 7 lines

kernel/power/suspend2_core/prepare_image.c line 33

Quoted 1 line
kernel/power/suspend2_core/prepare_image.c +1 -0
+#define EATEN_ENOUGH_MEMORY() (amount_needed(1) < 1)

Hmm...

kernel/power/suspend2_core/prepare_image.c line 34

Quoted 1 line
kernel/power/suspend2_core/prepare_image.c +1 -0
+static int arefrozen = 0, numnosave = 0;

Missing _s.

Fixed. Thanks.

Quoted 31 lines
Quoted 31 lines
kernel/power/suspend2_core/prepare_image.c +31 -0
+/* display_stats
+ *
+ * Display the vital statistics.of the image.
+ */
+#ifdef CONFIG_PM_DEBUG
+static void display_stats(void)
+{ 
+	storage_allocated = active_writer->ops.writer.storage_allocated();
+	suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_MEDIUM, 1,
+		"Free:%d(%d). Sets:%d(%d),%d(%d). Nosave:%d-%d=%d. Storage:%d/%d+%d=%d(%lu). Needed:%d|%d|%d.\n", 
+		
+		/* Free */
+		real_nr_free_pages(),
+		real_nr_free_pages() - nr_free_highpages(),
+		
+		/* Sets */
+		pageset1_size, pageset1_sizelow,
+		pageset2_size, pageset2_sizelow,
+
+		/* Nosave */
+		numnosave, extra_pagedir_pages_allocated,
+		numnosave - extra_pagedir_pages_allocated,
+
+		/* Storage */
+		storage_allocated,
+		MAIN_STORAGE_NEEDED(1), HEADER_STORAGE_NEEDED,
+		STORAGE_NEEDED(1),
+		storage_available,
+
+		/* Needed */
+		RAM_TO_SUSPEND - real_nr_free_pages() - nr_free_highpages(),
Quoted 8 lines

kernel/power/suspend2_core/prepare_image.c line 277

Quoted 6 lines
kernel/power/suspend2_core/prepare_image.c +6 -0
+		STORAGE_NEEDED(1) - storage_available, 
+		(image_size_limit > 0) ? (STORAGE_NEEDED(1) - (image_size_limit << 8)) : 0);
+}
+#else
+#define display_stats() do { } while(0)
+#endif

Is this kind of debugging neccessary any more?

Not very often. Removed. I can re-add when necessary.

Quoted 19 lines
Quoted 19 lines
kernel/power/suspend2_core/prepare_image.h +19 -0
+#define MIN_FREE_RAM (max_low_pfn >> 7)
+
+#define EXTRA_PD1_PAGES_ALLOWANCE 100
+
+#define MAIN_STORAGE_NEEDED(USE_ECR) \
+	((pageset1_size + pageset2_size + 100 + \
+	  EXTRA_PD1_PAGES_ALLOWANCE) * \
+	 (USE_ECR ? expected_compression_ratio() : 100) / 100)
+
+#define HEADER_BYTES_NEEDED \
+	((extents_allocated * 2 * sizeof(unsigned long)) + \
+	 sizeof(struct suspend_header) + \
+	 sizeof(struct plugin_header) + \
+	 (int) header_storage_for_plugins() + \
+	 (PAGES_PER_BITMAP << PAGE_SHIFT) + \
+	 num_plugins * \
+	 	(sizeof(struct plugin_header) + sizeof(int)))
+	
+#define HEADER_STORAGE_NEEDED ((int) ((HEADER_BYTES_NEEDED + (int) PAGE_SIZE - 1) >> PAGE_SHIFT))
Quoted 8 lines

kernel/power/suspend2_core/prepare_image.h line 43

Quoted 6 lines
kernel/power/suspend2_core/prepare_image.h +6 -0
+
+#define STORAGE_NEEDED(USE_ECR) \
+	(MAIN_STORAGE_NEEDED(USE_ECR) + HEADER_STORAGE_NEEDED)
+
+#define RAM_TO_SUSPEND (1 + max((pageset1_size + EXTRA_PD1_PAGES_ALLOWANCE - pageset2_sizelow), 0) + \
+		MIN_FREE_RAM + memory_for_plugins())

Can we convert this to inline functions or something?

Done.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 
#128 lore raw

PATCH 40/48 Suspend2 2.1.9.8 for 2.6.12: 616-prepare_image.patch

In reply to Nigel Cunningham
kernel/power/suspend2_core/proc.c +336 -0
diff -ruNp 617-proc.patch-old/kernel/power/suspend2_core/proc.c 617-proc.patch-new/kernel/power/suspend2_core/proc.c
@@ -0,0 +1,336 @@
+/*
+ * /kernel/power/proc.c
+ *
+ * Copyright (C) 2002-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * This file contains support for proc entries for tuning Software Suspend.
+ *
+ * We have a generic handler that deals with the most common cases, and
+ * hooks for special handlers to use.
+ *
+ * Versions:
+ * 1: /proc/sys/kernel/suspend the only tuning interface
+ * 2: Initial version of this file
+ * 3: Removed kernel debugger parameter.
+ *    Added checkpage parameter (for checking checksum of a page over time).
+ * 4: Added entry for maximum granularity in splash screen progress bar.
+ *    (Progress bar is slow, but the right setting will vary with disk &
+ *    processor speed and the user's tastes).
+ * 5: Added enable_escape to control ability to cancel aborting by pressing
+ *    ESC key.
+ * 6: Removed checksumming and checkpage parameter. Made all debugging proc
+ *    entries dependant upon debugging being compiled in.
+ *    Meaning of some flags also changed in this version.
+ * 7: Added header_locations entry to simplify getting the resume= parameter for
+ *    swapfiles easy and swapfile entry for automatically doing swapon/off from
+ *    swapfiles as well as partitions.
+ * 8: Added option for marking process pages as pageset 2 (processes_pageset2).
+ * 9: Added option for keep image mode.
+ *    Enumeration patch from Michael Frank applied.
+ * 10: Various corrections to when options are disabled/enabled;
+ *     Added option for specifying expected compression.
+ * 11: Added option for freezer testing. Debug only.
+ * 12: Removed test entries no_async_[read|write], processes_pageset2 and
+ *     NoPageset2.
+ * 13: Make default_console_level available when debugging disabled, but limited
+ *     to 0 or 1.
+ * 14: Rewrite to allow for dynamic registration of proc entries and smooth the
+ *     transition to kobjects in 2.6.
+ * 15: Add setting resume2 parameter without rebooting (still need to run lilo
+ *     though!). Add support for generic string handling and switch resume2 to use
+ *     it.
+ * 16: Switched to cryptoapi, adding entries for selecting encryptor and compressor.
+ */
+
+#define SUSPEND_PROC_C
+
+static int suspend_proc_version = 16;
+static int suspend_proc_initialised = 0;
+
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+#include "proc.h"
+#include "suspend.h"
+
+static struct list_head suspend_proc_entries;
+static struct proc_dir_entry *suspend_dir;
+static struct suspend_proc_data proc_params[];
+
+extern void __suspend2_try_resume(void);
+extern void __suspend2_try_suspend(void);
+
+/* suspend2_read_proc
+ *
+ * Generic handling for reading the contents of bits, integers,
+ * unsigned longs and strings.
+ */
+static int suspend2_read_proc(char * page, char ** start, off_t off, int count,
+		int *eof, void *data)
+{
+	int len = 0;
+	struct suspend_proc_data * proc_data = (struct suspend_proc_data *) data;
+
+	if (suspend_start_anything(0))
+		return -EBUSY;
+	
+	switch (proc_data->type) {
+		case SUSPEND_PROC_DATA_CUSTOM:
+			if (proc_data->data.special.read_proc) {
+				read_proc_t * read_proc = proc_data->data.special.read_proc;
+				len = read_proc(page, start, off, count, eof, data);
+			} else
+				len = 0;
+			break;
+		case SUSPEND_PROC_DATA_BIT:
+			len = sprintf(page, "%d\n", 
+				-test_bit(proc_data->data.bit.bit,
+					proc_data->data.bit.bit_vector));
+			break;
+		case SUSPEND_PROC_DATA_INTEGER:
+			{
+				int * variable = proc_data->data.integer.variable;
+				len = sprintf(page, "%d\n", *variable);
+				break;
+			}
+		case SUSPEND_PROC_DATA_UL:
+			{
+				long * variable = proc_data->data.ul.variable;
+				len = sprintf(page, "%lu\n", *variable);
+				break;
+			}
+		case SUSPEND_PROC_DATA_STRING:
+			{
+				char * variable = proc_data->data.string.variable;
+				len = sprintf(page, "%s\n", variable);
+				break;
+			}
+	}
+	/* Side effect routine? */
+	if (proc_data->read_proc)
+		proc_data->read_proc();
+	if ((proc_data->type != SUSPEND_PROC_DATA_CUSTOM) || (!proc_data->data.special.read_proc))
+		*eof = 1;
+	
+	suspend_finish_anything(0);
+	
+	return len;
+}
+/* suspend2_write_proc
+ *
+ * Generic routine for handling writing to files representing
+ * bits, integers and unsigned longs.
+ */
+
+static int suspend2_write_proc(struct file *file, const char * buffer,
+		unsigned long count, void * data)
+{
+	struct suspend_proc_data * proc_data = (struct suspend_proc_data *) data;
+	char * my_buf = (char *) get_zeroed_page(GFP_ATOMIC);
+	int result = count, assigned_temp_buffer = 0;
+
+	if (!my_buf)
+		return -ENOMEM;
+
+	if (count > PAGE_SIZE)
+		count = PAGE_SIZE;
+
+	if (copy_from_user(my_buf, buffer, count))
+		return -EFAULT;
+	
+	if (suspend_start_anything(proc_data == &proc_params[0]))
+		return -EBUSY;
+
+	my_buf[count] = 0;
+
+	switch (proc_data->type) {
+		case SUSPEND_PROC_DATA_CUSTOM:
+			if (proc_data->data.special.write_proc) {
+				write_proc_t * write_proc = proc_data->data.special.write_proc;
+				result = write_proc(file, buffer, count, data);
+			}
+			break;
+		case SUSPEND_PROC_DATA_BIT:
+			{
+			int value = simple_strtoul(my_buf, NULL, 0);
+			if (value)
+				set_bit(proc_data->data.bit.bit, 
+					(proc_data->data.bit.bit_vector));
+			else
+				clear_bit(proc_data->data.bit.bit,
+					(proc_data->data.bit.bit_vector));
+			}
+			break;
+		case SUSPEND_PROC_DATA_INTEGER:
+			{
+				int * variable = proc_data->data.integer.variable;
+				int minimum = proc_data->data.integer.minimum;
+				int maximum = proc_data->data.integer.maximum;
+				*variable = simple_strtol(my_buf, NULL, 0);
+				if (((*variable) < minimum))
+					*variable = minimum;
+
+				if (((*variable) > maximum))
+					*variable = maximum;
+				break;
+			}
+		case SUSPEND_PROC_DATA_UL:
+			{
+				unsigned long * variable = proc_data->data.ul.variable;
+				unsigned long minimum = proc_data->data.ul.minimum;
+				unsigned long maximum = proc_data->data.ul.maximum;
+				*variable = simple_strtoul(my_buf, NULL, 0);
+				
+				if (minimum && ((*variable) < minimum))
+					*variable = minimum;
+
+				if (maximum && ((*variable) > maximum))
+					*variable = maximum;
+				break;
+			}
+			break;
+		case SUSPEND_PROC_DATA_STRING:
+			{
+				int copy_len = count;
+				char * variable =
+					proc_data->data.string.variable;
+
+				if (proc_data->data.string.max_length &&
+				    (copy_len > proc_data->data.string.max_length))
+					copy_len = proc_data->data.string.max_length;
+
+				if (!variable) {
+					proc_data->data.string.variable =
+						variable = (char *) get_zeroed_page(GFP_ATOMIC);
+					assigned_temp_buffer = 1;
+				}
+				strncpy(variable, my_buf, copy_len);
+				if ((copy_len) &&
+					 (my_buf[copy_len - 1] == '\n'))
+					variable[count - 1] = 0;
+				variable[count] = 0;
+			}
+			break;
+	}
+	free_pages((unsigned long) my_buf, 0);
+	/* Side effect routine? */
+	if (proc_data->write_proc)
+		proc_data->write_proc();
+
+	/* Free temporary buffers */
+	if (assigned_temp_buffer) {
+		free_pages((unsigned long) proc_data->data.string.variable, 0);
+		proc_data->data.string.variable = NULL;
+	}
+
+	suspend_finish_anything(proc_data == &proc_params[0]);
+	
+	return result;
+}
+
+/* Non-plugin proc entries.
+ *
+ * This array contains entries that are automatically registered at
+ * boot. Plugins and the console code register their own entries separately.
+ *
+ * NB: If you move do_suspend, change suspend2_write_proc's test so that
+ * suspend_start_anything still gets a 1 when the user echos > do_suspend!
+ */
+
+static struct suspend_proc_data proc_params[] = {
+	{ .filename			= "do_suspend",
+	  .permissions			= PROC_WRITEONLY,
+	  .type				= SUSPEND_PROC_DATA_CUSTOM,
+	  .write_proc			= __suspend2_try_suspend,
+	},
+
+	{ .filename			= "do_resume",
+	  .permissions			= PROC_WRITEONLY,
+	  .type				= SUSPEND_PROC_DATA_CUSTOM,
+	  .write_proc			= __suspend2_try_resume,
+	},
+
+
+	{ .filename			= "interface_version",
+	  .permissions			= PROC_READONLY,
+	  .type				= SUSPEND_PROC_DATA_INTEGER,
+	  .data = {
+		  .integer = {
+			  .variable	= &suspend_proc_version,
+		  }
+	  }
+	},
+};
+
+/* suspend_initialise_proc
+ *
+ * Initialise the /proc/software_suspend directory.
+ */
+
+static void suspend_initialise_proc(void)
+{
+	int i;
+	int numfiles = sizeof(proc_params) / sizeof(struct suspend_proc_data);
+	
+	if (suspend_proc_initialised)
+		return;
+
+	suspend_dir = proc_mkdir("software_suspend", NULL);
+	
+	BUG_ON(!suspend_dir);
+
+	INIT_LIST_HEAD(&suspend_proc_entries);
+
+	suspend_proc_initialised = 1;
+
+	for (i=0; i< numfiles; i++)
+		suspend_register_procfile(&proc_params[i]);
+}
+
+/* suspend_register_procfile
+ *
+ * Helper for registering a new /proc/software_suspend entry.
+ */
+
+struct proc_dir_entry * suspend_register_procfile(
+		struct suspend_proc_data * suspend_proc_data)
+{
+	struct proc_dir_entry * new_entry;
+	
+	if (!suspend_proc_initialised)
+		suspend_initialise_proc();
+
+	new_entry = create_proc_entry(
+			suspend_proc_data->filename,
+			suspend_proc_data->permissions, 
+			suspend_dir);
+	if (new_entry) {
+		list_add_tail(&suspend_proc_data->proc_data_list, &suspend_proc_entries);
+		new_entry->read_proc = suspend2_read_proc;
+		new_entry->write_proc = suspend2_write_proc;
+		new_entry->data = suspend_proc_data;
+	} else {
+		printk("Error! create_proc_entry returned NULL.\n");
+		INIT_LIST_HEAD(&suspend_proc_data->proc_data_list);
+	}
+	return new_entry;
+}
+
+/* suspend_unregister_procfile
+ *
+ * Helper for removing unwanted /proc/software_suspend entries.
+ *
+ */
+void suspend_unregister_procfile(struct suspend_proc_data * suspend_proc_data)
+{
+	if (list_empty(&suspend_proc_data->proc_data_list))
+		return;
+
+	remove_proc_entry(
+		suspend_proc_data->filename,
+		suspend_dir);
+	list_del(&suspend_proc_data->proc_data_list);
+}
kernel/power/suspend2_core/proc.h +66 -0

66 lines not on this page · raw message

#129 lore raw

Re: [PATCH] [40/48] Suspend2 2.1.9.8 for 2.6.12: 616-prepare_image.patch

Hi!

Quoted 38 lines

diff -ruNp 617-proc.patch-old/kernel/power/suspend2_core/proc.c 617-proc.patch-new/kernel/power/suspend2_core/proc.c

kernel/power/suspend2_core/proc.c +34 -0
@@ -0,0 +1,336 @@
+/*
+ * /kernel/power/proc.c
+ *
+ * Copyright (C) 2002-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * This file contains support for proc entries for tuning Software Suspend.
+ *
+ * We have a generic handler that deals with the most common cases, and
+ * hooks for special handlers to use.
+ *
+ * Versions:
+ * 1: /proc/sys/kernel/suspend the only tuning interface
+ * 2: Initial version of this file
+ * 3: Removed kernel debugger parameter.
+ *    Added checkpage parameter (for checking checksum of a page over time).
+ * 4: Added entry for maximum granularity in splash screen progress bar.
+ *    (Progress bar is slow, but the right setting will vary with disk &
+ *    processor speed and the user's tastes).
+ * 5: Added enable_escape to control ability to cancel aborting by pressing
+ *    ESC key.
+ * 6: Removed checksumming and checkpage parameter. Made all debugging proc
+ *    entries dependant upon debugging being compiled in.
+ *    Meaning of some flags also changed in this version.
+ * 7: Added header_locations entry to simplify getting the resume= parameter for
+ *    swapfiles easy and swapfile entry for automatically doing swapon/off from
+ *    swapfiles as well as partitions.
+ * 8: Added option for marking process pages as pageset 2 (processes_pageset2).
+ * 9: Added option for keep image mode.
+ *    Enumeration patch from Michael Frank applied.
+ * 10: Various corrections to when options are disabled/enabled;
+ *     Added option for specifying expected compression.
+ * 11: Added option for freezer testing. Debug only.

kernel/power/suspend2_core/proc.c line 44

Quoted 10 lines
kernel/power/suspend2_core/proc.c +10 -0
+ * 12: Removed test entries no_async_[read|write], processes_pageset2 and
+ *     NoPageset2.
+ * 13: Make default_console_level available when debugging disabled, but limited
+ *     to 0 or 1.
+ * 14: Rewrite to allow for dynamic registration of proc entries and smooth the
+ *     transition to kobjects in 2.6.
+ * 15: Add setting resume2 parameter without rebooting (still need to run lilo
+ *     though!). Add support for generic string handling and switch resume2 to use
+ *     it.
+ * 16: Switched to cryptoapi, adding entries for selecting encryptor and compressor.

Pretty please, can we support just one version?
Pavel

Signature · 1 line
teflon -- maybe it is a trademark, but it should not be.
#130 lore raw

Re: [PATCH] [40/48] Suspend2 2.1.9.8 for 2.6.12: 616-prepare_image.patch

Hi.

Quoted 44 lines · Pavel Machek

Hi!

Quoted 42 lines

diff -ruNp 617-proc.patch-old/kernel/power/suspend2_core/proc.c 617-proc.patch-new/kernel/power/suspend2_core/proc.c

kernel/power/suspend2_core/proc.c +38 -0
@@ -0,0 +1,336 @@
+/*
+ * /kernel/power/proc.c
+ *
+ * Copyright (C) 2002-2005 Nigel Cunningham <[email protected]>
+ *
+ * This file is released under the GPLv2.
+ *
+ * This file contains support for proc entries for tuning Software Suspend.
+ *
+ * We have a generic handler that deals with the most common cases, and
+ * hooks for special handlers to use.
+ *
+ * Versions:
+ * 1: /proc/sys/kernel/suspend the only tuning interface
+ * 2: Initial version of this file
+ * 3: Removed kernel debugger parameter.
+ *    Added checkpage parameter (for checking checksum of a page over time).
+ * 4: Added entry for maximum granularity in splash screen progress bar.
+ *    (Progress bar is slow, but the right setting will vary with disk &
+ *    processor speed and the user's tastes).
+ * 5: Added enable_escape to control ability to cancel aborting by pressing
+ *    ESC key.
+ * 6: Removed checksumming and checkpage parameter. Made all debugging proc
+ *    entries dependant upon debugging being compiled in.
+ *    Meaning of some flags also changed in this version.
+ * 7: Added header_locations entry to simplify getting the resume= parameter for
+ *    swapfiles easy and swapfile entry for automatically doing swapon/off from
+ *    swapfiles as well as partitions.
+ * 8: Added option for marking process pages as pageset 2 (processes_pageset2).
+ * 9: Added option for keep image mode.
+ *    Enumeration patch from Michael Frank applied.
+ * 10: Various corrections to when options are disabled/enabled;
+ *     Added option for specifying expected compression.
+ * 11: Added option for freezer testing. Debug only.
+ * 12: Removed test entries no_async_[read|write], processes_pageset2 and
+ *     NoPageset2.
+ * 13: Make default_console_level available when debugging disabled, but limited
+ *     to 0 or 1.
Quoted 8 lines

kernel/power/suspend2_core/proc.c line 44

Quoted 6 lines
kernel/power/suspend2_core/proc.c +6 -0
+ * 14: Rewrite to allow for dynamic registration of proc entries and smooth the
+ *     transition to kobjects in 2.6.
+ * 15: Add setting resume2 parameter without rebooting (still need to run lilo
+ *     though!). Add support for generic string handling and switch resume2 to use
+ *     it.
+ * 16: Switched to cryptoapi, adding entries for selecting encryptor and compressor.

Pretty please, can we support just one version?

It is just one version supported. This is a log of the changes made. Sorry for the ambiguity.

Regards,

Nigel

Signature · 5 lines
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened.