linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
  2005-07-06  2:20 ` [PATCH] [1/48] Suspend2 2.1.9.8 for 2.6.12: submit_intro Nigel Cunningham
  2005-07-06  2:20 ` [PATCH] [4/48] Suspend2 2.1.9.8 for 2.6.12: 302-init-hooks.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 23:03   ` Christoph Hellwig
  2005-07-06  2:20 ` [PATCH] [2/48] Suspend2 2.1.9.8 for 2.6.12: 300-reboot-handler-hook.patch Nigel Cunningham
                   ` (48 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 302-init-hooks.patch-old/init/do_mounts.c 302-init-hooks.patch-new/init/do_mounts.c
--- 302-init-hooks.patch-old/init/do_mounts.c	2005-06-20 11:47:31.000000000 +1000
+++ 302-init-hooks.patch-new/init/do_mounts.c	2005-07-04 23:14:19.000000000 +1000
@@ -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;
 
diff -ruNp 302-init-hooks.patch-old/init/do_mounts_initrd.c 302-init-hooks.patch-new/init/do_mounts_initrd.c
--- 302-init-hooks.patch-old/init/do_mounts_initrd.c	2004-11-03 21:51:15.000000000 +1100
+++ 302-init-hooks.patch-new/init/do_mounts_initrd.c	2005-07-04 23:14:19.000000000 +1000
@@ -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);
diff -ruNp 302-init-hooks.patch-old/init/main.c 302-init-hooks.patch-new/init/main.c
--- 302-init-hooks.patch-old/init/main.c	2005-07-06 11:13:20.000000000 +1000
+++ 302-init-hooks.patch-new/init/main.c	2005-07-04 23:14:19.000000000 +1000
@@ -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";


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [6/48] Suspend2 2.1.9.8 for 2.6.12: 351-syncthreads.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (3 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [2/48] Suspend2 2.1.9.8 for 2.6.12: 300-reboot-handler-hook.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  2:20 ` [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch Nigel Cunningham
                   ` (46 subsequent siblings)
  51 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 352-disable-pdflush-during-suspend.patch-old/mm/page-writeback.c 352-disable-pdflush-during-suspend.patch-new/mm/page-writeback.c
--- 352-disable-pdflush-during-suspend.patch-old/mm/page-writeback.c	2005-06-20 11:47:32.000000000 +1000
+++ 352-disable-pdflush-during-suspend.patch-new/mm/page-writeback.c	2005-07-04 23:14:19.000000000 +1000
@@ -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)


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (4 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [6/48] Suspend2 2.1.9.8 for 2.6.12: 351-syncthreads.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 23:04   ` Christoph Hellwig
  2005-07-06  2:20 ` [PATCH] [8/48] Suspend2 2.1.9.8 for 2.6.12: 353-disable-highmem-tlb-flush-for-copyback.patch Nigel Cunningham
                   ` (45 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 351-syncthreads.patch-old/fs/buffer.c 351-syncthreads.patch-new/fs/buffer.c
--- 351-syncthreads.patch-old/fs/buffer.c	2005-07-06 11:15:04.000000000 +1000
+++ 351-syncthreads.patch-new/fs/buffer.c	2005-07-04 23:14:18.000000000 +1000
@@ -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;
 }
 
diff -ruNp 351-syncthreads.patch-old/fs/jbd/journal.c 351-syncthreads.patch-new/fs/jbd/journal.c
--- 351-syncthreads.patch-old/fs/jbd/journal.c	2005-07-06 11:15:04.000000000 +1000
+++ 351-syncthreads.patch-new/fs/jbd/journal.c	2005-07-04 23:14:19.000000000 +1000
@@ -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 */
diff -ruNp 351-syncthreads.patch-old/fs/jffs/intrep.c 351-syncthreads.patch-new/fs/jffs/intrep.c
--- 351-syncthreads.patch-old/fs/jffs/intrep.c	2005-07-06 11:15:04.000000000 +1000
+++ 351-syncthreads.patch-new/fs/jffs/intrep.c	2005-07-04 23:14:19.000000000 +1000
@@ -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;
 
diff -ruNp 351-syncthreads.patch-old/fs/jfs/jfs_logmgr.c 351-syncthreads.patch-new/fs/jfs/jfs_logmgr.c
--- 351-syncthreads.patch-old/fs/jfs/jfs_logmgr.c	2005-07-06 11:15:04.000000000 +1000
+++ 351-syncthreads.patch-new/fs/jfs/jfs_logmgr.c	2005-07-04 23:14:19.000000000 +1000
@@ -2351,6 +2351,7 @@ int jfsIOWait(void *arg)
 	struct lbuf *bp;
 
 	daemonize("jfsIO");
+	current->flags |= PF_SYNCTHREAD;
 
 	complete(&jfsIOwait);
 
diff -ruNp 351-syncthreads.patch-old/fs/jfs/jfs_txnmgr.c 351-syncthreads.patch-new/fs/jfs/jfs_txnmgr.c
--- 351-syncthreads.patch-old/fs/jfs/jfs_txnmgr.c	2005-07-06 11:15:04.000000000 +1000
+++ 351-syncthreads.patch-new/fs/jfs/jfs_txnmgr.c	2005-07-04 23:14:19.000000000 +1000
@@ -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);
 
diff -ruNp 351-syncthreads.patch-old/fs/lockd/clntlock.c 351-syncthreads.patch-new/fs/lockd/clntlock.c
--- 351-syncthreads.patch-old/fs/lockd/clntlock.c	2005-07-06 11:15:04.000000000 +1000
+++ 351-syncthreads.patch-new/fs/lockd/clntlock.c	2005-07-04 23:14:19.000000000 +1000
@@ -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
diff -ruNp 351-syncthreads.patch-old/fs/lockd/svc.c 351-syncthreads.patch-new/fs/lockd/svc.c
--- 351-syncthreads.patch-old/fs/lockd/svc.c	2005-06-20 11:47:13.000000000 +1000
+++ 351-syncthreads.patch-new/fs/lockd/svc.c	2005-07-04 23:14:19.000000000 +1000
@@ -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) {
diff -ruNp 351-syncthreads.patch-old/fs/nfsd/nfssvc.c 351-syncthreads.patch-new/fs/nfsd/nfssvc.c
--- 351-syncthreads.patch-old/fs/nfsd/nfssvc.c	2005-06-20 11:47:13.000000000 +1000
+++ 351-syncthreads.patch-new/fs/nfsd/nfssvc.c	2005-07-04 23:14:19.000000000 +1000
@@ -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
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
--- 351-syncthreads.patch-old/fs/xfs/linux-2.6/xfs_buf.c	2005-07-06 11:15:04.000000000 +1000
+++ 351-syncthreads.patch-new/fs/xfs/linux-2.6/xfs_buf.c	2005-07-04 23:14:19.000000000 +1000
@@ -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;
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
--- 351-syncthreads.patch-old/fs/xfs/linux-2.6/xfs_super.c	2005-07-06 11:15:04.000000000 +1000
+++ 351-syncthreads.patch-new/fs/xfs/linux-2.6/xfs_super.c	2005-07-04 23:14:19.000000000 +1000
@@ -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;
diff -ruNp 351-syncthreads.patch-old/include/linux/sched.h 351-syncthreads.patch-new/include/linux/sched.h
--- 351-syncthreads.patch-old/include/linux/sched.h	2005-07-06 11:15:04.000000000 +1000
+++ 351-syncthreads.patch-new/include/linux/sched.h	2005-07-04 23:14:19.000000000 +1000
@@ -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
diff -ruNp 351-syncthreads.patch-old/mm/pdflush.c 351-syncthreads.patch-new/mm/pdflush.c
--- 351-syncthreads.patch-old/mm/pdflush.c	2005-07-06 11:15:04.000000000 +1000
+++ 351-syncthreads.patch-new/mm/pdflush.c	2005-07-04 23:14:19.000000000 +1000
@@ -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);


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [4/48] Suspend2 2.1.9.8 for 2.6.12: 302-init-hooks.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
  2005-07-06  2:20 ` [PATCH] [1/48] Suspend2 2.1.9.8 for 2.6.12: submit_intro Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  8:38   ` Shaohua Li
  2005-07-06  2:20 ` [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch Nigel Cunningham
                   ` (49 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 350-workthreads.patch-old/drivers/acpi/osl.c 350-workthreads.patch-new/drivers/acpi/osl.c
--- 350-workthreads.patch-old/drivers/acpi/osl.c	2005-06-20 11:46:50.000000000 +1000
+++ 350-workthreads.patch-new/drivers/acpi/osl.c	2005-07-04 23:14:18.000000000 +1000
@@ -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;
diff -ruNp 350-workthreads.patch-old/drivers/block/ll_rw_blk.c 350-workthreads.patch-new/drivers/block/ll_rw_blk.c
--- 350-workthreads.patch-old/drivers/block/ll_rw_blk.c	2005-06-20 11:46:50.000000000 +1000
+++ 350-workthreads.patch-new/drivers/block/ll_rw_blk.c	2005-07-04 23:14:18.000000000 +1000
@@ -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");
 
diff -ruNp 350-workthreads.patch-old/drivers/block/pktcdvd.c 350-workthreads.patch-new/drivers/block/pktcdvd.c
--- 350-workthreads.patch-old/drivers/block/pktcdvd.c	2005-07-06 11:14:09.000000000 +1000
+++ 350-workthreads.patch-new/drivers/block/pktcdvd.c	2005-07-04 23:14:18.000000000 +1000
@@ -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;
diff -ruNp 350-workthreads.patch-old/drivers/char/hvc_console.c 350-workthreads.patch-new/drivers/char/hvc_console.c
--- 350-workthreads.patch-old/drivers/char/hvc_console.c	2005-02-03 22:33:25.000000000 +1100
+++ 350-workthreads.patch-new/drivers/char/hvc_console.c	2005-07-04 23:14:18.000000000 +1000
@@ -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);
diff -ruNp 350-workthreads.patch-old/drivers/char/hvcs.c 350-workthreads.patch-new/drivers/char/hvcs.c
--- 350-workthreads.patch-old/drivers/char/hvcs.c	2005-02-14 09:05:25.000000000 +1100
+++ 350-workthreads.patch-new/drivers/char/hvcs.c	2005-07-04 23:14:18.000000000 +1000
@@ -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);
diff -ruNp 350-workthreads.patch-old/drivers/infiniband/core/fmr_pool.c 350-workthreads.patch-new/drivers/infiniband/core/fmr_pool.c
--- 350-workthreads.patch-old/drivers/infiniband/core/fmr_pool.c	2005-06-20 11:46:54.000000000 +1000
+++ 350-workthreads.patch-new/drivers/infiniband/core/fmr_pool.c	2005-07-04 23:14:18.000000000 +1000
@@ -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)) {
diff -ruNp 350-workthreads.patch-old/drivers/infiniband/core/mad.c 350-workthreads.patch-new/drivers/infiniband/core/mad.c
--- 350-workthreads.patch-old/drivers/infiniband/core/mad.c	2005-06-20 11:46:54.000000000 +1000
+++ 350-workthreads.patch-new/drivers/infiniband/core/mad.c	2005-07-04 23:14:18.000000000 +1000
@@ -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;
diff -ruNp 350-workthreads.patch-old/drivers/infiniband/ulp/ipoib/ipoib_main.c 350-workthreads.patch-new/drivers/infiniband/ulp/ipoib/ipoib_main.c
--- 350-workthreads.patch-old/drivers/infiniband/ulp/ipoib/ipoib_main.c	2005-06-20 11:46:54.000000000 +1000
+++ 350-workthreads.patch-new/drivers/infiniband/ulp/ipoib/ipoib_main.c	2005-07-04 23:14:18.000000000 +1000
@@ -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;
diff -ruNp 350-workthreads.patch-old/drivers/macintosh/therm_adt746x.c 350-workthreads.patch-new/drivers/macintosh/therm_adt746x.c
--- 350-workthreads.patch-old/drivers/macintosh/therm_adt746x.c	2005-07-06 11:14:09.000000000 +1000
+++ 350-workthreads.patch-new/drivers/macintosh/therm_adt746x.c	2005-07-04 23:14:18.000000000 +1000
@@ -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");
diff -ruNp 350-workthreads.patch-old/drivers/md/dm-crypt.c 350-workthreads.patch-new/drivers/md/dm-crypt.c
--- 350-workthreads.patch-old/drivers/md/dm-crypt.c	2005-06-20 11:46:55.000000000 +1000
+++ 350-workthreads.patch-new/drivers/md/dm-crypt.c	2005-07-04 23:14:18.000000000 +1000
@@ -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");
diff -ruNp 350-workthreads.patch-old/drivers/md/dm-mpath.c 350-workthreads.patch-new/drivers/md/dm-mpath.c
--- 350-workthreads.patch-old/drivers/md/dm-mpath.c	2005-06-20 11:46:55.000000000 +1000
+++ 350-workthreads.patch-new/drivers/md/dm-mpath.c	2005-07-04 23:14:18.000000000 +1000
@@ -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);
diff -ruNp 350-workthreads.patch-old/drivers/md/dm-raid1.c 350-workthreads.patch-new/drivers/md/dm-raid1.c
--- 350-workthreads.patch-old/drivers/md/dm-raid1.c	2005-06-20 11:46:55.000000000 +1000
+++ 350-workthreads.patch-new/drivers/md/dm-raid1.c	2005-07-04 23:14:18.000000000 +1000
@@ -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();
diff -ruNp 350-workthreads.patch-old/drivers/md/kcopyd.c 350-workthreads.patch-new/drivers/md/kcopyd.c
--- 350-workthreads.patch-old/drivers/md/kcopyd.c	2005-02-03 22:33:28.000000000 +1100
+++ 350-workthreads.patch-new/drivers/md/kcopyd.c	2005-07-04 23:14:18.000000000 +1000
@@ -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);
diff -ruNp 350-workthreads.patch-old/drivers/media/video/cx88/cx88-video.c 350-workthreads.patch-new/drivers/media/video/cx88/cx88-video.c
--- 350-workthreads.patch-old/drivers/media/video/cx88/cx88-video.c	2005-06-20 11:46:58.000000000 +1000
+++ 350-workthreads.patch-new/drivers/media/video/cx88/cx88-video.c	2005-07-04 23:14:18.000000000 +1000
@@ -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:
diff -ruNp 350-workthreads.patch-old/drivers/media/video/msp3400.c 350-workthreads.patch-new/drivers/media/video/msp3400.c
--- 350-workthreads.patch-old/drivers/media/video/msp3400.c	2005-07-06 11:14:10.000000000 +1000
+++ 350-workthreads.patch-new/drivers/media/video/msp3400.c	2005-07-04 23:14:18.000000000 +1000
@@ -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);
diff -ruNp 350-workthreads.patch-old/drivers/media/video/video-buf-dvb.c 350-workthreads.patch-new/drivers/media/video/video-buf-dvb.c
--- 350-workthreads.patch-old/drivers/media/video/video-buf-dvb.c	2005-07-06 11:14:09.000000000 +1000
+++ 350-workthreads.patch-new/drivers/media/video/video-buf-dvb.c	2005-07-04 23:14:18.000000000 +1000
@@ -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;
diff -ruNp 350-workthreads.patch-old/drivers/message/i2o/driver.c 350-workthreads.patch-new/drivers/message/i2o/driver.c
--- 350-workthreads.patch-old/drivers/message/i2o/driver.c	2005-02-03 22:33:29.000000000 +1100
+++ 350-workthreads.patch-new/drivers/message/i2o/driver.c	2005-07-04 23:14:18.000000000 +1000
@@ -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);
diff -ruNp 350-workthreads.patch-old/drivers/net/wan/sdlamain.c 350-workthreads.patch-new/drivers/net/wan/sdlamain.c
--- 350-workthreads.patch-old/drivers/net/wan/sdlamain.c	2004-11-03 21:54:35.000000000 +1100
+++ 350-workthreads.patch-new/drivers/net/wan/sdlamain.c	2005-07-04 23:14:18.000000000 +1000
@@ -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;
 
diff -ruNp 350-workthreads.patch-old/drivers/s390/cio/device.c 350-workthreads.patch-new/drivers/s390/cio/device.c
--- 350-workthreads.patch-old/drivers/s390/cio/device.c	2005-06-20 11:47:03.000000000 +1000
+++ 350-workthreads.patch-new/drivers/s390/cio/device.c	2005-07-04 23:14:18.000000000 +1000
@@ -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;
diff -ruNp 350-workthreads.patch-old/drivers/scsi/hosts.c 350-workthreads.patch-new/drivers/scsi/hosts.c
--- 350-workthreads.patch-old/drivers/scsi/hosts.c	2005-06-20 11:47:04.000000000 +1000
+++ 350-workthreads.patch-new/drivers/scsi/hosts.c	2005-07-04 23:14:18.000000000 +1000
@@ -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;
 	}
diff -ruNp 350-workthreads.patch-old/drivers/scsi/libata-core.c 350-workthreads.patch-new/drivers/scsi/libata-core.c
--- 350-workthreads.patch-old/drivers/scsi/libata-core.c	2005-06-20 11:47:05.000000000 +1000
+++ 350-workthreads.patch-new/drivers/scsi/libata-core.c	2005-07-04 23:14:18.000000000 +1000
@@ -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;
 
diff -ruNp 350-workthreads.patch-old/drivers/usb/net/pegasus.c 350-workthreads.patch-new/drivers/usb/net/pegasus.c
--- 350-workthreads.patch-old/drivers/usb/net/pegasus.c	2005-06-20 11:47:09.000000000 +1000
+++ 350-workthreads.patch-new/drivers/usb/net/pegasus.c	2005-07-04 23:14:18.000000000 +1000
@@ -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);
diff -ruNp 350-workthreads.patch-old/fs/aio.c 350-workthreads.patch-new/fs/aio.c
--- 350-workthreads.patch-old/fs/aio.c	2005-06-20 11:47:11.000000000 +1000
+++ 350-workthreads.patch-new/fs/aio.c	2005-07-04 23:14:18.000000000 +1000
@@ -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));
 
diff -ruNp 350-workthreads.patch-old/fs/nfsd/nfs4state.c 350-workthreads.patch-new/fs/nfsd/nfs4state.c
--- 350-workthreads.patch-old/fs/nfsd/nfs4state.c	2005-06-20 11:47:13.000000000 +1000
+++ 350-workthreads.patch-new/fs/nfsd/nfs4state.c	2005-07-04 23:14:18.000000000 +1000
@@ -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;
 
diff -ruNp 350-workthreads.patch-old/fs/reiserfs/journal.c 350-workthreads.patch-new/fs/reiserfs/journal.c
--- 350-workthreads.patch-old/fs/reiserfs/journal.c	2005-06-20 11:47:13.000000000 +1000
+++ 350-workthreads.patch-new/fs/reiserfs/journal.c	2005-07-04 23:14:18.000000000 +1000
@@ -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 ;
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
--- 350-workthreads.patch-old/fs/xfs/linux-2.6/xfs_buf.c	2005-07-06 11:14:10.000000000 +1000
+++ 350-workthreads.patch-new/fs/xfs/linux-2.6/xfs_buf.c	2005-07-06 11:14:38.000000000 +1000
@@ -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;
diff -ruNp 350-workthreads.patch-old/include/linux/kthread.h 350-workthreads.patch-new/include/linux/kthread.h
--- 350-workthreads.patch-old/include/linux/kthread.h	2004-11-03 21:51:12.000000000 +1100
+++ 350-workthreads.patch-new/include/linux/kthread.h	2005-07-04 23:14:18.000000000 +1000
@@ -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;								   \
diff -ruNp 350-workthreads.patch-old/include/linux/workqueue.h 350-workthreads.patch-new/include/linux/workqueue.h
--- 350-workthreads.patch-old/include/linux/workqueue.h	2005-06-20 11:47:30.000000000 +1000
+++ 350-workthreads.patch-new/include/linux/workqueue.h	2005-07-04 23:14:18.000000000 +1000
@@ -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);
 
diff -ruNp 350-workthreads.patch-old/kernel/kmod.c 350-workthreads.patch-new/kernel/kmod.c
--- 350-workthreads.patch-old/kernel/kmod.c	2004-12-10 14:27:00.000000000 +1100
+++ 350-workthreads.patch-new/kernel/kmod.c	2005-07-04 23:14:18.000000000 +1000
@@ -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);
 }
diff -ruNp 350-workthreads.patch-old/kernel/kthread.c 350-workthreads.patch-new/kernel/kthread.c
--- 350-workthreads.patch-old/kernel/kthread.c	2005-07-06 11:14:10.000000000 +1000
+++ 350-workthreads.patch-new/kernel/kthread.c	2005-07-06 11:14:38.000000000 +1000
@@ -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;
diff -ruNp 350-workthreads.patch-old/kernel/sched.c 350-workthreads.patch-new/kernel/sched.c
--- 350-workthreads.patch-old/kernel/sched.c	2005-07-06 11:14:10.000000000 +1000
+++ 350-workthreads.patch-new/kernel/sched.c	2005-07-04 23:14:19.000000000 +1000
@@ -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);
diff -ruNp 350-workthreads.patch-old/kernel/softirq.c 350-workthreads.patch-new/kernel/softirq.c
--- 350-workthreads.patch-old/kernel/softirq.c	2005-06-20 11:47:32.000000000 +1000
+++ 350-workthreads.patch-new/kernel/softirq.c	2005-07-04 23:14:18.000000000 +1000
@@ -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;
diff -ruNp 350-workthreads.patch-old/kernel/stop_machine.c 350-workthreads.patch-new/kernel/stop_machine.c
--- 350-workthreads.patch-old/kernel/stop_machine.c	2005-06-20 11:47:32.000000000 +1000
+++ 350-workthreads.patch-new/kernel/stop_machine.c	2005-07-04 23:14:18.000000000 +1000
@@ -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);
diff -ruNp 350-workthreads.patch-old/kernel/workqueue.c 350-workthreads.patch-new/kernel/workqueue.c
--- 350-workthreads.patch-old/kernel/workqueue.c	2005-06-20 11:47:32.000000000 +1000
+++ 350-workthreads.patch-new/kernel/workqueue.c	2005-07-04 23:14:18.000000000 +1000
@@ -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);
 }
 
diff -ruNp 350-workthreads.patch-old/mm/pdflush.c 350-workthreads.patch-new/mm/pdflush.c
--- 350-workthreads.patch-old/mm/pdflush.c	2005-07-06 11:14:10.000000000 +1000
+++ 350-workthreads.patch-new/mm/pdflush.c	2005-07-06 11:14:38.000000000 +1000
@@ -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)
diff -ruNp 350-workthreads.patch-old/net/sunrpc/sched.c 350-workthreads.patch-new/net/sunrpc/sched.c
--- 350-workthreads.patch-old/net/sunrpc/sched.c	2005-07-06 11:14:10.000000000 +1000
+++ 350-workthreads.patch-new/net/sunrpc/sched.c	2005-07-04 23:14:18.000000000 +1000
@@ -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--;
diff -ruNp 350-workthreads.patch-old/sound/i2c/other/ak4114.c 350-workthreads.patch-new/sound/i2c/other/ak4114.c
--- 350-workthreads.patch-old/sound/i2c/other/ak4114.c	2005-06-20 11:47:36.000000000 +1000
+++ 350-workthreads.patch-new/sound/i2c/other/ak4114.c	2005-07-04 23:14:18.000000000 +1000
@@ -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;
diff -ruNp 350-workthreads.patch-old/sound/pci/hda/hda_codec.c 350-workthreads.patch-new/sound/pci/hda/hda_codec.c
--- 350-workthreads.patch-old/sound/pci/hda/hda_codec.c	2005-06-20 11:47:40.000000000 +1000
+++ 350-workthreads.patch-new/sound/pci/hda/hda_codec.c	2005-07-04 23:14:18.000000000 +1000
@@ -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);


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [0/48] Suspend2 2.1.9.8 for 2.6.12
@ 2005-07-06  2:20 Nigel Cunningham
  2005-07-06  2:20 ` [PATCH] [1/48] Suspend2 2.1.9.8 for 2.6.12: submit_intro Nigel Cunningham
                   ` (51 more replies)
  0 siblings, 52 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [1/48] Suspend2 2.1.9.8 for 2.6.12: submit_intro
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  6:37   ` Pekka Enberg
  2005-07-06  8:12   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [4/48] Suspend2 2.1.9.8 for 2.6.12: 302-init-hooks.patch Nigel Cunningham
                   ` (50 subsequent siblings)
  51 siblings, 2 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 300-reboot-handler-hook.patch-old/kernel/sys.c 300-reboot-handler-hook.patch-new/kernel/sys.c
--- 300-reboot-handler-hook.patch-old/kernel/sys.c	2005-06-20 11:47:32.000000000 +1000
+++ 300-reboot-handler-hook.patch-new/kernel/sys.c	2005-07-04 23:14:18.000000000 +1000
@@ -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
 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [2/48] Suspend2 2.1.9.8 for 2.6.12: 300-reboot-handler-hook.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (2 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06 10:08   ` Pekka Enberg
  2005-07-06  2:20 ` [PATCH] [6/48] Suspend2 2.1.9.8 for 2.6.12: 351-syncthreads.patch Nigel Cunningham
                   ` (47 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

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
--- 301-proc-acpi-sleep-activate-hook.patch-old/drivers/acpi/sleep/proc.c	2005-06-20 11:46:50.000000000 +1000
+++ 301-proc-acpi-sleep-activate-hook.patch-new/drivers/acpi/sleep/proc.c	2005-07-04 23:14:18.000000000 +1000
@@ -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();


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [8/48] Suspend2 2.1.9.8 for 2.6.12: 353-disable-highmem-tlb-flush-for-copyback.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (5 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  2:20 ` [PATCH] [10/48] Suspend2 2.1.9.8 for 2.6.12: 360-reset-kswapd-max-order-after-resume.patch Nigel Cunningham
                   ` (44 subsequent siblings)
  51 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

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
--- 354-disable-mce-checking-during-suspend-avoid-smp-deadlock.patch-old/arch/i386/kernel/cpu/mcheck/non-fatal.c	2004-12-10 14:26:18.000000000 +1100
+++ 354-disable-mce-checking-during-suspend-avoid-smp-deadlock.patch-new/arch/i386/kernel/cpu/mcheck/non-fatal.c	2005-07-04 23:14:20.000000000 +1000
@@ -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);
 } 
 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [12/48] Suspend2 2.1.9.8 for 2.6.12: 402-mtrr-remove-sysdev.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (11 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [11/48] Suspend2 2.1.9.8 for 2.6.12: 401-e820-table-support.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 23:07   ` Christoph Hellwig
  2005-07-06  2:20 ` [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch Nigel Cunningham
                   ` (38 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 403-debug-pagealloc-support.patch-old/arch/i386/mm/pageattr.c 403-debug-pagealloc-support.patch-new/arch/i386/mm/pageattr.c
--- 403-debug-pagealloc-support.patch-old/arch/i386/mm/pageattr.c	2005-06-20 11:46:43.000000000 +1000
+++ 403-debug-pagealloc-support.patch-new/arch/i386/mm/pageattr.c	2005-07-04 23:14:19.000000000 +1000
@@ -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);


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [11/48] Suspend2 2.1.9.8 for 2.6.12: 401-e820-table-support.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (10 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [14/48] Suspend2 2.1.9.8 for 2.6.12: 404-check-mounts-support.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  3:35   ` Zwane Mwaikambo
  2005-07-06  2:20 ` [PATCH] [12/48] Suspend2 2.1.9.8 for 2.6.12: 402-mtrr-remove-sysdev.patch Nigel Cunningham
                   ` (39 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

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
--- 402-mtrr-remove-sysdev.patch-old/arch/i386/kernel/cpu/mtrr/main.c	2005-06-20 11:46:42.000000000 +1000
+++ 402-mtrr-remove-sysdev.patch-new/arch/i386/kernel/cpu/mtrr/main.c	2005-07-04 23:14:19.000000000 +1000
@@ -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;
 }


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (12 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [12/48] Suspend2 2.1.9.8 for 2.6.12: 402-mtrr-remove-sysdev.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  3:34   ` Zwane Mwaikambo
                     ` (3 more replies)
  2005-07-06  2:20 ` [PATCH] [17/48] Suspend2 2.1.9.8 for 2.6.12: 500-version-specific-i386.patch Nigel Cunningham
                   ` (37 subsequent siblings)
  51 siblings, 4 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

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
--- 353-disable-highmem-tlb-flush-for-copyback.patch-old/mm/highmem.c	2005-06-20 11:47:32.000000000 +1000
+++ 353-disable-highmem-tlb-flush-for-copyback.patch-new/mm/highmem.c	2005-07-04 23:14:20.000000000 +1000
@@ -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)


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [14/48] Suspend2 2.1.9.8 for 2.6.12: 404-check-mounts-support.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (9 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [9/48] Suspend2 2.1.9.8 for 2.6.12: 354-disable-mce-checking-during-suspend-avoid-smp-deadlock.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  8:15   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [11/48] Suspend2 2.1.9.8 for 2.6.12: 401-e820-table-support.patch Nigel Cunningham
                   ` (40 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 405-clear-swapfile-bdev-in-swapoff.patch-old/mm/swapfile.c 405-clear-swapfile-bdev-in-swapoff.patch-new/mm/swapfile.c
--- 405-clear-swapfile-bdev-in-swapoff.patch-old/mm/swapfile.c	2005-07-06 11:22:01.000000000 +1000
+++ 405-clear-swapfile-bdev-in-swapoff.patch-new/mm/swapfile.c	2005-07-04 23:14:19.000000000 +1000
@@ -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;


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [13/48] Suspend2 2.1.9.8 for 2.6.12: 403-debug-pagealloc-support.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (7 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [10/48] Suspend2 2.1.9.8 for 2.6.12: 360-reset-kswapd-max-order-after-resume.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 23:02   ` Christoph Hellwig
  2005-07-06  2:20 ` [PATCH] [9/48] Suspend2 2.1.9.8 for 2.6.12: 354-disable-mce-checking-during-suspend-avoid-smp-deadlock.patch Nigel Cunningham
                   ` (42 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 404-check-mounts-support.patch-old/drivers/usb/core/inode.c 404-check-mounts-support.patch-new/drivers/usb/core/inode.c
--- 404-check-mounts-support.patch-old/drivers/usb/core/inode.c	2005-06-20 11:47:07.000000000 +1000
+++ 404-check-mounts-support.patch-new/drivers/usb/core/inode.c	2005-07-04 23:14:19.000000000 +1000
@@ -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,
 };
 
 /* --------------------------------------------------------------------- */
diff -ruNp 404-check-mounts-support.patch-old/fs/block_dev.c 404-check-mounts-support.patch-new/fs/block_dev.c
--- 404-check-mounts-support.patch-old/fs/block_dev.c	2005-06-20 11:47:11.000000000 +1000
+++ 404-check-mounts-support.patch-new/fs/block_dev.c	2005-07-04 23:14:19.000000000 +1000
@@ -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;
diff -ruNp 404-check-mounts-support.patch-old/fs/debugfs/inode.c 404-check-mounts-support.patch-new/fs/debugfs/inode.c
--- 404-check-mounts-support.patch-old/fs/debugfs/inode.c	2005-02-03 22:33:40.000000000 +1100
+++ 404-check-mounts-support.patch-new/fs/debugfs/inode.c	2005-07-04 23:14:19.000000000 +1000
@@ -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,
diff -ruNp 404-check-mounts-support.patch-old/fs/devfs/base.c 404-check-mounts-support.patch-new/fs/devfs/base.c
--- 404-check-mounts-support.patch-old/fs/devfs/base.c	2005-02-03 22:33:40.000000000 +1100
+++ 404-check-mounts-support.patch-new/fs/devfs/base.c	2005-07-04 23:14:19.000000000 +1000
@@ -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  */
diff -ruNp 404-check-mounts-support.patch-old/fs/devpts/inode.c 404-check-mounts-support.patch-new/fs/devpts/inode.c
--- 404-check-mounts-support.patch-old/fs/devpts/inode.c	2005-02-03 22:33:40.000000000 +1100
+++ 404-check-mounts-support.patch-new/fs/devpts/inode.c	2005-07-04 23:14:19.000000000 +1000
@@ -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,
 };
 
 /*
diff -ruNp 404-check-mounts-support.patch-old/fs/eventpoll.c 404-check-mounts-support.patch-new/fs/eventpoll.c
--- 404-check-mounts-support.patch-old/fs/eventpoll.c	2005-06-20 11:47:12.000000000 +1000
+++ 404-check-mounts-support.patch-new/fs/eventpoll.c	2005-07-04 23:14:19.000000000 +1000
@@ -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 */
diff -ruNp 404-check-mounts-support.patch-old/fs/hugetlbfs/inode.c 404-check-mounts-support.patch-new/fs/hugetlbfs/inode.c
--- 404-check-mounts-support.patch-old/fs/hugetlbfs/inode.c	2005-06-20 11:47:12.000000000 +1000
+++ 404-check-mounts-support.patch-new/fs/hugetlbfs/inode.c	2005-07-04 23:14:19.000000000 +1000
@@ -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;
diff -ruNp 404-check-mounts-support.patch-old/fs/nfs/inode.c 404-check-mounts-support.patch-new/fs/nfs/inode.c
--- 404-check-mounts-support.patch-old/fs/nfs/inode.c	2005-06-20 11:47:13.000000000 +1000
+++ 404-check-mounts-support.patch-new/fs/nfs/inode.c	2005-07-04 23:14:19.000000000 +1000
@@ -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
diff -ruNp 404-check-mounts-support.patch-old/fs/pipe.c 404-check-mounts-support.patch-new/fs/pipe.c
--- 404-check-mounts-support.patch-old/fs/pipe.c	2005-06-20 11:47:13.000000000 +1000
+++ 404-check-mounts-support.patch-new/fs/pipe.c	2005-07-04 23:14:19.000000000 +1000
@@ -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)
diff -ruNp 404-check-mounts-support.patch-old/fs/proc/root.c 404-check-mounts-support.patch-new/fs/proc/root.c
--- 404-check-mounts-support.patch-old/fs/proc/root.c	2004-12-10 14:26:29.000000000 +1100
+++ 404-check-mounts-support.patch-new/fs/proc/root.c	2005-07-04 23:14:19.000000000 +1000
@@ -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);
diff -ruNp 404-check-mounts-support.patch-old/fs/ramfs/inode.c 404-check-mounts-support.patch-new/fs/ramfs/inode.c
--- 404-check-mounts-support.patch-old/fs/ramfs/inode.c	2005-06-20 11:47:13.000000000 +1000
+++ 404-check-mounts-support.patch-new/fs/ramfs/inode.c	2005-07-04 23:14:19.000000000 +1000
@@ -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)
diff -ruNp 404-check-mounts-support.patch-old/fs/super.c 404-check-mounts-support.patch-new/fs/super.c
--- 404-check-mounts-support.patch-old/fs/super.c	2005-06-20 11:47:13.000000000 +1000
+++ 404-check-mounts-support.patch-new/fs/super.c	2005-07-04 23:14:19.000000000 +1000
@@ -584,6 +584,68 @@ void emergency_remount(void)
 	pdflush_operation(do_emergency_remount, 0);
 }
 
+static inline int mount_s4_resume_safe(struct super_block *sb)
+{
+	return ((sb->s_flags & MS_RDONLY) ||
+		(sb->s_type->fs_flags & FS_RW_S4_RESUME_SAFE));
+}
+
+/* mounts_are_s4_resume_safe
+ *
+ * This routine is used by software suspend to check that
+ * the user doesn't have any mounts that we might corrupt
+ * by resuming. This is a possibility where initrds/initramfs
+ * are used and the user hasn't properly configured their
+ * system to check for resuming _before_ mounting filesystems
+ */
+
+int mounts_are_S4_resume_safe(void)
+{
+	struct super_block *sb;
+	int result = 1;
+
+	spin_lock(&sb_lock);
+	list_for_each_entry(sb, &super_blocks, s_list) {
+		if (!mount_s4_resume_safe(sb)) {
+			result = 0;
+			break;
+		}
+	}
+
+	spin_unlock(&sb_lock);
+	return result;
+}
+
+/* printk_S4_resume_unsafe_mounts
+ *
+ * Display which mounts we consider unsafe. It's all very
+ * well to tell the user some are, but it's more helpful
+ * to tell them which ones. It might simply be that the
+ * FS is safe but hasn't been marked as such yet.
+ */
+
+void get_S4_resume_unsafe_mounts(char * buffer, int buffer_size)
+{
+	struct super_block *sb;
+	int printed_len = 0;
+
+	spin_lock(&sb_lock);
+	list_for_each_entry(sb, &super_blocks, s_list) {
+		if (!mount_s4_resume_safe(sb)) {
+			printed_len += snprintf(
+				buffer + printed_len,
+				buffer_size - printed_len,
+				" - %s fs mounted %s.\n",
+				sb->s_type->name,
+				sb->s_flags & MS_RDONLY ? " ro" : " rw");
+			if (printed_len > buffer_size)
+				break;
+		}
+	}
+
+	spin_unlock(&sb_lock);
+}
+
 /*
  * Unnamed block devices are dummy devices used by virtual
  * filesystems which don't use real block-devices.  -- jrs
diff -ruNp 404-check-mounts-support.patch-old/fs/sysfs/mount.c 404-check-mounts-support.patch-new/fs/sysfs/mount.c
--- 404-check-mounts-support.patch-old/fs/sysfs/mount.c	2005-06-20 11:47:13.000000000 +1000
+++ 404-check-mounts-support.patch-new/fs/sysfs/mount.c	2005-07-04 23:14:19.000000000 +1000
@@ -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)
diff -ruNp 404-check-mounts-support.patch-old/include/linux/fs.h 404-check-mounts-support.patch-new/include/linux/fs.h
--- 404-check-mounts-support.patch-old/include/linux/fs.h	2005-06-20 11:47:29.000000000 +1000
+++ 404-check-mounts-support.patch-new/include/linux/fs.h	2005-07-04 23:14:19.000000000 +1000
@@ -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))
diff -ruNp 404-check-mounts-support.patch-old/ipc/mqueue.c 404-check-mounts-support.patch-new/ipc/mqueue.c
--- 404-check-mounts-support.patch-old/ipc/mqueue.c	2005-06-20 11:47:31.000000000 +1000
+++ 404-check-mounts-support.patch-new/ipc/mqueue.c	2005-07-04 23:14:19.000000000 +1000
@@ -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;
diff -ruNp 404-check-mounts-support.patch-old/kernel/futex.c 404-check-mounts-support.patch-new/kernel/futex.c
--- 404-check-mounts-support.patch-old/kernel/futex.c	2005-06-20 11:47:31.000000000 +1000
+++ 404-check-mounts-support.patch-new/kernel/futex.c	2005-07-04 23:14:19.000000000 +1000
@@ -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)
diff -ruNp 404-check-mounts-support.patch-old/mm/shmem.c 404-check-mounts-support.patch-new/mm/shmem.c
--- 404-check-mounts-support.patch-old/mm/shmem.c	2005-06-20 11:47:32.000000000 +1000
+++ 404-check-mounts-support.patch-new/mm/shmem.c	2005-07-04 23:14:19.000000000 +1000
@@ -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;
 
diff -ruNp 404-check-mounts-support.patch-old/mm/tiny-shmem.c 404-check-mounts-support.patch-new/mm/tiny-shmem.c
--- 404-check-mounts-support.patch-old/mm/tiny-shmem.c	2004-12-10 14:26:31.000000000 +1100
+++ 404-check-mounts-support.patch-new/mm/tiny-shmem.c	2005-07-04 23:14:19.000000000 +1000
@@ -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;
diff -ruNp 404-check-mounts-support.patch-old/net/socket.c 404-check-mounts-support.patch-new/net/socket.c
--- 404-check-mounts-support.patch-old/net/socket.c	2005-06-20 11:47:34.000000000 +1000
+++ 404-check-mounts-support.patch-new/net/socket.c	2005-07-04 23:14:19.000000000 +1000
@@ -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)
 {
diff -ruNp 404-check-mounts-support.patch-old/net/sunrpc/rpc_pipe.c 404-check-mounts-support.patch-new/net/sunrpc/rpc_pipe.c
--- 404-check-mounts-support.patch-old/net/sunrpc/rpc_pipe.c	2005-02-03 22:33:53.000000000 +1100
+++ 404-check-mounts-support.patch-new/net/sunrpc/rpc_pipe.c	2005-07-04 23:14:19.000000000 +1000
@@ -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
diff -ruNp 404-check-mounts-support.patch-old/security/selinux/selinuxfs.c 404-check-mounts-support.patch-new/security/selinux/selinuxfs.c
--- 404-check-mounts-support.patch-old/security/selinux/selinuxfs.c	2005-06-20 11:47:35.000000000 +1000
+++ 404-check-mounts-support.patch-new/security/selinux/selinuxfs.c	2005-07-04 23:14:19.000000000 +1000
@@ -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;


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [10/48] Suspend2 2.1.9.8 for 2.6.12: 360-reset-kswapd-max-order-after-resume.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (6 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [8/48] Suspend2 2.1.9.8 for 2.6.12: 353-disable-highmem-tlb-flush-for-copyback.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 23:09   ` Christoph Hellwig
  2005-07-06  2:20 ` [PATCH] [13/48] Suspend2 2.1.9.8 for 2.6.12: 403-debug-pagealloc-support.patch Nigel Cunningham
                   ` (43 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 401-e820-table-support.patch-old/arch/i386/mm/init.c 401-e820-table-support.patch-new/arch/i386/mm/init.c
--- 401-e820-table-support.patch-old/arch/i386/mm/init.c	2005-06-20 11:46:43.000000000 +1000
+++ 401-e820-table-support.patch-new/arch/i386/mm/init.c	2005-07-04 23:14:18.000000000 +1000
@@ -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++;
diff -ruNp 401-e820-table-support.patch-old/mm/bootmem.c 401-e820-table-support.patch-new/mm/bootmem.c
--- 401-e820-table-support.patch-old/mm/bootmem.c	2005-02-03 22:33:50.000000000 +1100
+++ 401-e820-table-support.patch-new/mm/bootmem.c	2005-07-04 23:14:18.000000000 +1000
@@ -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);
 	}


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [9/48] Suspend2 2.1.9.8 for 2.6.12: 354-disable-mce-checking-during-suspend-avoid-smp-deadlock.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (8 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [13/48] Suspend2 2.1.9.8 for 2.6.12: 403-debug-pagealloc-support.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-09 11:49   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [14/48] Suspend2 2.1.9.8 for 2.6.12: 404-check-mounts-support.patch Nigel Cunningham
                   ` (41 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

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
--- 360-reset-kswapd-max-order-after-resume.patch-old/mm/vmscan.c	2005-07-06 11:18:05.000000000 +1000
+++ 360-reset-kswapd-max-order-after-resume.patch-new/mm/vmscan.c	2005-07-04 23:14:20.000000000 +1000
@@ -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;


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [18/48] Suspend2 2.1.9.8 for 2.6.12: 501-tlb-flushing-functions.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (16 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [21/48] Suspend2 2.1.9.8 for 2.6.12: 550-documentation.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-09 11:52   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [16/48] Suspend2 2.1.9.8 for 2.6.12: 406-dynamic-pageflags.patch Nigel Cunningham
                   ` (33 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 510-version-specific-mac.patch-old/arch/ppc/Kconfig 510-version-specific-mac.patch-new/arch/ppc/Kconfig
--- 510-version-specific-mac.patch-old/arch/ppc/Kconfig	2005-06-20 11:46:44.000000000 +1000
+++ 510-version-specific-mac.patch-new/arch/ppc/Kconfig	2005-07-04 23:14:19.000000000 +1000
@@ -1081,7 +1081,7 @@ config PROC_HARDWARE
 
 source "drivers/zorro/Kconfig"
 
-source kernel/power/Kconfig
+source "kernel/power/Kconfig"
 
 endmenu
 
diff -ruNp 510-version-specific-mac.patch-old/arch/ppc/kernel/signal.c 510-version-specific-mac.patch-new/arch/ppc/kernel/signal.c
--- 510-version-specific-mac.patch-old/arch/ppc/kernel/signal.c	2005-07-06 11:25:14.000000000 +1000
+++ 510-version-specific-mac.patch-new/arch/ppc/kernel/signal.c	2005-07-04 23:14:19.000000000 +1000
@@ -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;
 
diff -ruNp 510-version-specific-mac.patch-old/arch/ppc/kernel/swsusp.c 510-version-specific-mac.patch-new/arch/ppc/kernel/swsusp.c
--- 510-version-specific-mac.patch-old/arch/ppc/kernel/swsusp.c	1970-01-01 10:00:00.000000000 +1000
+++ 510-version-specific-mac.patch-new/arch/ppc/kernel/swsusp.c	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,88 @@
+/*
+ * Written by Hu Gang (hugang@soulinfo.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/sysrq.h>
+#include <linux/proc_fs.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <asm/mmu_context.h>
+#include <asm/uaccess.h>
+#include <asm/suspend.h>
+
+#include "cpu_context.h"
+
+extern suspend_pagedir_t *pagedir_nosave __nosavedata;
+extern int nr_copy_pages __nosavedata;
+
+extern asmlinkage int swsusp_save(void);
+
+static void inline do_swsusp_copyback(void)
+{
+	register int i = 0; 
+	
+	for (i = 0; i < nr_copy_pages; i++) {
+		register int loop;
+		register unsigned long *orig, *copy;
+		
+		copy = (unsigned long *)pagedir_nosave[i].address;
+		orig = (unsigned long *)pagedir_nosave[i].orig_address;
+		
+		for (loop = 0; 
+		     loop < (PAGE_SIZE / sizeof(unsigned long));
+		     loop ++)
+			*(orig + loop) = *(copy + loop);
+	}
+}
+
+static struct saved_context swsusp_saved_context;
+
+void save_processor_state(void)
+{
+	__save_processor_state(&swsusp_saved_context);
+}
+
+void restore_processor_state(void)
+{
+	__restore_processor_state(&swsusp_saved_context);
+}
+
+void __flush_tlb_global(void)
+{
+	/* do nothing */
+}
+
+static struct saved_context saved_context;
+
+void swsusp_arch_suspend(void)
+{
+	save_context();
+	__save_processor_state(&saved_context);
+	swsusp_save();
+}
+
+void swsusp_arch_resume(void)
+{
+	save_context();
+	do_swsusp_copyback();
+	__restore_processor_state(&saved_context);
+	restore_context();
+}
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
--- 510-version-specific-mac.patch-old/arch/ppc/kernel/vmlinux.lds.S	2005-06-20 11:46:45.000000000 +1000
+++ 510-version-specific-mac.patch-new/arch/ppc/kernel/vmlinux.lds.S	2005-07-04 23:14:19.000000000 +1000
@@ -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) }
 
diff -ruNp 510-version-specific-mac.patch-old/arch/ppc/mm/init.c 510-version-specific-mac.patch-new/arch/ppc/mm/init.c
--- 510-version-specific-mac.patch-old/arch/ppc/mm/init.c	2005-06-20 11:46:45.000000000 +1000
+++ 510-version-specific-mac.patch-new/arch/ppc/mm/init.c	2005-07-04 23:14:19.000000000 +1000
@@ -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);
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
--- 510-version-specific-mac.patch-old/arch/ppc/platforms/pmac_feature.c	2005-06-20 11:46:45.000000000 +1000
+++ 510-version-specific-mac.patch-new/arch/ppc/platforms/pmac_feature.c	2005-07-04 23:14:19.000000000 +1000
@@ -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,
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
--- 510-version-specific-mac.patch-old/arch/ppc/syslib/of_device.c	2004-11-03 21:55:03.000000000 +1100
+++ 510-version-specific-mac.patch-new/arch/ppc/syslib/of_device.c	2005-07-04 23:14:19.000000000 +1000
@@ -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);
diff -ruNp 510-version-specific-mac.patch-old/drivers/macintosh/Kconfig 510-version-specific-mac.patch-new/drivers/macintosh/Kconfig
--- 510-version-specific-mac.patch-old/drivers/macintosh/Kconfig	2005-06-20 11:46:55.000000000 +1000
+++ 510-version-specific-mac.patch-new/drivers/macintosh/Kconfig	2005-07-04 23:14:19.000000000 +1000
@@ -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
diff -ruNp 510-version-specific-mac.patch-old/drivers/macintosh/via-pmu.c 510-version-specific-mac.patch-new/drivers/macintosh/via-pmu.c
--- 510-version-specific-mac.patch-old/drivers/macintosh/via-pmu.c	2005-07-06 11:25:14.000000000 +1000
+++ 510-version-specific-mac.patch-new/drivers/macintosh/via-pmu.c	2005-07-04 23:14:19.000000000 +1000
@@ -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:
diff -ruNp 510-version-specific-mac.patch-old/include/asm-ppc/cpu_context.h 510-version-specific-mac.patch-new/include/asm-ppc/cpu_context.h
--- 510-version-specific-mac.patch-old/include/asm-ppc/cpu_context.h	1970-01-01 10:00:00.000000000 +1000
+++ 510-version-specific-mac.patch-new/include/asm-ppc/cpu_context.h	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,98 @@
+/*
+ * Written by Hu Gang (hugang@soulinfo.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* image of the saved processor states */
+struct saved_context {
+	u32 lr, cr, sp, r2;
+	u32 r[20]; /* r12 - r31 */                                                 
+	u32 sprg[4];
+	u32 msr, sdr1, tb1, tb2;
+} __attribute__((packed));
+
+inline static void __save_processor_state(struct saved_context *s)
+{
+	/*asm volatile ("mflr 0; stw 0,%0" : "=m" (s->lr));*/
+	asm volatile ("mfcr 0; stw 0,%0" : "=m" (s->cr));
+	asm volatile ("stw 1,%0" : "=m" (s->sp));
+	asm volatile ("stw 2,%0" : "=m" (s->r2));
+	asm volatile ("stmw 12,%0" : "=m" (s->r));
+
+	/* Save MSR & SDR1 */
+	asm volatile ("mfmsr 4; stw 4,%0" : "=m" (s->msr));
+	asm volatile ("mfsdr1 4; stw 4,%0": "=m" (s->sdr1));
+
+	/* Get a stable timebase and save it */
+	asm volatile ("1:\n"
+		      "mftbu 4;stw 4,%0\n"
+		      "mftb  5;stw 5,%1\n"
+		      "mftbu 3\n"
+		      "cmpw 3,4;\n"
+			  "bne 1b" : 
+			  "=m" (s->tb1),
+			  "=m" (s->tb2));
+		
+	/* Save SPRGs */
+	asm volatile ("mfsprg 4,0; stw 4,%0 " : "=m" (s->sprg[0]));
+	asm volatile ("mfsprg 4,1; stw 4,%0 " : "=m" (s->sprg[1]));
+	asm volatile ("mfsprg 4,2; stw 4,%0 " : "=m" (s->sprg[2]));
+	asm volatile ("mfsprg 4,3; stw 4,%0 " : "=m" (s->sprg[3]));
+}
+
+inline static void __restore_processor_state(struct saved_context *s)
+{
+	/* Restore the BATs, and SDR1 */
+	asm volatile ("lwz 4,%0; mtsdr1 4" : "=m" (s->sdr1));
+	/* asm volatile ("lwz 3,%0" : "=m" (saved_context.msr)); */
+
+	asm volatile ("lwz 4,%0; mtsprg 0,4": "=m" (s->sprg[0]));
+	asm volatile ("lwz 4,%0; mtsprg 1,4": "=m" (s->sprg[1]));
+	asm volatile ("lwz 4,%0; mtsprg 2,4": "=m" (s->sprg[2]));
+	asm volatile ("lwz 4,%0; mtsprg 3,4": "=m" (s->sprg[3]));
+
+	/* Restore TB */
+	asm volatile ("li 3,0; mttbl 3; \n"
+		      "lwz 3,%0\n; lwz 4,%1\n"
+		      "mttbu 3; mttbl 4" :
+		      "=m" (s->tb1),
+		      "=m" (s->tb2));
+
+	/* Restore the callee-saved registers and return */
+	asm volatile ("lmw 12,%0" : "=m" (s->r)); 
+	asm volatile ("lwz 2,%0" : "=m" (s->r2));
+	asm volatile ("lwz 1,%0" : "=m" (s->sp));
+	asm volatile ("lwz 0,%0; mtcr 0" : "=m" (s->cr)); 	
+	/*asm volatile ("lwz 0,%0; mtlr 0" : "=m" (s->lr));*/
+}
+
+static inline void save_context(void)
+{
+	printk("pmu suspend\n");
+	pmu_suspend();
+}
+
+extern void enable_kernel_altivec(void);
+
+static inline void restore_context(void)
+{
+	printk("set context: <%p>\n", current);
+	set_context(current->active_mm->context,
+			current->active_mm->pgd);
+
+	printk("pmu_resume\n");
+	pmu_resume();
+
+#ifdef CONFIG_ALTIVEC
+	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC) {
+		printk("enable altivec\n");
+		enable_kernel_altivec();
+	}
+#endif
+	printk("enable fp\n");
+	enable_kernel_fp();
+}
diff -ruNp 510-version-specific-mac.patch-old/include/asm-ppc/suspend2.h 510-version-specific-mac.patch-new/include/asm-ppc/suspend2.h
--- 510-version-specific-mac.patch-old/include/asm-ppc/suspend2.h	1970-01-01 10:00:00.000000000 +1000
+++ 510-version-specific-mac.patch-new/include/asm-ppc/suspend2.h	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,74 @@
+/*
+ * Written by Hu Gang (hugang@soulinfo.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "asm/cpu_context.h"
+
+static struct saved_context suspend_saved_context;
+
+static inline void suspend2_save_processor_context(void)
+{
+	__save_processor_state(&suspend_saved_context);
+}
+
+static inline void suspend2_restore_processor_context(void)
+{
+	__restore_processor_state(&suspend_saved_context);
+
+	restore_context();
+}
+
+static inline void suspend2_pre_copy(void)
+{
+}
+
+static inline void suspend2_post_copy(void)
+{
+}
+
+static inline void suspend2_pre_copyback(void)
+{
+	save_context();
+}
+
+static inline void suspend2_post_copyback(void)
+{
+}
+
+static inline void suspend2_flush_caches(void)
+{
+}
+
+static unsigned long new_stack_page;
+
+static inline void move_stack_to_nonconflicing_area(void)
+{
+	unsigned long old_stack, src;
+
+	new_stack_page = 
+		suspend2_get_nonconflicting_pages(get_order(THREAD_SIZE));
+
+	BUG_ON(!new_stack_page);
+	
+	local_irq_disable();
+
+	/* geting stack address */
+	asm volatile ("stw %%r1, %0" : "=m" (old_stack));
+
+	src = old_stack & (~(THREAD_SIZE - 1));
+	
+	/* Copy stack */
+	memcpy((void*)new_stack_page, (void*)src, THREAD_SIZE);
+
+	new_stack_page += (old_stack - src);
+
+	/* switch to new stack */
+	asm volatile ("lwz %%r1, %0" : "=m" (new_stack_page));
+	
+	local_irq_enable();
+}
diff -ruNp 510-version-specific-mac.patch-old/kernel/kthread.c 510-version-specific-mac.patch-new/kernel/kthread.c
--- 510-version-specific-mac.patch-old/kernel/kthread.c	2005-07-06 11:25:15.000000000 +1000
+++ 510-version-specific-mac.patch-new/kernel/kthread.c	2005-07-04 23:14:19.000000000 +1000
@@ -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);


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [16/48] Suspend2 2.1.9.8 for 2.6.12: 406-dynamic-pageflags.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (17 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [18/48] Suspend2 2.1.9.8 for 2.6.12: 501-tlb-flushing-functions.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  7:46   ` Shaohua Li
  2005-07-06  2:20 ` [PATCH] [22/48] Suspend2 2.1.9.8 for 2.6.12: 560-Kconfig-and-Makefile-for-suspend2.patch Nigel Cunningham
                   ` (32 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 500-version-specific-i386.patch-old/arch/i386/power/Makefile 500-version-specific-i386.patch-new/arch/i386/power/Makefile
--- 500-version-specific-i386.patch-old/arch/i386/power/Makefile	2004-11-03 21:52:57.000000000 +1100
+++ 500-version-specific-i386.patch-new/arch/i386/power/Makefile	2005-07-04 23:14:19.000000000 +1000
@@ -1,2 +1,2 @@
-obj-$(CONFIG_PM)		+= cpu.o
+obj-$(CONFIG_PM)		+= cpu.o smp.o
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o
diff -ruNp 500-version-specific-i386.patch-old/arch/i386/power/smp.c 500-version-specific-i386.patch-new/arch/i386/power/smp.c
--- 500-version-specific-i386.patch-old/arch/i386/power/smp.c	1970-01-01 10:00:00.000000000 +1000
+++ 500-version-specific-i386.patch-new/arch/i386/power/smp.c	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,84 @@
+//#ifdef CONFIG_SMP
+#include <linux/suspend.h>
+#include <linux/irq.h>
+#include <asm/tlbflush.h>
+#include <asm/suspend2.h>
+
+extern atomic_t suspend_cpu_counter __nosavedata;
+unsigned char * my_saved_context __nosavedata;
+static unsigned long c_loops_per_jiffy_ref[NR_CPUS] __nosavedata;
+
+struct suspend2_saved_context suspend2_saved_contexts[NR_CPUS];
+struct suspend2_saved_context suspend2_saved_context;	/* temporary storage */
+cpumask_t saved_affinity[NR_IRQS];
+
+/*
+ * 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);
+		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();
+	}
+}
+//#endif
diff -ruNp 500-version-specific-i386.patch-old/include/asm-i386/suspend2.h 500-version-specific-i386.patch-new/include/asm-i386/suspend2.h
--- 500-version-specific-i386.patch-old/include/asm-i386/suspend2.h	1970-01-01 10:00:00.000000000 +1000
+++ 500-version-specific-i386.patch-new/include/asm-i386/suspend2.h	2005-07-05 23:56:41.000000000 +1000
@@ -0,0 +1,391 @@
+ /*
+  * Copyright 2003-2005 Nigel Cunningham <nigel@suspend2.net>
+  * Based on code
+  * Copyright 2001-2002 Pavel Machek <pavel@suse.cz>
+  * Based on code
+  * Copyright 2001 Patrick Mochel <mochel@osdl.org>
+  */
+#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 {
+	u32 eax, ebx, ecx, edx;
+	u32 esp, ebp, esi, edi;
+	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;
+	u32 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)
+{
+	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));
+
+	/*
+	 * 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 %%esp, (%0)" : "=m" (suspend2_saved_context.esp));
+	asm volatile ("movl %%eax, (%0)" : "=m" (suspend2_saved_context.eax));
+	asm volatile ("movl %%ebx, (%0)" : "=m" (suspend2_saved_context.ebx));
+	asm volatile ("movl %%ecx, (%0)" : "=m" (suspend2_saved_context.ecx));
+	asm volatile ("movl %%edx, (%0)" : "=m" (suspend2_saved_context.edx));
+	asm volatile ("movl %%ebp, (%0)" : "=m" (suspend2_saved_context.ebp));
+	asm volatile ("movl %%esi, (%0)" : "=m" (suspend2_saved_context.esi));
+	asm volatile ("movl %%edi, (%0)" : "=m" (suspend2_saved_context.edi));
+
+	/*
+	 * segment registers
+	 */
+	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));
+
+	/*
+	 * 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));
+
+	/*
+	 * eflags
+	 */
+	asm volatile ("pushfl ; popl (%0)" : "=m" (suspend2_saved_context.eflags));
+}
+
+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. */
+        per_cpu(cpu_gdt_table,nr)[GDT_ENTRY_TSS].b &= 0xfffffdff;
+
+	load_TR_desc();
+
+	load_LDT(&current->active_mm->context);	/* This does lldt */
+
+	/*
+	 * Now maybe reload the debug registers
+	 */
+	if (current->thread.debugreg[7]){
+                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();
+}
+
+/*
+ * 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 (".align 4");
+	asm volatile ("movw %0, %%ds" :: "r" ((u16)__KERNEL_DS));
+
+
+	/*
+	 * 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, %%es" :: "r" (suspend2_saved_context.es));
+	asm volatile ("movw %0, %%fs" :: "r" (suspend2_saved_context.fs));
+	asm volatile ("movw %0, %%gs" :: "r" (suspend2_saved_context.gs));
+	asm volatile ("movw %0, %%ss" :: "r" (suspend2_saved_context.ss));
+
+	/*
+	 * 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, %%esp" :: "m" (suspend2_saved_context.esp));
+	asm volatile ("movl %0, %%ebp" :: "m" (suspend2_saved_context.ebp));
+	asm volatile ("movl %0, %%eax" :: "m" (suspend2_saved_context.eax));
+	asm volatile ("movl %0, %%ebx" :: "m" (suspend2_saved_context.ebx));
+	asm volatile ("movl %0, %%ecx" :: "m" (suspend2_saved_context.ecx));
+	asm volatile ("movl %0, %%edx" :: "m" (suspend2_saved_context.edx));
+	asm volatile ("movl %0, %%esi" :: "m" (suspend2_saved_context.esi));
+	asm volatile ("movl %0, %%edi" :: "m" (suspend2_saved_context.edi));
+
+	/*
+	 * 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();
+
+	/*
+	 * the flags
+	 */
+	asm volatile ("pushl %0 ; popfl" :: "m" (suspend2_saved_context.eflags));
+
+	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)
+{
+	/* 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)));
+	/* 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
+	
+}
+
+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 500-version-specific-i386.patch-old/include/asm-i386/suspend.h 500-version-specific-i386.patch-new/include/asm-i386/suspend.h
--- 500-version-specific-i386.patch-old/include/asm-i386/suspend.h	2005-06-20 11:47:15.000000000 +1000
+++ 500-version-specific-i386.patch-new/include/asm-i386/suspend.h	2005-07-04 23:14:19.000000000 +1000
@@ -3,6 +3,7 @@
  * Based on code
  * Copyright 2001 Patrick Mochel <mochel@osdl.org>
  */
+#include <linux/errno.h>
 #include <asm/desc.h>
 #include <asm/i387.h>
 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [23/48] Suspend2 2.1.9.8 for 2.6.12: 600-suspend-header.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (14 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [17/48] Suspend2 2.1.9.8 for 2.6.12: 500-version-specific-i386.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  2:20 ` [PATCH] [21/48] Suspend2 2.1.9.8 for 2.6.12: 550-documentation.patch Nigel Cunningham
                   ` (35 subsequent siblings)
  51 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 601-kernel_power_power-header.patch-old/kernel/power/power.h 601-kernel_power_power-header.patch-new/kernel/power/power.h
--- 601-kernel_power_power-header.patch-old/kernel/power/power.h	2005-07-06 11:29:15.000000000 +1000
+++ 601-kernel_power_power-header.patch-new/kernel/power/power.h	2005-07-04 23:14:19.000000000 +1000
@@ -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.


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (19 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [22/48] Suspend2 2.1.9.8 for 2.6.12: 560-Kconfig-and-Makefile-for-suspend2.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  3:49   ` Nigel Cunningham
                     ` (2 more replies)
  2005-07-06  2:20 ` [PATCH] [15/48] Suspend2 2.1.9.8 for 2.6.12: 405-clear-swapfile-bdev-in-swapoff.patch Nigel Cunningham
                   ` (30 subsequent siblings)
  51 siblings, 3 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

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
--- 520-version-specific-x86_64.patch-old/arch/x86_64/kernel/asm-offsets.c	2005-06-20 11:46:49.000000000 +1000
+++ 520-version-specific-x86_64.patch-new/arch/x86_64/kernel/asm-offsets.c	2005-07-04 23:14:19.000000000 +1000
@@ -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
--- 520-version-specific-x86_64.patch-old/arch/x86_64/kernel/Makefile	2005-06-20 11:46:49.000000000 +1000
+++ 520-version-specific-x86_64.patch-new/arch/x86_64/kernel/Makefile	2005-07-04 23:14:19.000000000 +1000
@@ -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
--- 520-version-specific-x86_64.patch-old/arch/x86_64/kernel/suspend.c	2004-11-03 21:53:44.000000000 +1100
+++ 520-version-specific-x86_64.patch-new/arch/x86_64/kernel/suspend.c	2005-07-04 23:14:19.000000000 +1000
@@ -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
--- 520-version-specific-x86_64.patch-old/arch/x86_64/mm/init.c	2005-06-20 11:46:49.000000000 +1000
+++ 520-version-specific-x86_64.patch-new/arch/x86_64/mm/init.c	2005-07-04 23:14:19.000000000 +1000
@@ -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
--- 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend2.h	1970-01-01 10:00:00.000000000 +1000
+++ 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend2.h	2005-07-05 23:56:15.000000000 +1000
@@ -0,0 +1,432 @@
+ /*
+  * Copyright 2005 Nigel Cunningham <nigel@suspend2.net>
+  * Based on code
+  * Copyright 2001-2002 Pavel Machek <pavel@suse.cz>
+  * Based on code
+  * Copyright 2001 Patrick Mochel <mochel@osdl.org>
+  */
+#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
--- 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend.h	2005-06-20 11:47:28.000000000 +1000
+++ 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend.h	2005-07-04 23:14:19.000000000 +1000
@@ -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;


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [20/48] Suspend2 2.1.9.8 for 2.6.12: 520-version-specific-x86_64.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (21 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [15/48] Suspend2 2.1.9.8 for 2.6.12: 405-clear-swapfile-bdev-in-swapoff.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  2:20 ` [PATCH] [31/48] Suspend2 2.1.9.8 for 2.6.12: 608-compression.patch Nigel Cunningham
                   ` (28 subsequent siblings)
  51 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 550-documentation.patch-old/Documentation/kernel-parameters.txt 550-documentation.patch-new/Documentation/kernel-parameters.txt
--- 550-documentation.patch-old/Documentation/kernel-parameters.txt	2005-06-20 11:46:40.000000000 +1000
+++ 550-documentation.patch-new/Documentation/kernel-parameters.txt	2005-07-04 23:14:19.000000000 +1000
@@ -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
diff -ruNp 550-documentation.patch-old/Documentation/power/internals.txt 550-documentation.patch-new/Documentation/power/internals.txt
--- 550-documentation.patch-old/Documentation/power/internals.txt	1970-01-01 10:00:00.000000000 +1000
+++ 550-documentation.patch-new/Documentation/power/internals.txt	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,364 @@
+		Software Suspend 2.0 Internal Documentation.
+				Version 1
+
+1.  Introduction.
+
+    Software Suspend 2.0 is an addition to the Linux Kernel, designed to
+    allow the user to quickly shutdown and quickly boot a computer, without
+    needing to close documents or programs. It is equivalent to the
+    hibernate facility in some laptops. This implementation, however,
+    requires no special BIOS or hardware support.
+
+    The code in these files is based upon the original implementation
+    prepared by Gabor Kuti and additional work by Pavel Machek and a
+    host of others. This code has been substantially reworked by Nigel
+    Cunningham, again with the help and testing of many others, not the
+    least of whom is Michael Frank, At its heart, however, the operation is
+    essentially the same as Gabor's version.
+
+2.  Overview of operation.
+
+    The basic sequence of operations is as follows:
+
+	a. Quiesce all other activity.
+	b. Ensure enough memory and storage space are available, and attempt
+	   to free memory/storage if necessary.
+	c. Allocate the required memory and storage space.
+	d. Write the image.
+	e. Power down.
+
+    There are a number of complicating factors which mean that things are
+    not as simple as the above would imply, however...
+
+    o The activity of each process must be stopped at a point where it will
+    not be holding locks necessary for saving the image, or unexpectedly
+    restart operations due to something like a timeout and thereby make
+    our image inconsistent.
+
+    o It is desirous that we sync outstanding I/O to disk before calculating
+    image statistics. This reduces corruption if one should suspend but
+    then not resume, and also makes later parts of the operation safer (see
+    below).
+
+    o We need to get as close as we can to an atomic copy of the data.
+    Inconsistencies in the image will result inconsistent memory contents at
+    resume time, and thus in instability of the system and/or file system
+    corruption. This would appear to imply a maximum image size of one half of
+    the amount of RAM, but we have a solution... (again, below).
+
+    o In 2.6, we must play nicely with the other suspend-to-disk
+    implementations.
+
+3.  Detailed description of internals.
+
+    a. Quiescing activity.
+
+    Safely quiescing the system is achieved in a number of steps. First, we
+    wait for existing activity to complete, while holding new activity until
+    post-resume. Second, we sync unwritten buffers. Third, we send a
+    'pseudo-signal' to all processes that have not yet entered the
+    'refrigerator' but should be frozen, causing them to be refrigerated.
+
+    Waiting for existing activity to complete is achieved by using hooks at
+    the beginning and end of critical paths in the kernel code. When a process
+    enters a section where it cannot be safely refrigerated, the process flag
+    PF_FRIDGE_WAIT is set from the SWSUSP_ACTIVITY_STARTING macro. In the same
+    routine, at completion of the critical region, a SWSUSP_ACTIVITY_END macro
+    resets the flag. The _STARTING and _ENDING macros also atomically adjust
+    the global counter swsusp_num_active. While the counter is non-zero, 
+    Software Suspend's freezer will wait.
+
+    These macros serve two other additional purposes. Local variables are used
+    to ensure that processes can safely pass through multiple  _STARTING and
+    _ENDING macros, and checks are made to ensure that the freezer is not
+    waiting for activity to finish. If a process wants to start on a critical
+    path when Suspend is waiting for activity to finish, it will be held at the
+    start of the critical path and refrigerated earlier than would normally be
+    the case. It will be allowed to continue operation after the Suspend cycle
+    is finished or aborted.
+
+    A process in a critical path may also have a section where it releases
+    locks and can be safely stopped until post-resume. For these cases, the
+    SWSUSP_ACTIVITY_PAUSING and _RESTARTING macros may be used. They function
+    in a similar manner to the _STARTING and _ENDING macros.
+
+    Finally, we remember that some threads may be necessary for syncing data to
+    storage. These threads have PF_SYNCTHREAD set, and may use the special macro
+    SWSUSP_ACTIVITY_SYNCTHREAD_PAUSING to indicate that Suspend can safely
+    continue, while not themselves entering the refrigerator.
+
+    Once activity is stopped, Suspend will initiate a fsync of all devices.
+    This aims to increase the integrity of the disk state, just in case
+    something should go wrong.
+
+    During the initial stage, Suspend indicates its desire that processes be
+    stopped by setting the FREEZE_NEW_ACTIVITY bit of swsusp_state.  Once the
+    sync is complete, SYNCTHREAD processes no longer need to run. The
+    FREEZE_UNREFRIGERATED bit is now set, causing them to be refrigerated as
+    well, should they attempt to start new activity. (There should be nothing
+    for them to do, but just-in-case).
+
+    Suspend can now put remaining processes in the refrigerator without fear
+    of deadlocking or leaving dirty data unsynced. The refrigerator is a
+    procedure where processes wait until the cycle is complete. While in there,
+    we can be sure that they will not perform activity that will make our
+    image inconsistent. Processes enter the refrigerator either by being
+    caught at one of the previously mentioned hooks, or by receiving a 'pseudo-
+    signal' from Suspend at this stage. I call it a pseudo signal because
+    signal_wake_up is called for the process when it actually hasn't been
+    signalled. A special hook in the signal handler then calls the refrigerator.
+    The refrigerator, in turn, recalculates the signal pending status to
+    ensure no ill effects result.
+
+    Not all processes are refrigerated. The Suspend thread itself, of course,
+    is one such thread. Others are flagged by setting PF_NOFREEZE, usually
+    because they are needed during suspend.
+
+    In 2.4, the dosexec thread (Win4Lin) is treated specially. It does not
+    handle us even pretending to send it a signal. This is worked-around by
+    us adjusting the can_schedule() macro in schedule.c to stop the task from
+    being scheduled during suspend. Ugly, but it works. The 2.6 version of
+    Win4Lin has been made compatible.
+
+    b. Ensure enough memory & storage are available.
+    c. Allocate the required memory and storage space.
+
+    These steps are merged together in the prepare_image function, found in
+    prepare_image.c. The functions are merged because of the cyclical nature
+    of the problem of calculating how much memory and storage is needed. Since
+    the data structures containing the information about the image must
+    themselves take memory and use storage, the amount of memory and storage
+    required changes as we prepare the image. Since the changes are not large,
+    only one or two iterations will be required to achieve a solution.
+
+    d. Write the image.
+
+    We previously mentioned the need to create an atomic copy of the data, and
+    the half-of-memory limitation that is implied in this. This limitation is
+    circumvented by dividing the memory to be saved into two parts, called
+    pagesets.
+
+    Pageset2 contains the page cache - the pages on the active and inactive
+    lists. These pages are saved first and reloaded last. While saving these
+    pages, the swapwriter plugin carefully ensures that the work of writing
+    the pages doesn't make the image inconsistent. Pages added to the LRU
+    lists are immediately shot down, and careful accounting for available
+    memory aids debugging. No atomic copy of these pages needs to be made.
+
+    Writing the image requires memory, of course, and at this point we have
+    also not yet suspended the drivers. To avoid the possibility of remaining
+    activity corrupting the image, we allocate a special memory pool. Calls
+    to __alloc_pages and __free_pages_ok are then diverted to use our memory
+    pool. Pages in the memory pool are saved as part of pageset1 regardless of
+    whether or not they are used.
+
+    Once pageset2 has been saved, we suspend the drivers and save the CPU
+    context before making an atomic copy of pageset1, resuming the drivers
+    and saving the atomic copy. After saving the two pagesets, we just need to
+    save our metadata before powering down.
+
+    Having saved pageset2 pages, we can safely overwrite their contents with
+    the atomic copy of pageset1. This is how we manage to overcome the half of
+    memory limitation. Pageset2 is normally far larger than pageset1, and
+    pageset1 is normally much smaller than half of the memory, with the result
+    that pageset2 pages can be safely overwritten with the atomic copy of
+    pageset1. This is where we need to be careful about syncing, however.
+    Pageset2 will probably contain filesystem meta data. If this is overwritten
+    with pageset1 and then a sync occurs, the filesystem will be corrupted -
+    at least until resume time and another sync of the restored data. Since
+    there is a possibility that the user might not resume or (may it never be!)
+    that suspend might oops, we do our utmost to avoid syncing filesystems after
+    copying pageset1.
+
+    e. Power down.
+
+    Powering down uses standard kernel routines. Prior to this, however, we
+    suspend drivers again, ensuring that write caches are flushed.
+
+4.  The method of writing the image.
+
+    Software Suspend 2.0rc3 and later contain an internal API which is
+    designed to simplify the implementation of new methods of transforming
+    the image to be written and writing the image itself. Prior to rc3,
+    compression support was inlined in the image writing code, and the data
+    structures and code for managing swap were intertwined with the rest of
+    the code. A number of people had expressed interest in implementing
+    image encryption, and alternative methods of storing the image. This
+    internal API makes that possible by implementing 'plugins'.
+
+    A plugin is a single file which encapsulates the functionality needed
+    to transform a pageset of data (encryption or compression, for example),
+    or to write the pageset to a device. The former type of plugin is called
+    a 'page-transformer', the later a 'writer'.
+
+    Plugins are linked together in pipeline fashion. There may be zero or more
+    page transformers in a pipeline, and there is always exactly one writer.
+    The pipeline follows this pattern:
+
+		---------------------------------
+		|     Software Suspend Core     |
+		---------------------------------
+				|
+				|
+		---------------------------------
+		|	Page transformer 1	|
+		---------------------------------
+				|
+				|
+		---------------------------------
+		|	Page transformer 2	|
+		---------------------------------
+				|
+				|
+		---------------------------------
+		|            Writer		|
+		---------------------------------
+
+    During the writing of an image, the core code feeds pages one at a time
+    to the first plugin. This plugin performs whatever transformations it
+    implements on the incoming data, completely consuming the incoming data and
+    feeding output in a similar manner to the next plugin. A plugin may buffer
+    its output.
+
+    During reading, the pipeline works in the reverse direction. The core code
+    calls the first plugin with the address of a buffer which should be filled.
+    (Note that the buffer size is always PAGE_SIZE at this time). This plugin
+    will in turn request data from the next plugin and so on down until the
+    writer is made to read from the stored image.
+
+    Part of definition of the structure of a plugin thus looks like this:
+
+	/* Writing the image proper */
+	int (*write_init) (int stream_number);
+	int (*write_chunk) (char * buffer_start);
+	int (*write_cleanup) (void);
+
+	/* Reading the image proper */
+	int (*read_init) (int stream_number);
+	int (*read_chunk) (char * buffer_start, int sync);
+	int (*read_cleanup) (void);
+
+    It should be noted that the _cleanup routines may be called before the
+    full stream of data has been read or written. While writing the image,
+    the user may (depending upon settings) choose to abort suspending, and
+    if we are in the midst of writing the last portion of the image, a portion
+    of the second pageset may be reread.
+
+    In addition to the above routines for writing the data, all plugins have a
+    number of other routines:
+
+    TYPE indicates whether the plugin is a page transformer or a writer.
+    #define TRANSFORMER_PLUGIN 1
+    #define WRITER_PLUGIN 2
+
+    NAME is the name of the plugin, used in generic messages.
+
+    PLUGIN_LIST is used to link the plugin into the list of all plugins.
+
+    MEMORY_NEEDED returns the number of pages of memory required by the plugin
+    to do its work.
+
+    STORAGE_NEEDED returns the number of pages in the suspend header required
+    to store the plugin's configuration data.
+
+    PRINT_DEBUG_INFO fills a buffer with information to be displayed about the
+    operation or settings of the plugin.
+
+    SAVE_CONFIG_INFO returns a buffer of PAGE_SIZE or smaller (the size is the
+    return code), containing the plugin's configuration info. This information
+    will be written in the image header and restored at resume time. Since this
+    buffer is allocated after the atomic copy of the kernel is made, you don't
+    need to worry about the buffer being freed.
+
+    LOAD_CONFIG_INFO gives the plugin a pointer to the the configuration info
+    which was saved during suspending. Once again, the plugin doesn't need to
+    worry about freeing the buffer. The kernel will be overwritten with the
+    original kernel, so no memory leak will occur.
+
+    OPS contains the operations specific to transformers and writers. These are
+    described below.
+
+    The complete definition of struct swsusp_plugin_ops is:
+
+	struct swsusp_plugin_ops {
+		/* Functions common to transformers and writers */
+		int type;
+		char * name;
+		struct list_head plugin_list;
+		unsigned long (*memory_needed) (void);
+		unsigned long (*storage_needed) (void);
+		int (*print_debug_info) (char * buffer, int size);
+		int (*save_config_info) (char * buffer);
+		void (*load_config_info) (char * buffer, int len);
+	
+		/* Writing the image proper */
+		int (*write_init) (int stream_number);
+		int (*write_chunk) (char * buffer_start);
+		int (*write_cleanup) (void);
+
+		/* Reading the image proper */
+		int (*read_init) (int stream_number);
+		int (*read_chunk) (char * buffer_start, int sync);
+		int (*read_cleanup) (void);
+
+		union {
+			struct swsusp_transformer_ops transformer;
+			struct swsusp_writer_ops writer;
+		} ops;
+	};
+
+
+	The operations specific to transformers are few in number:
+
+	struct swsusp_transformer_ops {
+		int (*expected_compression) (void);
+		struct list_head transformer_list;
+	};
+
+	Expected compression returns the expected ratio between the amount of
+	data sent to this plugin and the amount of data it passes to the next
+	plugin. The value is used by the core code to calculate the amount of
+	space required to write the image. If the ratio is not achieved, the
+	writer will complain when it runs out of space with data still to
+	write, and the core code will abort the suspend.
+
+	transformer_list links together page transformers, in the order in
+	which they register, which is in turn determined by order in the
+	Makefile.
+	
+	There are many more operations specific to a writer:
+
+	struct swsusp_writer_ops {
+
+		long (*storage_available) (void);
+	
+		unsigned long (*storage_allocated) (void);
+		
+		int (*release_storage) (void);
+
+		long (*allocate_header_space) (unsigned long space_requested);
+		int (*allocate_storage) (unsigned long space_requested);
+
+		int (*write_header_init) (void);
+		int (*write_header_chunk) (char * buffer_start, int buffer_size);
+		int (*write_header_cleanup) (void);
+
+		int (*read_header_init) (void);
+		int (*read_header_chunk) (char * buffer_start, int buffer_size);
+		int (*read_header_cleanup) (void);
+
+		int (*prepare_save) (void);
+		int (*post_load) (void);
+
+		int (*parse_image_location) (char * buffer);
+
+		int (*image_exists) (void);
+
+		int (*invalidate_image) (void);
+
+		int (*wait_on_io) (int flush_all);
+
+		struct list_head writer_list;
+	};
+
+	STORAGE_AVAILABLE is 
diff -ruNp 550-documentation.patch-old/Documentation/power/suspend2.txt 550-documentation.patch-new/Documentation/power/suspend2.txt
--- 550-documentation.patch-old/Documentation/power/suspend2.txt	1970-01-01 10:00:00.000000000 +1000
+++ 550-documentation.patch-new/Documentation/power/suspend2.txt	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,631 @@
+	--- Suspend2, version 2.1.9 ---
+
+1.  What is it?
+2.  Why would you want it?
+3.  What do you need to use it?
+4.  How do you use it?
+5.  What do all those entries in /proc/software_suspend do?
+6.  How do you get support?
+7.  I think I've found a bug. What should I do?
+8.  When will XXX be supported?
+9.  How does it work?
+10. Who wrote Suspend2?
+
+1. What is it?
+
+   Imagine you're sitting at your computer, working away. For some reason, you
+   need to turn off your computer for a while - perhaps it's time to go home
+   for the day. When you come back to your computer next, you're going to want
+   to carry on where you left off. Now imagine that you could push a button and
+   have your computer store the contents of its memory to disk and power down.
+   Then, when you next start up your computer, it loads that image back into
+   memory and you can carry on from where you were, just as if you'd never
+   turned the computer off. Far less time to start up, no reopening
+   applications and finding what directory you put that file in yesterday.
+   That's what Suspend2 does.
+
+2. Why would you want it?
+
+   Why wouldn't you want it?
+   
+   Being able to save the state of your system and quickly restore it improves
+   your productivity - you get a useful system in far less time than through
+   the normal boot process.
+   
+3. What do you need to use it?
+
+   a. Kernel Support.
+
+   i) The Suspend2 patch.
+   
+   Suspend2 is part of the Linux Kernel. This version is not part of Linus's
+   2.6 tree at the moment, so you will need to download the kernel source and
+   apply the latest patch. Having done that, enable the appropriate options in
+   make [menu|x]config (under General Setup), compile and install your kernel.
+   Suspend2 works with SMP, Highmem, preemption, x86-32, PPC and mac.
+   x86-64 support is coming.
+
+   Suspend2 patches are available from http://suspend2.net.
+
+   ii) Compression and encryption support.
+
+   As of 2.1.9.2, compression and encryption support are implemented via the
+   cryptoapi. You will therefore want to select any Cryptoapi transforms that
+   you want to use on your image from the Cryptoapi menu while configuring
+   your kernel.
+
+   You can also tell Suspend to write it's image to an encrypted and/or
+   compressed filesystem/swap partition. In that case, you don't need to do
+   anything special for Suspend2 when it comes to kernel configuration.
+
+   iii) Configuring other options.
+
+   While you're configuring your kernel, try to configure as much as possible
+   to build as modules. We recommend this because there are a number of drivers
+   that are still in the process of implementing proper power management
+   support. In those cases, the best way to work around their current lack is
+   to build them as modules and remove the modules while suspending. You might
+   also bug the driver authors to get their support up to speed, or even help!
+
+   b. Storage.
+
+   i) Swap.
+
+   Suspend2 can store the suspend image in your swap partition, a swap file or
+   a combination thereof. Whichever combination you choose, you will probably
+   want to create enough swap space to store the largest image you could have,
+   plus the space you'd normally use for swap. A good rule of thumb would be
+   to calculate the amount of swap you'd want without using Suspend2, and then
+   add the amount of memory you have. This swapspace can be arranged in any way
+   you'd like. It can be in one partition or file, or spread over a number. The
+   only requirement is that they be active when you start a suspend cycle.
+   
+   There is one exception to this requirement. Suspend2 has the ability to turn
+   on one swap file or partition at the start of suspending and turn it back off
+   at the end. If you want to ensure you have enough memory to store a image
+   when your memory is fully used, you might want to make one swap partition or
+   file for 'normal' use, and another for Suspend2 to activate & deactivate
+   automatically. (Further details below).
+
+   ii) Normal files.
+
+   As of 2.1.8.5, Suspend2 includes a 'filewriter'. The filewriter can store
+   your image in a simple file. Since Linux has the idea of everything being
+   a file, this is more powerful than it initially sounds. If, for example,
+   you were to set up a network block device file, you could suspend to a
+   network server. This has been tested and works to a point, but nbd itself
+   isn't stateless enough for our purposes.
+
+   Take extra care when setting up the filewriter. If you just type commands
+   without thinking and then try to suspend, you could cause irreversible
+   corruption on your filesystems! Make sure you have backups. Also, because
+   the filewriter is comparatively new, it's not as well tested as the
+   swapwriter. Be aware that there may be bugs that could cause damage to your
+   data even if you are careful! You have been warned!
+
+   Most people will only want to suspend to a local file. To achieve that, do
+   something along the lines of:
+
+   echo Suspend2 > /suspend-file
+   dd if=/dev/zero bs=1M count=512 >> suspend-file
+
+   This will create a 512MB file called /suspend-file. To get Suspend2 to use
+   it:
+
+   echo /suspend-file > /proc/software_suspend/filewriter_target
+
+   Then
+
+   cat /proc/software_suspend/resume2
+
+   Put the results of this into your bootloader's configuration (see also step
+   C, below:
+
+   ---EXAMPLE-ONLY-DON'T-COPY-AND-PASTE---
+   # cat /proc/software_suspend/resume2
+   file:/dev/hda2:0x1e001
+   
+   In this example, we would edit the append= line of our lilo.conf|menu.lst
+   so that it included:
+
+   resume2=file:/dev/hda2:0x1e001
+   ---EXAMPLE-ONLY-DON'T-COPY-AND-PASTE---
+ 
+   For those who are thinking 'Could I make the file sparse?', the answer is
+   'No!'. At the moment, there is no way for Suspend2 to fill in the holes in
+   a sparse file while suspending. In the longer term (post merge!), I'd like
+   to change things so that the file could be dynamically resized as needed.
+   Right now, however, that's not possible.
+
+   c. Bootloader configuration.
+   
+   Using Suspend2 also requires that you add an extra parameter to 
+   your lilo.conf or equivalent. Here's an example for a swap partition:
+
+   append="resume2=swap:/dev/hda1"
+
+   This would tell Suspend2 that /dev/hda1 is a swap partition you 
+   have. Suspend2 will use the swap signature of this partition as a
+   pointer to your data when you suspend. This means that (in this example)
+   /dev/hda1 doesn't need to be _the_ swap partition where all of your data
+   is actually stored. It just needs to be a swap partition that has a
+   valid signature.
+
+   You don't need to have a swap partition for this purpose. Suspend2
+   can also use a swap file, but usage is a little more complex. Having made
+   your swap file, turn it on and do 
+
+   cat /proc/software_suspend/header_locations
+
+   (this assumes you've already compiled your kernel with Suspend2
+   support and booted it). The results of the cat command will tell you
+   what you need to put in lilo.conf:
+
+   For swap partitions like /dev/hda1, simply use resume2=/dev/hda1.
+   For swapfile `swapfile`, use resume2=swap:/dev/hda2:0x242d@4096.
+
+   If the swapfile changes for any reason (it is moved to a different
+   location, it is deleted and recreated, or the filesystem is
+   defragmented) then you will have to check
+   /proc/software_suspend/header_locations for a new resume_block value.
+
+   Once you've compiled and installed the kernel, adjusted your lilo.conf
+   and rerun lilo, you should only need to reboot for the most basic part
+   of Suspend2 to be ready.
+
+   If you only compile in the swapwriter, or only compile in the filewriter,
+   you don't need to add the "swap:" part of the resume2= parameters above.
+   resume2=/dev/hda2:0x242d@4096 will work just as well.
+
+   d. The hibernate script.
+
+   Since the driver model in 2.6 kernels is still being developed, you may need
+   to do more, however. Users of Suspend2 usually start the process via a script
+   which prepares for the suspend, tells the kernel to do its stuff and then
+   restore things afterwards. This script might involve:
+
+   - Switching to a text console and back if X doesn't like the video card
+     status on resume.
+   - Un/reloading PCMCIA support since it doesn't play well with suspend.
+  
+   Note that you might not be able to unload some drivers if there are 
+   processes using them. You might have to kill off processes that hold
+   devices open. Hint: if your X server accesses an USB mouse, doing a
+   'chvt' to a text console releases the device and you can unload the
+   module.
+
+   Check out the latest script (available on suspend2.net).
+   
+4. How do you use it?
+
+   Once your script is properly set up, you should just be able to start it
+   and everything should go like clockwork. Of course things aren't always
+   that easy out of the box.
+
+   Check out (in the kernel source tree) include/linux/suspend2.h for
+   settings you can use to get detailed information about what suspend is doing.
+   The kernel parameters suspend_act, suspend_dbg and suspend_lvl allow you to
+   set the action and debugging parameters prior to starting a suspend and/or
+   at the lilo prompt before resuming. There is also a nice little program that
+   should be available from suspend2.net which makes it easier to turn these
+   debugging settings on and off. Note that to get any debugging output, you
+   need to enable CONFIG_PM_DEBUG when compiling the kernel.
+
+   A neat feature of Suspend2 is that you can press Escape at any time
+   during suspending, and the process will be aborted.
+   
+   Due to the way suspend works, this means you'll have your system back and
+   perfectly usable almost instantly. The only exception is when it's at
+   the very end of writing the image. Then it will need to reload a small
+   (usually 4-50MBs, depending upon the image characteristics) portion first.
+
+   If you run into problems with resuming, adding the "noresume2" option to
+   the kernel command line will let you skip the resume step and recover your
+   system.
+
+5. What do all those entries in /proc/software_suspend do?
+
+   /proc/software_suspend is the directory which contains files you can use to
+   tune and configure Suspend2 to your liking. The exact contents of
+   the directory will depend upon the version of Suspend2 you're
+   running and the options you selected at compile time. In the following
+   descriptions, names in brackets refer to compile time options.
+   (Note that they're all dependant upon you having selected CONFIG_SUSPEND2
+   in the first place!)
+
+   Since the values of these settings can open potential security risks, they
+   are usually accessible only to the root user. You can, however, enable a
+   compile time option which makes all of these files world-accessible. This
+   should only be done if you trust everyone with shell access to this
+   computer!
+  
+   - all_settings:
+
+   This file provides a convenient way to save and restore all of the other
+   settings in one hit. The contents include binary data, so you'll want to
+   redirect the output to a file:
+
+   cat /proc/software_suspend/all_settings > /etc/hibernate/all_settings.conf
+
+   cat /etc/hibernate/all_settings.conf > /proc/software_suspend/all_settings
+
+   - debug_info:
+  
+   This file returns information about your configuration that may be helpful
+   in diagnosing problems with suspending.
+
+   - debug_sections (CONFIG_PM_DEBUG):
+
+   This value, together with the console log level, controls what debugging
+   information is displayed. The console log level determines the level of
+   detail, and this value determines what detail is displayed. This value is
+   a bit vector, and the meaning of the bits can be found in the kernel tree
+   in include/linux/suspend2.h. It can be overridden using the kernel's
+   command line option suspend_dbg.
+
+   - default_console_level (CONFIG_PM_DEBUG):
+
+   This determines the value of the console log level at the start of a
+   suspend cycle. If debugging is compiled in, the console log level can be
+   changed during a cycle by pressing the digit keys. Meanings are:
+
+   0: Nice display.
+   1: Nice display plus numerical progress.
+   2: Errors only.
+   3: Low level debugging info.
+   4: Medium level debugging info.
+   5: High level debugging info.
+   6: Verbose debugging info.
+
+   This value can be overridden using the kernel command line option 
+   suspend_lvl.
+
+   - disable_*
+
+   This option can be used to temporarily disable various parts of suspend.
+   Note that these flags can be set by restoring all_settings: If the saved
+   settings don't include any information about how a part of suspend should
+   be configured, that section will be disabled.
+
+   - do_resume:
+
+   When anything is written to this file suspend will attempt to read and
+   restore an image. If there is no image, it will return almost immediately.
+   If an image exists, the echo > will never return. Instead, the original
+   kernel context will be restored and the original echo > do_suspend will
+   return.
+
+   - do_suspend:
+
+   When anything is written to this file, the kernel side of Suspend2 will
+   begin to attempt to write an image to disk and power down. You'll normally
+   want to run the hibernate script instead, to get modules unloaded first.
+
+   - enable_escape:
+
+   Setting this to "1" will enable you abort a suspend by
+   pressing escape, "0" (default) disables this feature. Note that enabling
+   this option means that you cannot initiate a suspend and then walk away
+   from your computer, expecting it to be secure. With feature disabled,
+   you can validly have this expectation once Suspend begins to write the
+   image to disk. (Prior to this point, it is possible that Suspend might
+   about because of failure to freeze all processes or because constraints
+   on its ability to save the image are not met).
+
+   - expected_compression:
+
+   These values allow you to set an expected compression ratio, which Software
+   Suspend will use in calculating whether it meets constraints on the image
+   size. If this expected compression ratio is not attained, the suspend will
+   abort, so it is wise to allow some spare. You can see what compression
+   ratio is achieved in the logs after suspending.
+
+   - filewriter_target:
+
+   Read this value to get the current setting. Write to it to point Suspend
+   at a new storage location for the filewriter. See above for details of how
+   to set up the filewriter.
+
+   - header_locations:
+
+   This option tells you the resume2= options to use for swap devices you
+   currently have activated. It is particularly useful when you only want to
+   use a swap file to store your image. See above for further details.
+
+   - image_exists:
+
+   Can be used in a script to determine whether a valid image exists at the
+   location currently pointed to by resume2=.  Echoing anything to this entry
+   removes any current image.
+
+   - image_size_limit:
+
+   The maximum size of suspend image written to disk, measured in megabytes
+   (1024*1024).
+
+   - interface_version:
+
+   The value returned by this file can be used by scripts and configuration
+   tools to determine what entries should be looked for. The value is
+   incremented whenever an entry in /proc/software_suspend is obsoleted or 
+   added.
+
+   - last_result:
+
+   The result of the last suspend, as defined in
+   include/linux/suspend-debug.h with the values SUSPEND_ABORTED to
+   SUSPEND_KEPT_IMAGE. This is a bitmask.
+
+   - log_everything (CONFIG_PM_DEBUG):
+
+   Setting this option results in all messages printed being logged. Normally,
+   only a subset are logged, so as to not slow the process and not clutter the
+   logs. Useful for debugging. It can be toggled during a cycle by pressing
+   'L'.
+
+   - pause_between_steps (CONFIG_PM_DEBUG):
+
+   This option is used during debugging, to make Suspend2 pause between
+   each step of the process. It is ignored when the nice display is on.
+
+   - powerdown_method:
+
+   Used to select a method by which Suspend2 should powerdown after writing the
+   image. Currently:
+
+   3: Attempt to enter Suspend-to-ram.
+   4: Attempt to enter ACPI S4 mode.
+   5: Normal power down.
+
+   Note that these options are highly dependant upon your hardware & software.
+
+   - progressbar_granularity_limit:
+
+   This option can be used to limit the granularity of the progress bar
+   displayed with a bootsplash screen. The value is the maximum number of
+   steps. That is, 10 will make the progress bar jump in 10% increments.
+
+   - reboot:
+
+   This option causes Suspend2 to reboot rather than powering down
+   at the end of saving an image. It can be toggled during a cycle by pressing
+   'R'.
+
+   - resume_commandline:
+
+   This entry can be read after resuming to see the commandline that was used
+   when resuming began. You might use this to set up two bootloader entries
+   that are the same apart from the fact that one includes a extra append=
+   argument "at_work=1". You could then grep resume_commandline in your
+   post-resume scripts and configure networking (for example) differently
+   depending upon whether you're at home or work. resume_commandline can be
+   set to arbitrary text if you wish to remove sensitive contents.
+
+   - swapfile:
+
+   This entry is used to specify the swapfile or partition that
+   Suspend2 will attempt to swapon/swapoff automatically. Thus, if
+   I normally use /dev/hda1 for swap, and want to use /dev/hda2 for specifically
+   for my suspend image, I would
+  
+   echo /dev/hda2 > /proc/software_suspend/swapfile
+
+   /dev/hda2 would then be automatically swapon'd and swapoff'd. Note that the
+   swapon and swapoff occur while other processes are frozen (including kswapd)
+   so this swap file will not be used up when attempting to free memory. The
+   parition/file is also given the highest priority, so other swapfiles/partitions
+   will only be used to save the image when this one is filled.
+
+   The value of this file is used by header_locations along with any currently
+   activated swapfiles/partitions.
+
+   - toggle_process_nofreeze
+
+   This entry can be used to toggle the NOFREEZE flag on a process, to allow it
+   to run during Suspending. It should be used with extreme caution. There are
+   strict limitations on what a process running during suspend can do. This is
+   really only intended for use by Suspend's helpers (userui in particular).
+
+   - userui_program
+
+   This entry is used to tell Suspend what userspace program to use for
+   providing a user interface while suspending. The program uses a netlink
+   socket to pass messages back and forward to the kernel, allowing all of the
+   functions formerly implemented in the kernel user interface components.
+
+   - version:
+  
+   The version of suspend you have compiled into the currently running kernel.
+
+6. How do you get support?
+
+   Glad you asked. Suspend2 is being actively maintained and supported
+   by Nigel (the guy doing most of the kernel coding at the moment), Bernard
+   (who maintains the hibernate script and userspace user interface components)
+   and its users.
+
+   Resources availble include HowTos, FAQs and a Wiki, all available via
+   suspend2.net.  You can find the mailing lists there.
+
+7. I think I've found a bug. What should I do?
+
+   By far and a way, the most common problems people have with suspend2
+   related to drivers not having adequate power management support. In this
+   case, it is not a bug with suspend2, but we can still help you. As we
+   mentioned above, such issues can usually be worked around by building the
+   functionality as modules and unloading them while suspending. Please visit
+   the Wiki for up-to-date lists of known issues and work arounds.
+
+   If this information doesn't help, try running:
+
+   hibernate --bug-report
+
+   ..and sending the output to the users mailing list.
+
+   Good information on how to provide us with useful information from an
+   oops is found in the file REPORTING-BUGS, in the top level directory
+   of the kernel tree. If you get an oops, please especially note the
+   information about running what is printed on the screen through ksymoops.
+   The raw information is useless.
+
+8. When will XXX be supported?
+
+   Suspend2 currently lacks support for x86-64. It is work in progress, but
+   hasn't been made a great priority because debugging is difficult (Nigel
+   doesn't have access to the hardware). 64GB Highmem and discontig-mem are
+   also not supported at the moment.
+
+   Patches for the other items (and anything that's been missed) are welcome. 
+   Please send to the list.
+
+9. How does it work?
+
+   Suspend2 does its work in a number of steps.
+
+   a. Freezing system activity.
+
+   The first main stage in suspending is to stop all other activity. This is
+   achieved in stages. Processes are considered in fours groups, which we will
+   describe in reverse order for clarity's sake: Threads with the PF_NOFREEZE
+   flag, kernel threads without this flag, userspace processes with the
+   PF_SYNCTHREAD flag and all other processes. The first set (PF_NOFREEZE) are
+   untouched by the refrigerator code. They are allowed to run during suspending
+   and resuming, and are used to support user interaction, storage access or the
+   like. Other kernel threads (those unneeded while suspending) are frozen last.
+   This leaves us with userspace processes that need to be frozen. When a
+   process enters one of the *_sync system calls, we set a PF_SYNCTHREAD flag on
+   that process for the duration of that call. Processes that have this flag are
+   frozen after processes without it, so that we can seek to ensure that dirty
+   data is synced to disk as quickly as possible in a situation where other
+   processes may be submitting writes at the same time. Freezing the processes
+   that are submitting data stops new I/O from being submitted. Syncthreads can
+   then cleanly finish their work. So the order is:
+
+   - Userspace processes without PF_SYNCTHREAD or PF_NOFREEZE;
+   - Userspace processes with PF_SYNCTHREAD (they won't have NOFREEZE);
+   - Kernel processes without PF_NOFREEZE.
+
+   b. Eating memory.
+
+   For a successful suspend, you need to have enough disk space to store the
+   image and enough memory for the various limitations of Suspend2's
+   algorithm. You can also specify a maximum image size. In order to attain
+   to those constraints, Suspend2 may 'eat' memory. If, after freezing
+   processes, the constraints aren't met, Suspend2 will thaw all the
+   other processes and begin to eat memory until its calculations indicate
+   the constraints are met. It will then freeze processes again and recheck
+   its calculations.
+
+   c. Allocation of storage.
+
+   Next, Suspend2 allocates the storage that will be used to save
+   the image.
+
+   The core of Suspend2 knows nothing about how or where pages are stored. We
+   therefore request the active writer (remember you might have compiled in
+   more than one!) to allocate enough storage for our expect image size. If
+   this request cannot be fulfilled, we eat more memory and try again. If it
+   is fulfiled, we seek to allocate additional storage, just in case our
+   expected compression ratio (if any) isn't achieved. This time, however, we
+   just continue if we can't allocate enough storage.
+
+   If these calls to our writer change the characteristics of the image such
+   that we haven't allocated enough memory, we also loop. (The writer may well
+   need to allocate space for its storage information).
+
+   d. Write the first part of the image.
+
+   Suspend2 stores the image in two sets of pages called 'pagesets'.
+   Pageset 2 contains pages on the active and inactive lists; essentially
+   the page cache. Pageset 1 contains all other pages, including the kernel.
+   We use two pagesets for one important reason: We need to make an atomic copy
+   of the kernel to ensure consistency of the image. Without a second pageset,
+   that would limit us to an image that was at most half the amount of memory
+   available. Using two pagesets allows us to store a full image. Since pageset
+   2 pages won't be needed in saving pageset 1, we first save pageset 2 pages.
+   We can then make our atomic copy of the remaining pages using both pageset 2
+   pages and any other pages that are free. While saving both pagesets, we are
+   careful not to corrupt the image. Among other things, we use lowlevel block
+   I/O routines that don't change the pagecache contents.
+
+   The next step, then, is writing pageset 2.
+
+   e. Suspending drivers and storing processor context.
+
+   Having written pageset2, Suspend2 calls the power management functions to
+   notify drivers of the suspend, and saves the processor state in preparation
+   for the atomic copy of memory we are about to make.
+
+   f. Atomic copy.
+
+   At this stage, everything else but the Suspend2 code is halted. Processes
+   are frozen or idling, drivers are quiesced and have stored (ideally and where
+   necessary) their configuration in memory we are about to atomically copy.
+   In our lowlevel architecture specific code, we have saved the CPU state.
+   We can therefore now do our atomic copy before resuming drivers etc.
+
+   g. Save the atomic copy (pageset 1).
+
+   Suspend can then write the atomic copy of the remaining pages. Since we
+   have copied the pages into other locations, we can continue to use the
+   normal block I/O routines without fear of corruption our image.
+
+   f. Save the suspend header.
+
+   Nearly there! We save our settings and other parameters needed for
+   reloading pageset 1 in a 'suspend header'. We also tell our writer to
+   serialise its data at this stage, so that it can reread the image at resume
+   time. Note that the writer can write this data in any format - in the case
+   of the swapwriter, for example, it splits header pages in 4092 byte blocks,
+   using the last four bytes to link pages of data together. This is completely
+   transparent to the core.
+
+   g. Set the image header.
+
+   Finally, we edit the header at our resume2= location. The signature is
+   changed by the writer to reflect the fact that an image exists, and to point
+   to the start of that data if necessary (swapwriter).
+
+   h. Power down.
+
+   Or reboot if we're debugging and the appropriate option is selected.
+
+   Whew!
+
+   Reloading the image.
+   --------------------
+
+   Reloading the image is essentially the reverse of all the above. We load
+   our copy of pageset 1, being careful to choose locations that aren't going
+   to be overwritten as we copy it back (We start very early in the boot
+   process, so there are no other processes to quiesce here). We then copy
+   pageset 1 back to its original location in memory and restore the process
+   context. We are now running with the original kernel. Next, we reload the
+   pageset 2 pages, free the memory and swap used by Suspend2, restore
+   the pageset header and restart processes. Sounds easy in comparison to
+   suspending, doesn't it!
+
+   There is of course more to Suspend2 than this, but this explanation
+   should be a good start. If there's interest, I'll write further
+   documentation on range pages and the low level I/O.
+
+10. Who wrote Suspend2?
+
+   (Answer based on the writings of Florent Chabaud, credits in files and
+   Nigel's limited knowledge; apologies to anyone missed out!)
+
+   The main developers of Suspend2 have been...
+
+   Gabor Kuti
+   Pavel Machek
+   Florent Chabaud
+   Bernard Blackham
+   Nigel Cunningham
+
+   They have been aided in their efforts by a host of hundreds, if not thousands
+   of testers and people who have submitted bug fixes & suggestions. Of special
+   note are the efforts of Michael Frank, who had his computers repetitively
+   suspend and resume for literally tens of thousands of cycles and developed
+   scripts to stress the system and test Suspend2 far beyond the point
+   most of us (Nigel included!) would consider testing. His efforts have
+   contributed as much to Suspend2 as any of the names above.
diff -ruNp 550-documentation.patch-old/Documentation/power/todo.txt 550-documentation.patch-new/Documentation/power/todo.txt
--- 550-documentation.patch-old/Documentation/power/todo.txt	1970-01-01 10:00:00.000000000 +1000
+++ 550-documentation.patch-new/Documentation/power/todo.txt	2005-07-05 23:44:36.000000000 +1000
@@ -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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [22/48] Suspend2 2.1.9.8 for 2.6.12: 560-Kconfig-and-Makefile-for-suspend2.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (18 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [16/48] Suspend2 2.1.9.8 for 2.6.12: 406-dynamic-pageflags.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  2:20 ` [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch Nigel Cunningham
                   ` (31 subsequent siblings)
  51 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 600-suspend-header.patch-old/include/linux/suspend2.h 600-suspend-header.patch-new/include/linux/suspend2.h
--- 600-suspend-header.patch-old/include/linux/suspend2.h	1970-01-01 10:00:00.000000000 +1000
+++ 600-suspend-header.patch-new/include/linux/suspend2.h	2005-07-04 23:14:19.000000000 +1000
@@ -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 */
diff -ruNp 600-suspend-header.patch-old/include/linux/suspend.h 600-suspend-header.patch-new/include/linux/suspend.h
--- 600-suspend-header.patch-old/include/linux/suspend.h	2005-06-20 11:47:30.000000000 +1000
+++ 600-suspend-header.patch-new/include/linux/suspend.h	2005-07-04 23:14:19.000000000 +1000
@@ -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 */


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [21/48] Suspend2 2.1.9.8 for 2.6.12: 550-documentation.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (15 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [23/48] Suspend2 2.1.9.8 for 2.6.12: 600-suspend-header.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  2:20 ` [PATCH] [18/48] Suspend2 2.1.9.8 for 2.6.12: 501-tlb-flushing-functions.patch Nigel Cunningham
                   ` (34 subsequent siblings)
  51 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 560-Kconfig-and-Makefile-for-suspend2.patch-old/kernel/power/Kconfig 560-Kconfig-and-Makefile-for-suspend2.patch-new/kernel/power/Kconfig
--- 560-Kconfig-and-Makefile-for-suspend2.patch-old/kernel/power/Kconfig	2005-02-03 22:33:50.000000000 +1100
+++ 560-Kconfig-and-Makefile-for-suspend2.patch-new/kernel/power/Kconfig	2005-07-04 23:14:19.000000000 +1000
@@ -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.
diff -ruNp 560-Kconfig-and-Makefile-for-suspend2.patch-old/kernel/power/Makefile 560-Kconfig-and-Makefile-for-suspend2.patch-new/kernel/power/Makefile
--- 560-Kconfig-and-Makefile-for-suspend2.patch-old/kernel/power/Makefile	2004-11-03 21:55:05.000000000 +1100
+++ 560-Kconfig-and-Makefile-for-suspend2.patch-new/kernel/power/Makefile	2005-07-04 23:14:19.000000000 +1000
@@ -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
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
--- 560-Kconfig-and-Makefile-for-suspend2.patch-old/kernel/power/suspend2_core/Makefile	1970-01-01 10:00:00.000000000 +1000
+++ 560-Kconfig-and-Makefile-for-suspend2.patch-new/kernel/power/suspend2_core/Makefile	2005-07-04 23:14:19.000000000 +1000
@@ -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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [17/48] Suspend2 2.1.9.8 for 2.6.12: 500-version-specific-i386.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (13 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  3:43   ` YOSHIFUJI Hideaki / 吉藤英明
  2005-07-06  2:20 ` [PATCH] [23/48] Suspend2 2.1.9.8 for 2.6.12: 600-suspend-header.patch Nigel Cunningham
                   ` (36 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 501-tlb-flushing-functions.patch-old/arch/i386/kernel/smp.c 501-tlb-flushing-functions.patch-new/arch/i386/kernel/smp.c
--- 501-tlb-flushing-functions.patch-old/arch/i386/kernel/smp.c	2005-07-06 11:24:23.000000000 +1000
+++ 501-tlb-flushing-functions.patch-new/arch/i386/kernel/smp.c	2005-07-04 23:14:19.000000000 +1000
@@ -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();
 
diff -ruNp 501-tlb-flushing-functions.patch-old/include/asm-i386/tlbflush.h 501-tlb-flushing-functions.patch-new/include/asm-i386/tlbflush.h
--- 501-tlb-flushing-functions.patch-old/include/asm-i386/tlbflush.h	2004-11-03 21:55:01.000000000 +1100
+++ 501-tlb-flushing-functions.patch-new/include/asm-i386/tlbflush.h	2005-07-04 23:14:19.000000000 +1000
@@ -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()
 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [15/48] Suspend2 2.1.9.8 for 2.6.12: 405-clear-swapfile-bdev-in-swapoff.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (20 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  2:20 ` [PATCH] [20/48] Suspend2 2.1.9.8 for 2.6.12: 520-version-specific-x86_64.patch Nigel Cunningham
                   ` (29 subsequent siblings)
  51 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 406-dynamic-pageflags.patch-old/include/linux/dyn_pageflags.h 406-dynamic-pageflags.patch-new/include/linux/dyn_pageflags.h
--- 406-dynamic-pageflags.patch-old/include/linux/dyn_pageflags.h	1970-01-01 10:00:00.000000000 +1000
+++ 406-dynamic-pageflags.patch-new/include/linux/dyn_pageflags.h	2005-07-04 23:14:20.000000000 +1000
@@ -0,0 +1,63 @@
+/*
+ * include/linux/dyn_pageflags.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <ncunningham@cyclades.com>
+ *
+ * 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
diff -ruNp 406-dynamic-pageflags.patch-old/lib/dyn_pageflags.c 406-dynamic-pageflags.patch-new/lib/dyn_pageflags.c
--- 406-dynamic-pageflags.patch-old/lib/dyn_pageflags.c	1970-01-01 10:00:00.000000000 +1000
+++ 406-dynamic-pageflags.patch-new/lib/dyn_pageflags.c	2005-07-04 23:14:20.000000000 +1000
@@ -0,0 +1,78 @@
+/*
+ * lib/dyn_pageflags.c
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <ncunningham@cyclades.com>
+ * 
+ * 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
+ * work under low memory conditions where order 0 might be all
+ * that's available. In their original use (suspend2), it also
+ * lets us save the pages at suspend time, reload and relocate them
+ * as necessary at resume time without much effort.
+ */
+
+#include <linux/module.h>
+#include <linux/dyn_pageflags.h>
+
+/* clear_map
+ *
+ * Description:	Clear an array used to store local page flags.
+ * Arguments:	dyn_pageflags_t:	The pagemap to be cleared.
+ */
+
+void clear_dyn_pageflags(dyn_pageflags_t pagemap)
+{
+	int i = 0;
+	
+	for (i = 0; i < PAGES_PER_BITMAP; i++)
+		memset((pagemap[i]), 0, PAGE_SIZE);
+}
+
+/* allocate_local_pageflags
+ *
+ * Description:	Allocate a bitmap for local page flags.
+ * Arguments:	dyn_pageflags_t *:	Pointer to the bitmap.
+ */
+int allocate_dyn_pageflags(dyn_pageflags_t *pagemap)
+{
+	int i;
+
+	BUG_ON(*pagemap);
+
+	*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 "
+					"dynamic pageflags.");
+			free_dyn_pageflags(pagemap);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/* free_dyn_pageflags
+ *
+ * Description:	Free a dynamically allocated pageflags bitmap.
+ * Arguments:	dyn_pageflags_t *: Pointer to the bitmap being freed.
+ */
+int free_dyn_pageflags(dyn_pageflags_t *pagemap)
+{
+	int i = 0;
+	if (!*pagemap)
+		return 1;
+	
+	for (i = 0; i < PAGES_PER_BITMAP; i++)
+		free_pages((unsigned long) (*pagemap)[i], 0);
+	
+	kfree(*pagemap);
+	*pagemap = NULL;
+	return 0;
+}
diff -ruNp 406-dynamic-pageflags.patch-old/lib/Makefile 406-dynamic-pageflags.patch-new/lib/Makefile
--- 406-dynamic-pageflags.patch-old/lib/Makefile	2005-06-20 11:47:32.000000000 +1000
+++ 406-dynamic-pageflags.patch-new/lib/Makefile	2005-07-04 23:14:20.000000000 +1000
@@ -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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [24/48] Suspend2 2.1.9.8 for 2.6.12: 601-kernel_power_power-header.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (24 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [25/48] Suspend2 2.1.9.8 for 2.6.12: 602-smp.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  3:42   ` Zwane Mwaikambo
  2005-07-06  2:20 ` [PATCH] [32/48] Suspend2 2.1.9.8 for 2.6.12: 609-driver-model.patch Nigel Cunningham
                   ` (25 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 602-smp.patch-old/kernel/power/suspend2_core/smp.c 602-smp.patch-new/kernel/power/suspend2_core/smp.c
--- 602-smp.patch-old/kernel/power/suspend2_core/smp.c	1970-01-01 10:00:00.000000000 +1000
+++ 602-smp.patch-new/kernel/power/suspend2_core/smp.c	2005-07-04 23:14:19.000000000 +1000
@@ -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);
+}
diff -ruNp 602-smp.patch-old/kernel/power/suspend2_core/smp.h 602-smp.patch-new/kernel/power/suspend2_core/smp.h
--- 602-smp.patch-old/kernel/power/suspend2_core/smp.h	1970-01-01 10:00:00.000000000 +1000
+++ 602-smp.patch-new/kernel/power/suspend2_core/smp.h	2005-07-04 23:14:19.000000000 +1000
@@ -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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [26/48] Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (26 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [32/48] Suspend2 2.1.9.8 for 2.6.12: 609-driver-model.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06 10:22   ` Pekka Enberg
  2005-07-09 11:53   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [30/48] Suspend2 2.1.9.8 for 2.6.12: 607-atomic-copy.patch Nigel Cunningham
                   ` (23 subsequent siblings)
  51 siblings, 2 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 604-utility-header.patch-old/kernel/power/suspend2_core/utility.c 604-utility-header.patch-new/kernel/power/suspend2_core/utility.c
--- 604-utility-header.patch-old/kernel/power/suspend2_core/utility.c	1970-01-01 10:00:00.000000000 +1000
+++ 604-utility-header.patch-new/kernel/power/suspend2_core/utility.c	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,46 @@
+/*
+ * kernel/power/utility.c
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ * 
+ * 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
--- 604-utility-header.patch-old/kernel/power/suspend2_core/utility.h	1970-01-01 10:00:00.000000000 +1000
+++ 604-utility-header.patch-new/kernel/power/suspend2_core/utility.h	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,12 @@
+/*
+ * kernel/power/suspend2_core/utility.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ * 
+ * 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, ...);


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [31/48] Suspend2 2.1.9.8 for 2.6.12: 608-compression.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (22 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [20/48] Suspend2 2.1.9.8 for 2.6.12: 520-version-specific-x86_64.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-09 11:55   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [25/48] Suspend2 2.1.9.8 for 2.6.12: 602-smp.patch Nigel Cunningham
                   ` (27 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

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
--- 609-driver-model.patch-old/kernel/power/suspend2_core/driver_model.c	1970-01-01 10:00:00.000000000 +1000
+++ 609-driver-model.patch-new/kernel/power/suspend2_core/driver_model.c	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,95 @@
+/*
+ * kernel/power/suspend2_core/driver_model.c
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * 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;
+	}
+}
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
--- 609-driver-model.patch-old/kernel/power/suspend2_core/driver_model.h	1970-01-01 10:00:00.000000000 +1000
+++ 609-driver-model.patch-new/kernel/power/suspend2_core/driver_model.h	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,24 @@
+/*
+ * kernel/power/driver_model.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * 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);


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [28/48] Suspend2 2.1.9.8 for 2.6.12: 605-kernel_power_suspend.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (30 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [29/48] Suspend2 2.1.9.8 for 2.6.12: 606-all-settings.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 17:58   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [38/48] Suspend2 2.1.9.8 for 2.6.12: 614-plugins.patch Nigel Cunningham
                   ` (19 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

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
--- 606-all-settings.patch-old/kernel/power/suspend2_core/all_settings.c	1970-01-01 10:00:00.000000000 +1000
+++ 606-all-settings.patch-new/kernel/power/suspend2_core/all_settings.c	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,325 @@
+/*
+ * /kernel/power/suspend2_core/all_settings.c
+ *
+ * Suspend2 is released under the GPLv2.
+ * 
+ * Copyright (C) 2002-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * 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);


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [27/48] Suspend2 2.1.9.8 for 2.6.12: 604-utility.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (28 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [30/48] Suspend2 2.1.9.8 for 2.6.12: 607-atomic-copy.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  2:20 ` [PATCH] [29/48] Suspend2 2.1.9.8 for 2.6.12: 606-all-settings.patch Nigel Cunningham
                   ` (21 subsequent siblings)
  51 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 605-kernel_power_suspend-header.patch-old/kernel/power/suspend.h 605-kernel_power_suspend-header.patch-new/kernel/power/suspend.h
--- 605-kernel_power_suspend-header.patch-old/kernel/power/suspend.h	1970-01-01 10:00:00.000000000 +1000
+++ 605-kernel_power_suspend-header.patch-new/kernel/power/suspend.h	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,28 @@
+/*
+ * kernel/power/suspend.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * 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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [30/48] Suspend2 2.1.9.8 for 2.6.12: 607-atomic-copy.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (27 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [26/48] Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 18:01   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [27/48] Suspend2 2.1.9.8 for 2.6.12: 604-utility.patch Nigel Cunningham
                   ` (22 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 608-compression.patch-old/kernel/power/suspend2_core/compression.c 608-compression.patch-new/kernel/power/suspend2_core/compression.c
--- 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	2005-07-05 23:52:59.000000000 +1000
@@ -0,0 +1,636 @@
+/*
+ * kernel/power/suspend2_core/compression.c
+ *
+ * Copyright (C) 2003-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * 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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [29/48] Suspend2 2.1.9.8 for 2.6.12: 606-all-settings.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (29 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [27/48] Suspend2 2.1.9.8 for 2.6.12: 604-utility.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 18:03   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [28/48] Suspend2 2.1.9.8 for 2.6.12: 605-kernel_power_suspend.patch Nigel Cunningham
                   ` (20 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

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
--- 607-atomic-copy.patch-old/kernel/power/suspend2_core/atomic_copy.c	1970-01-01 10:00:00.000000000 +1000
+++ 607-atomic-copy.patch-new/kernel/power/suspend2_core/atomic_copy.c	2005-07-04 23:14:19.000000000 +1000
@@ -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();
+	}
+}
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
--- 607-atomic-copy.patch-old/kernel/power/suspend2_core/atomic_copy.h	1970-01-01 10:00:00.000000000 +1000
+++ 607-atomic-copy.patch-new/kernel/power/suspend2_core/atomic_copy.h	2005-07-04 23:14:19.000000000 +1000
@@ -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);


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [25/48] Suspend2 2.1.9.8 for 2.6.12: 602-smp.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (23 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [31/48] Suspend2 2.1.9.8 for 2.6.12: 608-compression.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06 12:03   ` Pekka Enberg
  2005-07-06  2:20 ` [PATCH] [24/48] Suspend2 2.1.9.8 for 2.6.12: 601-kernel_power_power-header.patch Nigel Cunningham
                   ` (26 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

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
--- 603-suspend2_common-headers.patch-old/kernel/power/suspend2_core/suspend2_common.h	1970-01-01 10:00:00.000000000 +1000
+++ 603-suspend2_common-headers.patch-new/kernel/power/suspend2_core/suspend2_common.h	2005-07-04 23:14:19.000000000 +1000
@@ -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;
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
--- 603-suspend2_common-headers.patch-old/kernel/power/suspend2_core/suspend.h	1970-01-01 10:00:00.000000000 +1000
+++ 603-suspend2_common-headers.patch-new/kernel/power/suspend2_core/suspend.h	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,24 @@
+/*
+ * kernel/power/suspend2.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * 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
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
--- 603-suspend2_common-headers.patch-old/kernel/power/suspend2_core/version.h	1970-01-01 10:00:00.000000000 +1000
+++ 603-suspend2_common-headers.patch-new/kernel/power/suspend2_core/version.h	2005-07-04 23:14:19.000000000 +1000
@@ -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
+


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [32/48] Suspend2 2.1.9.8 for 2.6.12: 609-driver-model.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (25 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [24/48] Suspend2 2.1.9.8 for 2.6.12: 601-kernel_power_power-header.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06 10:10   ` Pekka Enberg
  2005-07-06  2:20 ` [PATCH] [26/48] Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch Nigel Cunningham
                   ` (24 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 610-encryption.patch-old/kernel/power/suspend2_core/encryption.c 610-encryption.patch-new/kernel/power/suspend2_core/encryption.c
--- 610-encryption.patch-old/kernel/power/suspend2_core/encryption.c	1970-01-01 10:00:00.000000000 +1000
+++ 610-encryption.patch-new/kernel/power/suspend2_core/encryption.c	2005-07-05 23:54:31.000000000 +1000
@@ -0,0 +1,598 @@
+/*
+ * kernel/power/suspend2_core/encryption.c
+ *
+ * Copyright (C) 2003-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * 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);


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [36/48] Suspend2 2.1.9.8 for 2.6.12: 612-pagedir.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (34 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [40/48] Suspend2 2.1.9.8 for 2.6.12: 616-prepare_image.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  2:20 ` [PATCH] [34/48] Suspend2 2.1.9.8 for 2.6.12: 610-extent.patch Nigel Cunningham
                   ` (15 subsequent siblings)
  51 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 613-pageflags.patch-old/kernel/power/suspend2_core/pageflags.c 613-pageflags.patch-new/kernel/power/suspend2_core/pageflags.c
--- 613-pageflags.patch-old/kernel/power/suspend2_core/pageflags.c	1970-01-01 10:00:00.000000000 +1000
+++ 613-pageflags.patch-new/kernel/power/suspend2_core/pageflags.c	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,126 @@
+/*
+ * kernel/power/suspend2_core/pageflags.c
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <ncunningham@cyclades.com>
+ * 
+ * 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]));
+}
diff -ruNp 613-pageflags.patch-old/kernel/power/suspend2_core/pageflags.h 613-pageflags.patch-new/kernel/power/suspend2_core/pageflags.h
--- 613-pageflags.patch-old/kernel/power/suspend2_core/pageflags.h	1970-01-01 10:00:00.000000000 +1000
+++ 613-pageflags.patch-new/kernel/power/suspend2_core/pageflags.h	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,84 @@
+/*
+ * kernel/power/pageflags.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Suspend2 needs a few pageflags while working that aren't otherwise
+ * used. To save the struct page pageflags, we dynamically allocate
+ * a bitmap and use that. These are the only non order-0 allocations
+ * we do.
+ *
+ * NOTE!!!
+ * We assume that PAGE_SIZE - sizeof(void *) is a multiple of
+ * sizeof(unsigned long). Is this ever false?
+ */
+
+#include <linux/dyn_pageflags.h>
+#include <linux/suspend.h>
+
+extern dyn_pageflags_t in_use_map;
+extern dyn_pageflags_t allocd_pages_map;
+#ifdef CONFIG_DEBUG_PAGEALLOC
+extern dyn_pageflags_t unmap_map;
+#endif
+extern dyn_pageflags_t	pageset2_map;
+
+/* 
+ * inusemap is used in two ways: 
+ * - During suspend, to tag pages which are not used (to speed up 
+ *   count_data_pages);
+ * - During resume, to tag pages which are in pagedir1. This does not tag 
+ *   pagedir2 pages, so !== first use.
+ */
+#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))
+
+#define PagePageset1(page) \
+	(pageset1_map ? test_bit(PAGEBIT(page), PAGE_UL_PTR(pageset1_map, page)): 0)
+#define SetPagePageset1(page) \
+	set_bit(PAGEBIT(page), PAGE_UL_PTR(pageset1_map, page))
+#define ClearPagePageset1(page) \
+	clear_bit(PAGEBIT(page), PAGE_UL_PTR(pageset1_map, page))
+
+#define PagePageset1Copy(page) \
+	(pageset1_copy_map ? \
+	 test_bit(PAGEBIT(page), PAGE_UL_PTR(pageset1_copy_map, page)): 0)
+#define SetPagePageset1Copy(page) \
+	set_bit(PAGEBIT(page), PAGE_UL_PTR(pageset1_copy_map, page))
+#define ClearPagePageset1Copy(page) \
+	clear_bit(PAGEBIT(page), PAGE_UL_PTR(pageset1_copy_map, page))
+
+#define PagePageset2(page) \
+	(pageset2_map ? \
+	 test_bit(PAGEBIT(page), PAGE_UL_PTR(pageset2_map, page)): 0)
+#define SetPagePageset2(page) \
+	set_bit(PAGEBIT(page), PAGE_UL_PTR(pageset2_map, page))
+#define ClearPagePageset2(page) \
+	clear_bit(PAGEBIT(page), PAGE_UL_PTR(pageset2_map, page))
+
+#define PageAllocd(page)	\
+	test_bit(PAGEBIT(page), PAGE_UL_PTR(allocd_pages_map, page))
+#define SetPageAllocd(page) \
+	set_bit(PAGEBIT(page), PAGE_UL_PTR(allocd_pages_map, page))
+#define ClearPageAllocd(page) \
+	clear_bit(PAGEBIT(page), PAGE_UL_PTR(alloc_pages_map, page))
+
+#define SetPageUnmap(page) \
+	set_bit(PAGEBIT(page), PAGE_UL_PTR(unmap_map, page))
+#define PageUnmap(page) \
+	test_bit(PAGEBIT(page), PAGE_UL_PTR(unmap_map, page))
+
+#define BITMAP_FOR_EACH_SET(bitmap, counter) \
+	for (counter = __get_next_bit_on(bitmap, -1); counter < max_mapnr; \
+		counter = __get_next_bit_on(bitmap, counter))
+
+extern void save_dyn_pageflags(dyn_pageflags_t pagemap);
+extern void load_dyn_pageflags(dyn_pageflags_t pagemap);
+int suspend_allocate_dyn_pageflags(dyn_pageflags_t *pagemap);
+void relocate_dyn_pageflags(dyn_pageflags_t *pagemap);


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [38/48] Suspend2 2.1.9.8 for 2.6.12: 614-plugins.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (31 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [28/48] Suspend2 2.1.9.8 for 2.6.12: 605-kernel_power_suspend.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 18:08   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [35/48] Suspend2 2.1.9.8 for 2.6.12: 611-io.patch Nigel Cunningham
                   ` (18 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 615-poweroff.patch-old/kernel/power/suspend2_core/power_off.c 615-poweroff.patch-new/kernel/power/suspend2_core/power_off.c
--- 615-poweroff.patch-old/kernel/power/suspend2_core/power_off.c	1970-01-01 10:00:00.000000000 +1000
+++ 615-poweroff.patch-new/kernel/power/suspend2_core/power_off.c	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,148 @@
+/*
+ * kernel/power/suspend2_core/power_off.c
+ *
+ * Copyright (C) 2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * 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();
+}
+
diff -ruNp 615-poweroff.patch-old/kernel/power/suspend2_core/power_off.h 615-poweroff.patch-new/kernel/power/suspend2_core/power_off.h
--- 615-poweroff.patch-old/kernel/power/suspend2_core/power_off.h	1970-01-01 10:00:00.000000000 +1000
+++ 615-poweroff.patch-new/kernel/power/suspend2_core/power_off.h	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,13 @@
+/*
+ * kernel/power/suspend2_core/power_off.h
+ *
+ * Copyright (C) 2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * 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;


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [35/48] Suspend2 2.1.9.8 for 2.6.12: 611-io.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (32 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [38/48] Suspend2 2.1.9.8 for 2.6.12: 614-plugins.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 18:12   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [40/48] Suspend2 2.1.9.8 for 2.6.12: 616-prepare_image.patch Nigel Cunningham
                   ` (17 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 612-pagedir.patch-old/kernel/power/suspend2_core/pagedir.c 612-pagedir.patch-new/kernel/power/suspend2_core/pagedir.c
--- 612-pagedir.patch-old/kernel/power/suspend2_core/pagedir.c	1970-01-01 10:00:00.000000000 +1000
+++ 612-pagedir.patch-new/kernel/power/suspend2_core/pagedir.c	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,336 @@
+/*
+ * kernel/power/pagedir.c
+ *
+ * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
+ * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr>
+ * Copyright (C) 2002-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * 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;
+}
diff -ruNp 612-pagedir.patch-old/kernel/power/suspend2_core/pagedir.h 612-pagedir.patch-new/kernel/power/suspend2_core/pagedir.h
--- 612-pagedir.patch-old/kernel/power/suspend2_core/pagedir.h	1970-01-01 10:00:00.000000000 +1000
+++ 612-pagedir.patch-new/kernel/power/suspend2_core/pagedir.h	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,55 @@
+/*
+ * kernel/power/suspend2_core/pagedir.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Declarations for routines for handling pagesets.
+ */
+
+/* Pagedir
+ *
+ * Contains the metadata for a set of pages saved in the image.
+ */
+
+struct pagedir {
+	int pageset_size;
+	int lastpageset_size;
+};
+
+extern struct pagedir pagedir1, pagedir2;
+
+#define pageset1_size (pagedir1.pageset_size)
+#define pageset2_size (pagedir2.pageset_size)
+
+extern void suspend2_copy_pageset1(void);
+
+extern void suspend2_free_pagedir_data(void);
+
+extern int suspend2_allocate_extra_pagedir_memory(struct pagedir * p, int pageset_size, int alloc_from);
+
+extern void suspend2_mark_task_as_pageset1 (struct task_struct *t);
+extern void suspend2_mark_pages_for_pageset2(void);
+
+extern void suspend2_release_conflicting_pages(void);
+extern void suspend2_relocate_page_if_required(void ** page_pointer_addr);
+extern int suspend2_get_pageset1_load_addresses(void);
+
+extern int extra_pagedir_pages_allocated;
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+/* Returns whether it was already in the requested state */
+extern int suspend2_map_kernel_page(struct page * page, int enable);
+
+extern void suspend2_map_atomic_copy_pages(void);
+extern void suspend2_unmap_atomic_copy_pages(void);
+#else
+#define suspend2_map_atomic_copy_pages() do { } while(0)
+#define suspend2_unmap_atomic_copy_pages() do { } while(0)
+static inline int suspend2_map_kernel_page(struct page * page, int enable)
+{
+	return 1;
+}
+#endif
+


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [37/48] Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (36 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [34/48] Suspend2 2.1.9.8 for 2.6.12: 610-extent.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06 12:01   ` Pekka Enberg
  2005-07-09 12:16   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [41/48] Suspend2 2.1.9.8 for 2.6.12: 617-proc.patch Nigel Cunningham
                   ` (13 subsequent siblings)
  51 siblings, 2 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 614-plugins.patch-old/kernel/power/suspend2_core/plugins.c 614-plugins.patch-new/kernel/power/suspend2_core/plugins.c
--- 614-plugins.patch-old/kernel/power/suspend2_core/plugins.c	1970-01-01 10:00:00.000000000 +1000
+++ 614-plugins.patch-new/kernel/power/suspend2_core/plugins.c	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,341 @@
+/*
+ * kernel/power/plugins.c
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ */
+
+#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);
+	}
+}
diff -ruNp 614-plugins.patch-old/kernel/power/suspend2_core/plugins.h 614-plugins.patch-new/kernel/power/suspend2_core/plugins.h
--- 614-plugins.patch-old/kernel/power/suspend2_core/plugins.h	1970-01-01 10:00:00.000000000 +1000
+++ 614-plugins.patch-new/kernel/power/suspend2_core/plugins.h	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,172 @@
+/*
+ * kernel/power/plugin.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ * It contains declarations for plugins. Plugins are additions to
+ * suspend2 that provide facilities such as image compression or
+ * encryption, backends for storage of the image and user interfaces.
+ *
+ */
+
+/* This is the maximum size we store in the image header for a plugin name */
+#define SUSPEND_MAX_PLUGIN_NAME_LENGTH 30
+
+/* Per-plugin metadata */
+struct plugin_header {
+	char name[SUSPEND_MAX_PLUGIN_NAME_LENGTH];
+	int disabled;
+	int type;
+	int index;
+	int data_length;
+	unsigned long signature;
+};
+
+extern int num_plugins, num_writers;
+
+#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
+
+#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);
+
+struct suspend_filter_ops {
+	SUSPEND_COMMON_IO_OPS
+	int (*expected_compression) (void);
+	struct list_head filter_list;
+};
+
+struct suspend_writer_ops {
+	
+	SUSPEND_COMMON_IO_OPS
+
+	/* Calls for allocating storage */
+
+	int (*storage_available) (void); // Maximum size of image we can save
+					  // (incl. space already allocated).
+	
+	int (*storage_allocated) (void);
+					// Amount of storage already allocated
+	int (*release_storage) (void);
+	
+	/* 
+	 * Header space is allocated separately. Note that allocation
+	 * of space for the header might result in allocated space 
+	 * being stolen from the main pool if there is no unallocated
+	 * space. We have to be able to allocate enough space for
+	 * the header. We can eat memory to ensure there is enough
+	 * for the main pool.
+	 */
+	int (*allocate_header_space) (int space_requested);
+	int (*allocate_storage) (int space_requested);
+	
+	/* Read and write the metadata */	
+	int (*write_header_init) (void);
+	int (*write_header_chunk) (char * buffer_start, int buffer_size);
+	int (*write_header_cleanup) (void);
+
+	int (*read_header_init) (void);
+	int (*read_header_chunk) (char * buffer_start, int buffer_size);
+	int (*read_header_cleanup) (void);
+
+	/* Prepare metadata to be saved (relativise/absolutise extents) */
+	int (*serialise_extents) (void);
+	int (*load_extents) (void);
+	
+	/* Attempt to parse an image location */
+	int (*parse_image_location) (char * buffer, int only_writer);
+
+	/* Determine whether image exists that we can restore */
+	int (*image_exists) (void);
+	
+	/* Mark the image as having tried to resume */
+	void (*mark_resume_attempted) (void);
+
+	/* Destroy image if one exists */
+	int (*invalidate_image) (void);
+	
+	/* Wait on I/O */
+	int (*wait_on_io) (int flush_all);
+
+	struct list_head writer_list;
+};
+
+struct suspend_plugin_ops {
+	/* Functions common to all plugins */
+	int type;
+	char * name;
+	struct module * module;
+	int disabled;
+	struct list_head plugin_list;
+
+	/* Bytes! */
+	unsigned long (*memory_needed) (void);
+	unsigned long (*storage_needed) (void);
+
+	int (*print_debug_info) (char * buffer, int size);
+	int (*save_config_info) (char * buffer);
+	void (*load_config_info) (char * buffer, int len);
+	
+	/* Initialise & cleanup - general routines called
+	 * at the start and end of a cycle. */
+	int (*initialise) (int starting_cycle);
+	void (*cleanup) (int finishing_cycle);
+
+	int (*write_init) (int stream_number);
+	int (*write_cleanup) (void);
+
+	int (*read_init) (int stream_number);
+	int (*read_cleanup) (void);
+
+	union {
+		struct suspend_filter_ops filter;
+		struct suspend_writer_ops writer;
+	} ops;
+};
+
+extern struct suspend_plugin_ops * active_writer;
+extern struct list_head suspend_filters, suspend_writers, suspend_plugins;
+
+extern void prepare_console_plugins(void);
+extern void cleanup_console_plugins(void);
+
+extern struct suspend_plugin_ops * find_plugin_given_name(char * name);
+extern struct suspend_plugin_ops * get_next_filter(struct suspend_plugin_ops *);
+
+extern int suspend_register_plugin(struct suspend_plugin_ops * plugin);
+extern void suspend_move_plugin_tail(struct suspend_plugin_ops * plugin);
+
+extern unsigned long header_storage_for_plugins(void);
+extern unsigned long memory_for_plugins(void);
+
+extern int print_plugin_debug_info(char * buffer, int buffer_size);
+extern int suspend_register_plugin(struct suspend_plugin_ops * plugin);
+extern void suspend_unregister_plugin(struct suspend_plugin_ops * plugin);
+
+extern int suspend2_initialise_plugins(int starting_cycle);
+extern void suspend2_cleanup_plugins(int finishing_cycle);
+
+int suspend2_get_modules(void);
+void suspend2_put_modules(void);
+
+static inline void suspend_initialise_plugin_lists(void) {
+	INIT_LIST_HEAD(&suspend_filters);
+	INIT_LIST_HEAD(&suspend_writers);
+	INIT_LIST_HEAD(&suspend_plugins);
+}
+
+extern int expected_compression_ratio(void);


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [40/48] Suspend2 2.1.9.8 for 2.6.12: 616-prepare_image.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (33 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [35/48] Suspend2 2.1.9.8 for 2.6.12: 611-io.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 18:13   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [36/48] Suspend2 2.1.9.8 for 2.6.12: 612-pagedir.patch Nigel Cunningham
                   ` (16 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 617-proc.patch-old/kernel/power/suspend2_core/proc.c 617-proc.patch-new/kernel/power/suspend2_core/proc.c
--- 617-proc.patch-old/kernel/power/suspend2_core/proc.c	1970-01-01 10:00:00.000000000 +1000
+++ 617-proc.patch-new/kernel/power/suspend2_core/proc.c	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,336 @@
+/*
+ * /kernel/power/proc.c
+ *
+ * Copyright (C) 2002-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * 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);
+}
diff -ruNp 617-proc.patch-old/kernel/power/suspend2_core/proc.h 617-proc.patch-new/kernel/power/suspend2_core/proc.h
--- 617-proc.patch-old/kernel/power/suspend2_core/proc.h	1970-01-01 10:00:00.000000000 +1000
+++ 617-proc.patch-new/kernel/power/suspend2_core/proc.h	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,66 @@
+/*
+ * kernel/power/proc.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ * It provides declarations for suspend to use in managing
+ * /proc/software_suspend. When we switch to kobjects,
+ * this will become redundant.
+ *
+ */
+
+#include <linux/proc_fs.h>
+
+struct suspend_proc_data {
+	char * filename;
+	int permissions;
+	int type;
+	union {
+		struct {
+			unsigned long * bit_vector;
+			int bit;
+		} bit;
+		struct {
+			int * variable;
+			int minimum;
+			int maximum;
+		} integer;
+		struct {
+			unsigned long * variable;
+			unsigned long minimum;
+			unsigned long maximum;
+		} ul;
+		struct {
+			char * variable;
+			int max_length;
+		} string;
+		struct {
+			read_proc_t * read_proc;
+			write_proc_t * write_proc;
+			void * data;
+		} special;
+	} data;
+	
+	/* Side effects routines. Used, eg, for reparsing the
+	 * resume2 entry when it changes */
+	void (* read_proc) (void);
+	void (* write_proc) (void); 
+	struct list_head proc_data_list;
+};
+
+#define SUSPEND_PROC_DATA_CUSTOM	0
+#define SUSPEND_PROC_DATA_BIT		1
+#define SUSPEND_PROC_DATA_INTEGER	2
+#define SUSPEND_PROC_DATA_UL		3
+#define SUSPEND_PROC_DATA_STRING	4
+
+#define PROC_WRITEONLY 0200
+#define PROC_READONLY 0400
+#define PROC_RW 0600
+
+struct proc_dir_entry * suspend_register_procfile(
+		struct suspend_proc_data * suspend_proc_data);
+void suspend_unregister_procfile(struct suspend_proc_data * suspend_proc_data);
+


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [33/48] Suspend2 2.1.9.8 for 2.6.12: 610-encryption.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (38 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [41/48] Suspend2 2.1.9.8 for 2.6.12: 617-proc.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 18:15   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [39/48] Suspend2 2.1.9.8 for 2.6.12: 615-poweroff.patch Nigel Cunningham
                   ` (11 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 610-extent.patch-old/kernel/power/suspend2_core/extent.c 610-extent.patch-new/kernel/power/suspend2_core/extent.c
--- 610-extent.patch-old/kernel/power/suspend2_core/extent.c	1970-01-01 10:00:00.000000000 +1000
+++ 610-extent.patch-new/kernel/power/suspend2_core/extent.c	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,206 @@
+/*
+ * kernel/power/suspend2_core/extent.c
+ * 
+ * Suspend2 routines for manipulating extents.
+ *
+ * (C) 2003-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * 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;
+}
diff -ruNp 610-extent.patch-old/kernel/power/suspend2_core/extent.h 610-extent.patch-new/kernel/power/suspend2_core/extent.h
--- 610-extent.patch-old/kernel/power/suspend2_core/extent.h	1970-01-01 10:00:00.000000000 +1000
+++ 610-extent.patch-new/kernel/power/suspend2_core/extent.h	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,84 @@
+/*
+ * kernel/power/extent.h
+ *
+ * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ * It contains declarations related to extents. Extents are
+ * suspend's method of storing some of the metadata for the image.
+ * See extent.c for more info.
+ *
+ */
+
+#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;
+	char * name;
+	struct extent * first;
+	struct extent * last;
+};
+
+/*
+ * We rely on extents not fitting evenly into a page.
+ * The last four bytes are used to store the number
+ * of the page, to make saving & reloading pages simpler.
+ */
+struct extent {
+	unsigned long minimum;
+	unsigned long maximum;
+	struct extent * next;
+};
+
+
+#define extent_for_each(extentchain, extentpointer, value) \
+if ((extentchain)->first) \
+	for ((extentpointer) = (extentchain)->first, (value) = \
+			(extentpointer)->minimum; \
+	     ((extentpointer) && ((extentpointer)->next || (value) <= \
+				 (extentpointer)->maximum)); \
+	     (((value) == (extentpointer)->maximum) ? \
+		((extentpointer) = (extentpointer)->next, (value) = \
+		 ((extentpointer) ? (extentpointer)->minimum : 0)) : \
+			(value)++))
+
+/*
+ * When using compression and expected_compression > 0,
+ * we allocate fewer swap entries, so GET_EXTENT_NEXT can
+ * validly run out of data to return.
+ */
+#define GET_EXTENT_NEXT(currentextent, currentval) \
+{ \
+	if (currentextent) { \
+		if ((currentval) == (currentextent)->maximum) { \
+			if ((currentextent)->next) { \
+				(currentextent) = (currentextent)->next; \
+				(currentval) = (currentextent)->minimum; \
+			} else { \
+				(currentextent) = NULL; \
+				(currentval) = 0; \
+			} \
+		} else \
+			currentval++; \
+	} \
+}
+
+extern int max_extents_used, extents_allocated;
+void put_extent(struct extent * extent);
+void put_extent_chain(struct extentchain * chain);
+int append_extent_to_extent_chain(struct extentchain * chain, 
+		unsigned long minimum, unsigned long maximum);
+int serialise_extent_chain(struct extentchain * chain);
+int load_extent_chain(struct extentchain * chain);
+
+/* swap_entry_to_extent_val & extent_val_to_swap_entry: 
+ * We are putting offset in the low bits so consecutive swap entries
+ * make consecutive extent values */
+#define swap_entry_to_extent_val(swp_entry) (swp_entry.val)
+#define extent_val_to_swap_entry(val) (swp_entry_t) { (val) }
+#endif


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [39/48] Suspend2 2.1.9.8 for 2.6.12: 615-poweroff.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (39 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [33/48] Suspend2 2.1.9.8 for 2.6.12: 610-encryption.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 18:18   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [47/48] Suspend2 2.1.9.8 for 2.6.12: 623-generic-block-io.patch Nigel Cunningham
                   ` (10 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

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
--- 616-prepare_image.patch-old/kernel/power/suspend2_core/prepare_image.c	1970-01-01 10:00:00.000000000 +1000
+++ 616-prepare_image.patch-new/kernel/power/suspend2_core/prepare_image.c	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,585 @@
+/*
+ * kernel/power/prepare_image.c
+ *
+ * Copyright (C) 2003-2005 Nigel Cunningham <nigel@suspend.net>
+ *
+ * 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;
+}
diff -ruNp 616-prepare_image.patch-old/kernel/power/suspend2_core/prepare_image.h 616-prepare_image.patch-new/kernel/power/suspend2_core/prepare_image.h
--- 616-prepare_image.patch-old/kernel/power/suspend2_core/prepare_image.h	1970-01-01 10:00:00.000000000 +1000
+++ 616-prepare_image.patch-new/kernel/power/suspend2_core/prepare_image.h	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,44 @@
+/*
+ * kernel/power/prepare_image.h
+ */
+
+extern int suspend2_prepare_image(void);
+extern struct pageset_sizes_result suspend2_recalculate_stats(void);
+extern int real_nr_free_pages(void);
+extern int image_size_limit;
+extern int pageset1_sizelow, pageset2_sizelow;
+
+struct pageset_sizes_result {
+	int size1; /* Can't be unsigned - breaks MAX function */
+	int size1low;
+	int size2;
+	int size2low;
+	int needmorespace;
+};
+
+#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))
+
+#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())
+


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [34/48] Suspend2 2.1.9.8 for 2.6.12: 610-extent.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (35 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [36/48] Suspend2 2.1.9.8 for 2.6.12: 612-pagedir.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06 10:14   ` Pekka Enberg
  2005-07-06  2:20 ` [PATCH] [37/48] Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch Nigel Cunningham
                   ` (14 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 611-io.patch-old/kernel/power/suspend2_core/io.c 611-io.patch-new/kernel/power/suspend2_core/io.c
--- 611-io.patch-old/kernel/power/suspend2_core/io.c	1970-01-01 10:00:00.000000000 +1000
+++ 611-io.patch-new/kernel/power/suspend2_core/io.c	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,1006 @@
+/*
+ * kernel/power/io.c
+ *
+ * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
+ * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr>
+ * Copyright (C) 2002-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * 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;
+}
diff -ruNp 611-io.patch-old/kernel/power/suspend2_core/io.h 611-io.patch-new/kernel/power/suspend2_core/io.h
--- 611-io.patch-old/kernel/power/suspend2_core/io.h	1970-01-01 10:00:00.000000000 +1000
+++ 611-io.patch-new/kernel/power/suspend2_core/io.h	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,44 @@
+/*
+ * kernel/power/io.h
+ */
+
+#include "pagedir.h"
+
+/* Non-plugin data saved in our image header */
+struct suspend_header {
+	u32 version_code;
+	unsigned long num_physpages;
+	unsigned long orig_mem_free;
+	char machine[65];
+	char version[65];
+	int num_cpus;
+	int page_size;
+	int pageset_2_size;
+	int param0;
+	int param1;
+	int param2;
+	int param3;
+	int progress0;
+	int progress1;
+	int progress2;
+	int progress3;
+	int io_time[2][2];
+	
+	/* Implementation specific variables */
+#ifdef KERNEL_POWER_SWSUSP_C
+	suspend_pagedir_t *suspend_pagedir;
+	unsigned int num_pbes;
+#else
+	struct pagedir pagedir;
+#endif
+};
+
+extern int write_pageset(struct pagedir * pagedir, int whichtowrite);
+extern int write_image_header(void);
+extern int read_pageset1(void);
+extern int read_pageset2(int overwrittenpagesonly);
+
+extern void attempt_to_parse_resume_device(void);
+extern dev_t name_to_dev_t(char *line);
+extern __nosavedata unsigned long bytes_in, bytes_out;
+


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [41/48] Suspend2 2.1.9.8 for 2.6.12: 617-proc.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (37 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [37/48] Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06 10:03   ` Pekka Enberg
  2005-07-06  2:20 ` [PATCH] [33/48] Suspend2 2.1.9.8 for 2.6.12: 610-encryption.patch Nigel Cunningham
                   ` (12 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 618-core.patch-old/kernel/power/suspend2_core/suspend.c 618-core.patch-new/kernel/power/suspend2_core/suspend.c
--- 618-core.patch-old/kernel/power/suspend2_core/suspend.c	1970-01-01 10:00:00.000000000 +1000
+++ 618-core.patch-new/kernel/power/suspend2_core/suspend.c	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,1180 @@
+/*
+ * kernel/power/suspend2.c
+ */
+/** \mainpage Software Suspend 2.
+ *
+ * Suspend2 provides support for saving and restoring an image of
+ * system memory to an arbitrary storage device, either on the local computer,
+ * or across some network. The support is entirely OS based, so Suspend2 
+ * works without requiring BIOS, APM or ACPI support. The vast majority of the
+ * code is also architecture independant, so it should be very easy to port
+ * the code to new architectures. Suspend includes support for SMP, 4G HighMem
+ * and preemption. Initramfses and initrds are also supported.
+ *
+ * Suspend2 uses a modular design, in which the method of storing the image is
+ * completely abstracted from the core code, as are transformations on the data
+ * such as compression and/or encryption (multiple 'plugins' can be used to
+ * provide arbitrary combinations of functionality). The user interface is also
+ * modular, so that arbitrarily simple or complex interfaces can be used to
+ * provide anything from debugging information through to eye candy.
+ * 
+ * \section Copyright
+ *
+ * Suspend2 is released under the GPLv2.
+ *
+ * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu><BR>
+ * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz><BR>
+ * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr><BR>
+ * Copyright (C) 2002-2005 Nigel Cunningham <ncunningham@cyclades.com><BR>
+ *
+ * \section Credits
+ * 
+ * Nigel would like to thank the following people for their work:
+ * 
+ * Pavel Machek <pavel@ucw.cz><BR>
+ * Modifications, defectiveness pointing, being with Gabor at the very beginning,
+ * suspend to swap space, stop all tasks. Port to 2.4.18-ac and 2.5.17.
+ *
+ * Steve Doddi <dirk@loth.demon.co.uk><BR> 
+ * Support the possibility of hardware state restoring.
+ *
+ * Raph <grey.havens@earthling.net><BR>
+ * Support for preserving states of network devices and virtual console
+ * (including X and svgatextmode)
+ *
+ * Kurt Garloff <garloff@suse.de><BR>
+ * Straightened the critical function in order to prevent compilers from
+ * playing tricks with local variables.
+ *
+ * Andreas Mohr <a.mohr@mailto.de>
+ *
+ * Alex Badea <vampire@go.ro><BR>
+ * Fixed runaway init
+ *
+ * Jeff Snyder <je4d@pobox.com><BR>
+ * ACPI patch
+ *
+ * Nathan Friess <natmanz@shaw.ca><BR>
+ * Some patches.
+ *
+ * Michael Frank <mhf@linuxmail.org><BR>
+ * Extensive testing and help with improving stability. Nigel was constantly
+ * amazed by the quality and quantity of Michael's help.
+ *
+ * Bernard Blackham <bernard@blackham.com.au><BR>
+ * Web page & Wiki administration, some coding. Another person without whom
+ * Suspend would not be where it is.
+ *
+ * ..and of course the myriads of Suspend2 users who have helped diagnose
+ * and fix bugs, made suggestions on how to improve the code, proofread
+ * documentation, and donated time and money.
+ *
+ * Thanks also to corporate sponsors:
+ *
+ * <B>Cyclades.com.</B> Nigel's employers from Dec 2004, who allow him to work on
+ * Suspend and PM related issues on company time.
+ * 
+ * <B>LinuxFund.org.</B> Sponsored Nigel's work on Suspend for four months Oct 2003
+ * to Jan 2004.
+ *
+ * <B>LAC Linux.</B> Donated P4 hardware that enabled development and ongoing
+ * maintenance of SMP and Highmem support.
+ *
+ * <B>OSDL.</B> Provided access to various hardware configurations, make occasional
+ * small donations to the project.
+ */
+
+#define SUSPEND_MAIN_C
+
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/version.h>
+#include <linux/reboot.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <asm/uaccess.h>
+#include <asm/param.h>
+
+#include "version.h"
+#include "suspend.h"
+#include "driver_model.h"
+#include "plugins.h"
+#include "proc.h"
+#include "pageflags.h"
+#include "prepare_image.h"
+#include "io.h"
+#include "ui.h"
+#include "version.h"
+#include "suspend2_common.h"
+#include "extent.h"
+#include "power_off.h"
+#include "utility.h"
+#include "smp.h"
+#include "atomic_copy.h"
+ 
+#ifdef  CONFIG_X86
+#include <asm/i387.h> /* for kernel_fpu_end */
+#endif
+
+/* Variables to be preserved over suspend */
+int pageset1_sizelow = 0, pageset2_sizelow = 0, image_size_limit = 0;
+unsigned long suspend2_orig_mem_free = 0;
+
+static dyn_pageflags_t pageset1_check_map;
+static dyn_pageflags_t pageset2_check_map;
+static char * debug_info_buffer;
+static char suspend_core_version[] = SUSPEND_CORE_VERSION;
+
+extern void do_suspend2_lowlevel(int resume);
+extern __nosavedata char resume_commandline[COMMAND_LINE_SIZE];
+
+/* 
+ *---------------------  Variables ---------------------------
+ * 
+ * The following are used by the arch specific low level routines 
+ * and only needed if suspend2 is compiled in. Other variables,
+ * used by the freezer even if suspend2 is not compiled in, are
+ * found in process.c
+ */
+
+/*! How long I/O took. */
+int suspend_io_time[2][2];
+
+/* Compression ratio */
+__nosavedata unsigned long bytes_in = 0, bytes_out = 0;
+
+/*! Pageset metadata. */
+struct pagedir pagedir1 = { 0, 0}, pagedir2 = { 0, 0}; 
+
+/* Suspend2 variables used by built-in routines. */
+
+/*! The number of suspends we have started (some may have been cancelled) */
+unsigned int nr_suspends = 0;
+
+/*! The console log level we default to. */
+int suspend_default_console_level = 0;
+
+/* 
+ * For resume2= kernel option. It's pointless to compile
+ * suspend2 without any writers, but compilation shouldn't
+ * fail if you do.
+ */
+
+unsigned long software_suspend_state = ((1 << SUSPEND_DISABLED) | (1 << SUSPEND_BOOT_TIME) |
+		(1 << SUSPEND_RESUME_NOT_DONE) | (1 << SUSPEND_IGNORE_LOGLEVEL));
+
+mm_segment_t	oldfs;
+
+#ifdef CONFIG_SUSPEND2_DEFAULT_RESUME2
+char resume2_file[256] = CONFIG_SUSPEND2_DEFAULT_RESUME2;
+#else
+char resume2_file[256]
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+static atomic_t actions_running;
+
+/*
+ * Basic clean-up routine.
+ */
+void suspend_finish_anything(int finishing_cycle)
+{
+	if (atomic_dec_and_test(&actions_running)) {
+		suspend2_cleanup_plugins(finishing_cycle);
+		suspend2_put_modules();
+		clear_suspend_state(SUSPEND_RUNNING);
+	}
+
+	set_fs(oldfs);
+}
+
+/*
+ * Basic set-up routine.
+ */
+int suspend_start_anything(int starting_cycle)
+{
+	oldfs = get_fs();
+
+	if (atomic_add_return(1, &actions_running) == 1) {
+       		set_fs(KERNEL_DS);
+
+		set_suspend_state(SUSPEND_RUNNING);
+
+		if (suspend2_get_modules()) {
+			printk("Get modules failed!\n");
+			clear_suspend_state(SUSPEND_RUNNING);
+			set_fs(oldfs);
+			return -EBUSY;
+		}
+
+		if (suspend2_initialise_plugins(starting_cycle)) {
+			printk("Initialise plugins failed!\n");
+			suspend_finish_anything(starting_cycle);
+			return -EBUSY;
+		}
+	}
+
+	return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * save_image
+ * Result code (int): Zero on success, non zero on failure.
+ * Functionality    : High level routine which performs the steps necessary
+ *                    to prepare and save the image after preparatory steps
+ *                    have been taken.
+ * Key Assumptions  : Processes frozen, sufficient memory available, drivers
+ *                    suspended.
+ * Called from      : suspend2_suspend_2
+ */
+
+static int save_image(void)
+{
+	int temp_result;
+
+	if (RAM_TO_SUSPEND > max_mapnr) {
+		suspend2_prepare_status(1, 1,
+			"Couldn't get enough free pages, on %ld pages short",
+			 RAM_TO_SUSPEND - max_mapnr);
+		return -1;
+	}
+	
+	suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
+		" - Final values: %d and %d.\n",
+		pageset1_size, 
+		pageset2_size);
+
+	check_shift_keys(1, "About to write pagedir2.");
+
+	temp_result = write_pageset(&pagedir2, 2);
+	
+	if (temp_result == -1 || TEST_RESULT_STATE(SUSPEND_ABORTED))
+		return -1;
+
+	check_shift_keys(1, "About to copy pageset 1.");
+
+	suspend2_prepare_status(1, 0, "Doing atomic copy.");
+	
+	do_suspend2_lowlevel(0);
+
+	return 0;
+}
+
+/*
+ * Save the second part of the image.
+ */
+int save_image_part1(void)
+{
+	int temp_result, old_ps1_size = pageset1_size;
+	dyn_pageflags_t temp;
+	
+	/* Quick switch: We want to compare the old stats with the new ones. */
+	temp = pageset1_map;
+	pageset1_map = pageset1_check_map;
+	pageset1_check_map = temp;
+
+	temp = pageset2_map;
+	pageset2_map = pageset2_check_map;
+	pageset2_check_map = temp;
+
+	suspend2_recalculate_stats();
+
+	if ((pageset1_size - old_ps1_size) > EXTRA_PD1_PAGES_ALLOWANCE) {
+		abort_suspend("Pageset1 has grown by %d pages."
+			" Only %d growth is allowed for!\n",
+			pageset1_size - old_ps1_size,
+			EXTRA_PD1_PAGES_ALLOWANCE);
+		return -1;
+	}
+
+	suspend2_map_atomic_copy_pages();
+
+	BUG_ON(!irqs_disabled());
+
+	if (!TEST_ACTION_STATE(SUSPEND_TEST_FILTER_SPEED))
+		suspend2_copy_pageset1();
+
+	/*
+	 *  ----   FROM HERE ON, NEED TO REREAD PAGESET2 IF ABORTING!!! -----
+	 *  
+	 */
+	
+	suspend2_unmap_atomic_copy_pages();
+
+	/* 
+	 * Other processors have waited for me to make the atomic copy of the 
+	 * kernel
+	 */
+
+	smp_continue();
+	
+#ifdef CONFIG_X86
+	kernel_fpu_end();
+#endif
+
+	preempt_enable_no_resched();
+
+	suspend_drivers_resume(SUSPEND_DRIVERS_IRQS_DISABLED);
+	
+	local_irq_enable();
+
+	suspend_drivers_resume(SUSPEND_DRIVERS_IRQS_ENABLED);
+
+	suspend2_update_status(pageset2_size, pageset1_size + pageset2_size, NULL);
+	
+	if (TEST_RESULT_STATE(SUSPEND_ABORTED))
+		goto abort_reloading_pagedir_two;
+
+	check_shift_keys(1, "About to write pageset1.");
+
+	/*
+	 * End of critical section.
+	 */
+	
+	suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
+			"-- Writing pageset1\n");
+
+	temp_result = write_pageset(&pagedir1, 1);
+
+	/* We didn't overwrite any memory, so no reread needs to be done. */
+	if (TEST_ACTION_STATE(SUSPEND_TEST_FILTER_SPEED))
+		return -1;
+
+	if (temp_result == -1 || TEST_RESULT_STATE(SUSPEND_ABORTED))
+		goto abort_reloading_pagedir_two;
+
+	check_shift_keys(1, "About to write header.");
+
+	if (TEST_RESULT_STATE(SUSPEND_ABORTED))
+		goto abort_reloading_pagedir_two;
+
+	temp_result = write_image_header();
+
+	if (temp_result || (TEST_RESULT_STATE(SUSPEND_ABORTED)))
+		goto abort_reloading_pagedir_two;
+
+	check_shift_keys(1, "About to power down or reboot.");
+
+	return 0;
+
+abort_reloading_pagedir_two:
+	temp_result = read_pageset2(1);
+
+	/* If that failed, we're sunk. Panic! */
+	if (temp_result)
+		panic("Attempt to reload pagedir 2 while aborting "
+				"a suspend failed.");
+
+	return -1;		
+
+}
+
+#define SNPRINTF(a...) 	len += suspend_snprintf(debug_info_buffer + len, \
+		PAGE_SIZE - len - 1, ## a)
+
+static inline int io_MB_per_second(int read_write)
+{
+	if (!suspend_io_time[read_write][1])
+		return 0;
+
+	return MB((unsigned long) suspend_io_time[read_write][0]) * HZ /
+		suspend_io_time[read_write][1];
+}
+
+/* get_debug_info
+ * Functionality:	Store debug info in a buffer.
+ * Called from:		suspend_try_suspend.
+ */
+
+
+static int get_suspend_debug_info(void)
+{
+	int len = 0;
+	if (!debug_info_buffer) {
+		debug_info_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+		if (!debug_info_buffer) {
+			printk("Error! Unable to allocate buffer for"
+					"software suspend debug info.\n");
+			return 0;
+		}
+	}
+
+	SNPRINTF("Please include the following information in bug reports:\n");
+	SNPRINTF("- SUSPEND core   : %s\n", SUSPEND_CORE_VERSION);
+	SNPRINTF("- Kernel Version : %s\n", UTS_RELEASE);
+	SNPRINTF("- Compiler vers. : %d.%d\n", __GNUC__, __GNUC_MINOR__);
+	SNPRINTF("- Attempt number : %d\n", nr_suspends);
+	SNPRINTF("- Pageset sizes  : %d (%d low) and %d (%d low).\n",
+			pagedir1.lastpageset_size, 
+			pageset1_sizelow,
+			pagedir2.lastpageset_size, 
+			pageset2_sizelow);
+	SNPRINTF("- Parameters     : %ld %ld %ld %d %d %ld\n",
+			suspend_result,
+			suspend_action,
+			suspend_debug_state,
+			suspend_default_console_level,
+			image_size_limit,
+			suspend2_powerdown_method);
+	SNPRINTF("- Calculations   : Image size: %lu. "
+			"Ram to suspend: %ld.\n",
+			STORAGE_NEEDED(1), RAM_TO_SUSPEND);
+	SNPRINTF("- Limits         : %lu pages RAM. Initial boot: %lu.\n",
+		max_mapnr, suspend2_orig_mem_free);
+	SNPRINTF("- Overall expected compression percentage: %d.\n",
+			100 - expected_compression_ratio());
+	len+= print_plugin_debug_info(debug_info_buffer + len, 
+			PAGE_SIZE - len - 1);
+#ifdef CONFIG_PM_DEBUG
+	SNPRINTF("- Debugging compiled in.\n");
+#endif
+#ifdef CONFIG_PREEMPT
+	SNPRINTF("- Preemptive kernel.\n");
+#endif
+#ifdef CONFIG_SMP
+	SNPRINTF("- SMP kernel.\n");
+#endif
+#ifdef CONFIG_HIGHMEM
+	SNPRINTF("- Highmem Support.\n");
+#endif
+	SNPRINTF("- Max extents used: %d\n",
+			max_extents_used);
+	if (suspend_io_time[0][1]) {
+		if ((io_MB_per_second(0) < 5) || (io_MB_per_second(1) < 5)) {
+			SNPRINTF("- I/O speed: Write %d KB/s",
+			  (KB((unsigned long) suspend_io_time[0][0]) * HZ /
+			  suspend_io_time[0][1]));
+			if (suspend_io_time[1][1])
+				SNPRINTF(", Read %d KB/s",
+				  (KB((unsigned long) suspend_io_time[1][0]) * HZ /
+				  suspend_io_time[1][1]));
+		} else {
+			SNPRINTF("- I/O speed: Write %d MB/s",
+			 (MB((unsigned long) suspend_io_time[0][0]) * HZ /
+			  suspend_io_time[0][1]));
+			if (suspend_io_time[1][1])
+				SNPRINTF(", Read %d MB/s",
+				 (MB((unsigned long) suspend_io_time[1][0]) * HZ /
+				  suspend_io_time[1][1]));
+		}
+		SNPRINTF(".\n");
+	}
+	else
+		SNPRINTF("- No I/O speed stats available.\n");
+
+	return len;
+}
+
+/*
+ * debuginfo_read_proc
+ * Functionality   : Displays information that may be helpful in debugging
+ *                   software suspend.
+ */
+int debuginfo_read_proc(char * page, char ** start, off_t off, int count,
+		int *eof, void *data)
+{
+	int info_len, copy_len;
+
+	info_len = get_suspend_debug_info();
+
+	copy_len = min(info_len - (int) off, count);
+	if (copy_len < 0)
+		copy_len = 0;
+
+	if (copy_len) {
+		memcpy(page, debug_info_buffer + off, copy_len);
+		*start = page;
+	} 
+
+	if (copy_len + off == info_len)
+		*eof = 1;
+
+	free_pages((unsigned long) debug_info_buffer, 0);
+	debug_info_buffer = NULL;
+	return copy_len;
+}
+
+static int allocate_bitmaps(void)
+{
+	suspend_message(SUSPEND_MEMORY, SUSPEND_VERBOSE, 1,
+			"Allocating in_use_map\n");
+	if (suspend_allocate_dyn_pageflags(&in_use_map))
+		return 1;
+	
+	if (suspend_allocate_dyn_pageflags(&pageset1_map))
+		return 1;
+
+	if (suspend_allocate_dyn_pageflags(&pageset1_copy_map))
+		return 1;
+
+	if (suspend_allocate_dyn_pageflags(&allocd_pages_map))
+		return 1;
+
+	if (suspend_allocate_dyn_pageflags(&pageset2_map))
+		return 1;
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+	if (suspend_allocate_dyn_pageflags(&unmap_map))
+		return 1;
+
+#endif	
+	
+	if (suspend_allocate_dyn_pageflags(&pageset1_check_map))
+		return 1;
+	
+	if (suspend_allocate_dyn_pageflags(&pageset2_check_map))
+		return 1;
+
+	return 0;
+}
+
+static void free_metadata(void)
+{
+	free_dyn_pageflags(&pageset1_map);
+
+	free_dyn_pageflags(&pageset1_copy_map);
+
+	free_dyn_pageflags(&allocd_pages_map);
+
+	free_dyn_pageflags(&pageset2_map);
+
+	free_dyn_pageflags(&in_use_map);
+
+	free_dyn_pageflags(&pageset1_check_map);
+	free_dyn_pageflags(&pageset2_check_map);
+}
+
+static inline int check_still_keeping_image(void)
+{
+	if (TEST_ACTION_STATE(SUSPEND_KEEP_IMAGE)) {
+		printk("Image already stored: powering down immediately.");
+		suspend_power_down();
+		return 1;	/* Just in case we're using S3 */
+	}
+
+	printk("Invalidating previous image.\n");
+	active_writer->ops.writer.invalidate_image();
+
+	return 0;
+}
+
+static inline int suspend2_init(void)
+{
+	suspend_result = 0;
+
+	printk(name_suspend "Initiating a software suspend cycle.\n");
+
+	max_extents_used = 0;
+	nr_suspends++;
+	clear_suspend_state(SUSPEND_NOW_RESUMING);
+	
+	suspend_io_time[0][0] = suspend_io_time[0][1] = 
+		suspend_io_time[1][0] =
+		suspend_io_time[1][1] = 0;
+
+	suspend2_prepare_console();
+
+	free_metadata();	/* We might have kept it */
+
+	attempt_to_parse_resume_device();
+	
+	if (test_suspend_state(SUSPEND_DISABLED))
+		return 0;
+	
+	if (suspend_drivers_init())
+		return 0;
+
+	if (allocate_bitmaps())
+		return 0;
+	
+	ensure_on_processor_zero();
+
+	return 1;
+}
+
+void inline suspend2_cleanup(void)
+{
+	int i;
+
+	i = get_suspend_debug_info();
+
+	suspend2_free_pagedir_data();
+	
+	thaw_processes(FREEZER_KERNEL_THREADS);
+
+#ifdef CONFIG_SUSPEND2_KEEP_IMAGE
+	if (TEST_ACTION_STATE(SUSPEND_KEEP_IMAGE) &&
+	    !TEST_RESULT_STATE(SUSPEND_ABORTED)) {
+		suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
+			name_suspend "Not invalidating the image due "
+			"to Keep Image being enabled.\n");
+		SET_RESULT_STATE(SUSPEND_KEPT_IMAGE);
+	} else
+#endif
+		if (active_writer)
+			active_writer->ops.writer.invalidate_image();
+
+	if (!TEST_ACTION_STATE(SUSPEND_KEEP_METADATA))
+		free_metadata();
+
+#ifdef CONFIG_DEBUG_PAGE_ALLOC
+	free_dyn_pageflags(&unmap_map);
+#endif
+
+	if (debug_info_buffer) {
+		/* Printk can only handle 1023 bytes, including
+		 * its level mangling. */
+		for (i = 0; i < 3; i++)
+			printk("%s", debug_info_buffer + (1023 * i));
+		free_pages((unsigned long) debug_info_buffer, 0);
+		debug_info_buffer = NULL;
+	}
+
+	suspend_drivers_cleanup();
+
+	thaw_processes(FREEZER_ALL_THREADS);
+
+	suspend2_cleanup_console();
+
+	return_to_all_processors();
+}
+
+/*
+ * suspend2_main
+ * Functionality   : First level of code for software suspend invocations.
+ *                   Stores and restores load averages (to avoid a spike),
+ *                   allocates bitmaps, freezes processes and eats memory
+ *                   as required before suspending drivers and invoking
+ *                   the 'low level' code to save the state to disk.
+ *                   By the time we return from do_suspend2_lowlevel, we
+ *                   have either failed to save the image or successfully
+ *                   suspended and reloaded the image. The difference can
+ *                   be discerned by checking SUSPEND_ABORTED.
+ * Called From     : 
+ */
+
+void suspend2_main(void)
+{
+	/*
+	 * If kept image and still keeping image and suspending to RAM, we will 
+	 * return 1 after suspending and resuming (provided the power doesn't
+	 * run out.
+	 */
+	if (TEST_RESULT_STATE(SUSPEND_KEPT_IMAGE) && check_still_keeping_image())
+		return;
+
+	if (suspend2_init() && suspend2_prepare_image() && !TEST_RESULT_STATE(SUSPEND_ABORTED) &&
+		!TEST_ACTION_STATE(SUSPEND_FREEZER_TEST))
+	{
+		if (!TEST_RESULT_STATE(SUSPEND_ABORTED)) {
+			suspend2_prepare_status(1, 0, "Starting to save the image..");
+			save_image();
+		}
+	}
+	
+	suspend2_cleanup();
+}
+
+/* image_exists_read
+ * 
+ * Return 0 or 1, depending on whether an image is found.
+ */
+static int image_exists_read(char * page, char ** start, off_t off, int count,
+		int *eof, void *data)
+{
+	int len = 0;
+	
+	attempt_to_parse_resume_device();
+
+	if (!active_writer)
+		len = sprintf(page, "-1\n");
+	else
+		len = sprintf(page, "%d\n", active_writer->ops.writer.image_exists());
+
+	*eof = 1;
+	return len;
+}
+
+/* image_exists_read
+ * 
+ * Return 0 or 1, depending on whether an image is found.
+ */
+static int image_exists_write(struct file *file, const char * buffer,
+		unsigned long count, void * data)
+{
+	if (active_writer && active_writer->ops.writer.image_exists())
+		active_writer->ops.writer.invalidate_image();
+
+	return count;
+}
+
+/*
+ * Core proc entries that aren't built in.
+ *
+ * This array contains entries that are automatically registered at
+ * boot. Plugins and the console code register their own entries separately.
+ */
+extern int toggle_pid;
+void toggle_thread_nofreeze(void);
+
+static struct suspend_proc_data proc_params[] = {
+	{ .filename			= "debug_info",
+	  .permissions			= PROC_READONLY,
+	  .type				= SUSPEND_PROC_DATA_CUSTOM,
+	  .data = {
+		  .special = {
+			  .read_proc	= debuginfo_read_proc,
+		  }
+	  }
+	},
+	
+	{ .filename			= "image_exists",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_CUSTOM,
+	  .data = {
+		  .special = {
+			  .read_proc	= image_exists_read,
+			  .write_proc	= image_exists_write,
+		  }
+	  }
+	},
+
+	{ .filename			= "image_size_limit",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_INTEGER,
+	  .data = {
+		  .integer = {
+			  .variable	= &image_size_limit,
+			  .minimum	= -2,
+			  .maximum	= 32767,
+		  }
+	  }
+	},
+
+	{ .filename			= "last_result",
+	  .permissions			= PROC_READONLY,
+	  .type				= SUSPEND_PROC_DATA_UL,
+	  .data = {
+		  .ul = {
+			  .variable	=  &suspend_result,
+		  }
+	  }
+	},
+	
+	{ .filename			= "reboot",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_REBOOT,
+		  }
+	  }
+	},
+	  
+	{ .filename			= "resume2",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_STRING,
+	  .data = {
+		  .string = {
+			  .variable	= resume2_file,
+			  .max_length	= 255,
+		  }
+	  },
+	  .write_proc			= attempt_to_parse_resume_device,
+	},
+
+	{ .filename			= "resume_commandline",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_STRING,
+	  .data = {
+		  .string = {
+			  .variable	= resume_commandline,
+			  .max_length	= COMMAND_LINE_SIZE,
+		  }
+	  },
+	  .write_proc			= attempt_to_parse_resume_device,
+	},
+
+
+	{ .filename			= "toggle_process_nofreeze",
+	  .permissions			= PROC_WRITEONLY,
+	  .type				= SUSPEND_PROC_DATA_INTEGER,
+	  .data = {
+		  .integer = {
+			  .variable	= &toggle_pid,
+			  .minimum	= 2,
+			  .maximum	= 32767,
+		  }
+	  },
+	  .write_proc			= toggle_thread_nofreeze,
+	},
+
+	{ .filename			= "version",
+	  .permissions			= PROC_READONLY,
+	  .type				= SUSPEND_PROC_DATA_STRING,
+	  .data = {
+		  .string = {
+			  .variable	= suspend_core_version,
+		  }
+	  }
+	},
+
+#ifdef CONFIG_PM_DEBUG
+	{ .filename			= "freezer_test",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_FREEZER_TEST,
+		  }
+	  }
+	},
+
+	{ .filename			= "keep_metadata",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_KEEP_METADATA,
+		  }
+	  }
+	},
+
+	{ .filename			= "test_filter_speed",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_TEST_FILTER_SPEED,
+		  }
+	  }
+	},
+
+	{ .filename			= "slow",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_SLOW,
+		  }
+	  }
+	},
+	
+#endif
+	  
+#if defined(CONFIG_ACPI)
+	{ .filename			= "powerdown_method",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_UL,
+	  .data = {
+		  .ul = {
+			  .variable	= &suspend2_powerdown_method,
+			  .minimum	= 3,
+			  .maximum	= 5,
+		  }
+	  }
+	},
+#endif
+
+#ifdef CONFIG_SUSPEND2_KEEP_IMAGE
+	{ .filename			= "keep_image",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_KEEP_IMAGE,
+		  }
+	  }
+	},
+#endif
+};
+
+
+/*
+ * Called from init kernel_thread.
+ * We check if we have an image and if so we try to resume.
+ * We also start ksuspendd if configuration looks right.
+ */
+
+int suspend2_resume(void)
+{
+	int read_image_result = 0;
+
+	if (sizeof(swp_entry_t) != sizeof(long)) {
+		printk(KERN_WARNING name_suspend
+			"The size of swp_entry_t != size of long. "
+			"Please report this!\n");
+		return 1;
+	}
+	
+	if (!resume2_file[0])
+		printk(KERN_WARNING name_suspend
+			"You need to use a resume2= command line parameter to "
+			"tell Software Suspend 2 where to look for an image.\n");
+
+	if (!(test_suspend_state(SUSPEND_RESUME_DEVICE_OK)))
+		attempt_to_parse_resume_device();
+
+	if (!(test_suspend_state(SUSPEND_RESUME_DEVICE_OK))) {
+		/* 
+		 * Without a usable storage device we can do nothing - 
+		 * even if noresume is given
+		 */
+
+		if (!num_writers)
+			printk(KERN_ALERT name_suspend
+				"No writers have been registered.\n");
+		else
+			printk(KERN_ALERT name_suspend
+				"Missing or invalid storage location "
+				"(resume2= parameter). Please correct and "
+				"rerun lilo (or equivalent) before "
+				"suspending.\n");
+		return 1;
+	}
+
+	/* We enable the possibility of machine suspend */
+	suspend2_orig_mem_free = real_nr_free_pages();
+
+	suspend_task = current->pid;
+
+	read_image_result = read_pageset1(); /* non fatal error ignored */
+
+	if (test_suspend_state(SUSPEND_NORESUME_SPECIFIED))
+		printk(KERN_WARNING name_suspend "Resuming disabled as requested.\n");
+
+	if (read_image_result) {
+		suspend_task = 0;
+		return 1;
+	}
+
+	suspend_drivers_init();
+
+	suspend_atomic_restore();
+
+	BUG();
+
+	return 0;
+}
+
+extern void request_abort_suspend(void);
+extern void suspend2_schedule_message(int message_number);
+
+static __init int core_load(void)
+{
+	int i, numfiles = sizeof(proc_params) / sizeof(struct suspend_proc_data);
+
+	printk("Software Suspend Core.\n");
+	
+	suspend_initialise_plugin_lists();
+	
+	for (i=0; i< numfiles; i++)
+		suspend_register_procfile(&proc_params[i]);
+
+	return 0;
+}
+
+/* ------------ Functions for kickstarting a suspend or resume ----------- */
+
+static int can_suspend(void)
+{
+	/* 
+	 * Perhaps something has changed such that we can suspend or
+	 * resume when we couldn't before. Check before complaining.
+	 */
+	
+	if (test_suspend_state(SUSPEND_DISABLED))
+		attempt_to_parse_resume_device();
+
+	if (test_suspend_state(SUSPEND_DISABLED)) {
+		printk(name_suspend "Software suspend is disabled.\n"
+			"This may be because you haven't put something along the "
+			"lines of\n\nresume2=swap:/dev/hda1\n\n"
+			"in lilo.conf or equivalent. (Where /dev/hda1 is your "
+			"swap partition).\n");
+		SET_RESULT_STATE(SUSPEND_ABORTED);
+		return 0;
+	}
+	
+	return 1;
+}
+
+/*
+ * Check if we have an image and if so try to resume.
+ */
+
+void __suspend2_try_resume(void)
+{
+	set_suspend_state(SUSPEND_TRYING_TO_RESUME);
+	
+	clear_suspend_state(SUSPEND_RESUME_NOT_DONE);
+
+	suspend2_resume();
+
+	clear_suspend_state(SUSPEND_IGNORE_LOGLEVEL);
+	clear_suspend_state(SUSPEND_TRYING_TO_RESUME);
+}
+
+/* Wrapper for when called from init/do_mounts.c */
+void suspend2_try_resume(void)
+{
+	if (suspend_start_anything(0))
+		return;
+
+	__suspend2_try_resume();
+
+	/* 
+	 * For initramfs, we have to clear the boot time
+	 * flag after trying to resume
+	 */
+	clear_suspend_state(SUSPEND_BOOT_TIME);
+
+	suspend_finish_anything(0);
+}
+
+/*
+ * suspend_check_mounts
+ *
+ * Functionality:	Check that the user doesn't have any mounts that
+ * 			may be corrupted by resuming. Display them if needsbe.
+ * 			On exit, CONTINUE_REQ is set if we can continue resuming.
+ */
+
+void suspend_check_mounts(void)
+{
+	if (!mounts_are_S4_resume_safe()) {
+		char *buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+		get_S4_resume_unsafe_mounts(buffer, PAGE_SIZE);
+		suspend_early_boot_message(1, 0,
+			"You have filesystems mounted that may make resuming unsafe:\n %s", buffer);
+		free_pages((unsigned long) buffer, 0);
+		return;
+	}
+
+	set_suspend_state(SUSPEND_CONTINUE_REQ);
+	return;
+}
+
+/*
+ * __suspend2_try_suspend
+ * Functionality   : Performs the basic checking as to whether suspend is
+ * 		     enabled before invoking the high level routine.
+ * Called From     : proc.c, suspend2_try_suspend.c
+ */
+void __suspend2_try_suspend(void)
+{
+	if (can_suspend())
+		suspend2_main();
+}
+
+/*
+ * suspend2_try_suspend
+ * Functionality   : Wrapper around __suspend2_try_suspend.
+ * Called From     : drivers/acpi/sleep/main.c
+ *                   kernel/reboot.c
+ */
+
+void suspend2_try_suspend(void)
+{
+	if (suspend_start_anything(0))
+		return;
+
+	__suspend2_try_suspend();
+
+	suspend_finish_anything(0);
+}
+
+/* -------------------  Commandline Parameter Handling -----------------
+ *
+ * Resume setup: obtain the storage device.
+ */
+
+static int __init resume_setup(char *str)
+{
+	if (str == NULL)
+		return 1;
+	
+	strncpy(resume2_file, str, 255);
+	return 0;
+}
+
+/*
+ * Allow the user to set the action parameter from lilo, prior to resuming.
+ */
+static int __init suspend_act_setup(char *str)
+{
+	if(str)
+		suspend_action=simple_strtol(str,NULL,0);
+	set_suspend_state(SUSPEND_ACT_USED);
+	return 0;
+}
+
+/*
+ * Allow the user to set the debug parameter from lilo, prior to resuming.
+ */
+/*
+ * Allow the user to specify that we should ignore any image found and
+ * invalidate the image if necesssary. This is equivalent to running
+ * the task queue and a sync and then turning off the power. The same
+ * precautions should be taken: fsck if you're not journalled.
+ */
+static int __init noresume_setup(char *str)
+{
+	set_suspend_state(SUSPEND_NORESUME_SPECIFIED);
+	/* Message printed later */
+	return 0;
+}
+
+static int __init suspend2_retry_resume_setup(char *str)
+{
+	set_suspend_state(SUSPEND_RETRY_RESUME);
+	return 0;
+}
+
+__setup("resume2=", resume_setup);
+__setup("suspend_act=", suspend_act_setup);
+
+#ifdef CONFIG_PM_DEBUG
+
+static int __init suspend_dbg_setup(char *str)
+{
+	if(str)
+		suspend_debug_state=simple_strtol(str,NULL,0);
+	set_suspend_state(SUSPEND_DBG_USED);
+	return 0;
+}
+
+/*
+ * Allow the user to set the debug level parameter from lilo, prior to
+ * resuming.
+ */
+static int __init suspend_lvl_setup(char *str)
+{
+	if(str)
+		console_loglevel =
+		suspend_default_console_level = 
+			simple_strtol(str,NULL,0);
+	set_suspend_state(SUSPEND_LVL_USED);
+	clear_suspend_state(SUSPEND_IGNORE_LOGLEVEL);
+	return 0;
+}
+
+__setup("suspend_dbg=", suspend_dbg_setup);
+__setup("suspend_lvl=", suspend_lvl_setup);
+#endif
+
+__setup("noresume2", noresume_setup);
+__setup("suspend_retry_resume", suspend2_retry_resume_setup);
+
+late_initcall(core_load);
+EXPORT_SYMBOL(software_suspend_state);


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [42/48] Suspend2 2.1.9.8 for 2.6.12: 618-core.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (43 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [46/48] Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 18:21   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [44/48] Suspend2 2.1.9.8 for 2.6.12: 620-userui.patch Nigel Cunningham
                   ` (6 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 619-userspace-nofreeze.patch-old/kernel/power/suspend2_core/userspace-nofreeze.c 619-userspace-nofreeze.patch-new/kernel/power/suspend2_core/userspace-nofreeze.c
--- 619-userspace-nofreeze.patch-old/kernel/power/suspend2_core/userspace-nofreeze.c	1970-01-01 10:00:00.000000000 +1000
+++ 619-userspace-nofreeze.patch-new/kernel/power/suspend2_core/userspace-nofreeze.c	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,69 @@
+/*
+ * kernel/power/suspend2_core/userspace-nofreeze.c
+ *
+ * Mark/unmark userspace processes as PF_NOFREEZE.
+ *
+ * This should be used with extreme caution!
+ *
+ * Initial purpose: make nbd-client about to be NOFREEZE.
+ */
+
+#include <linux/module.h>
+#include <linux/suspend.h>
+#include <asm/tlbflush.h>
+#include "../suspend.h"
+
+int toggle_pid;
+
+/*
+ * toggle_thread_nofreeze
+ *
+ * Toggle a thread's PF_NOFREEZE flag
+ *
+ * Returns:
+ * -1: PID not found
+ *  0: NO_FREEZE cleared.
+ *  1: NO_FREEZE set.
+ */
+static int __toggle_thread_nofreeze(int pid)
+{
+	struct task_struct *p, *g;
+	int result = -1;
+
+	read_lock(&tasklist_lock);
+
+	do_each_thread(g, p) {
+		if (p->pid == pid) {
+			if (p->mm) {
+				p->flags ^=PF_NOFREEZE;
+				result = !!(p->flags & PF_NOFREEZE);
+			} else
+				printk("Cowardly refusing to toggle NOFREEZE on a real kernel thread!");
+		}
+	} while_each_thread(g, p);
+
+	read_unlock(&tasklist_lock);
+
+	return result;
+}
+
+void toggle_thread_nofreeze(void)
+{
+	int result;
+	printk("Seeking %d... ", toggle_pid);
+
+	switch ((result = __toggle_thread_nofreeze(toggle_pid)))
+	{
+		case -1:
+			printk("Can't toggle NO_FREEZE for thread - not found.\n");
+			break;
+		case 0:
+			printk("NO_FREEZE flag cleared.\n");
+			break;
+		case 1:
+			printk("NO_FREEZE flag set.\n");
+			break;
+		default:
+			printk("what does %d mean?!", result);
+	}
+}


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [44/48] Suspend2 2.1.9.8 for 2.6.12: 620-userui.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (44 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [42/48] Suspend2 2.1.9.8 for 2.6.12: 618-core.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 18:22   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [43/48] Suspend2 2.1.9.8 for 2.6.12: 619-userspace-nofreeze.patch Nigel Cunningham
                   ` (5 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 621-swsusp-tidy.patch-old/kernel/power/swsusp.c 621-swsusp-tidy.patch-new/kernel/power/swsusp.c
--- 621-swsusp-tidy.patch-old/kernel/power/swsusp.c	2005-06-20 11:47:31.000000000 +1000
+++ 621-swsusp-tidy.patch-new/kernel/power/swsusp.c	2005-07-04 23:14:19.000000000 +1000
@@ -36,6 +36,8 @@
  * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt
  */
 
+#define KERNEL_POWER_SWSUSP_C
+
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/suspend.h>
@@ -51,9 +53,7 @@
 #include <linux/keyboard.h>
 #include <linux/spinlock.h>
 #include <linux/genhd.h>
-#include <linux/kernel.h>
 #include <linux/major.h>
-#include <linux/swap.h>
 #include <linux/pm.h>
 #include <linux/device.h>
 #include <linux/buffer_head.h>
@@ -71,9 +71,7 @@
 #include <asm/io.h>
 
 #include "power.h"
-
-/* References to section boundaries */
-extern const void __nosave_begin, __nosave_end;
+#include "suspend.h"
 
 /* Variables to be preserved over suspend */
 static int nr_copy_pages_check;


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [48/48] Suspend2 2.1.9.8 for 2.6.12: 624-filewriter.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (41 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [47/48] Suspend2 2.1.9.8 for 2.6.12: 623-generic-block-io.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06 10:07   ` Pekka Enberg
                     ` (2 more replies)
  2005-07-06  2:20 ` [PATCH] [46/48] Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch Nigel Cunningham
                   ` (8 subsequent siblings)
  51 siblings, 3 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 625-crypto-api-work.patch-old/crypto/Kconfig 625-crypto-api-work.patch-new/crypto/Kconfig
--- 625-crypto-api-work.patch-old/crypto/Kconfig	2005-06-20 11:46:49.000000000 +1000
+++ 625-crypto-api-work.patch-new/crypto/Kconfig	2005-07-04 23:14:19.000000000 +1000
@@ -262,6 +262,13 @@ config CRYPTO_DEFLATE
 	  
 	  You will most probably want this if using IPSec.
 
+config CRYPTO_LZF
+	tristate "LZF compression algorithm"
+	depends on CRYPTO
+	help
+	  This is the LZF algorithm. It is especially useful for Suspend2,
+	  because it achieves good compression quickly.
+
 config CRYPTO_MICHAEL_MIC
 	tristate "Michael MIC keyed digest algorithm"
 	depends on CRYPTO
diff -ruNp 625-crypto-api-work.patch-old/crypto/lzf.c 625-crypto-api-work.patch-new/crypto/lzf.c
--- 625-crypto-api-work.patch-old/crypto/lzf.c	1970-01-01 10:00:00.000000000 +1000
+++ 625-crypto-api-work.patch-new/crypto/lzf.c	2005-07-05 23:57:15.000000000 +1000
@@ -0,0 +1,442 @@
+/* 
+ * Cryptoapi LZF compression module.
+ *
+ * Copyright (c) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * based on the deflate.c file:
+ * 
+ * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
+ * 
+ * and upon the LZF compression module donated to the Suspend2 project with
+ * the following copyright:
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option) 
+ * any later version.
+ * Copyright (c) 2000-2003 Marc Alexander Lehmann <pcg@goof.com>
+ * 
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ * 
+ *   1.  Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *   2.  Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ * 
+ *   3.  The name of the author may not be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
+ * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
+ * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
+ * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * the GNU General Public License version 2 (the "GPL"), in which case the
+ * provisions of the GPL are applicable instead of the above. If you wish to
+ * allow the use of your version of this file only under the terms of the
+ * GPL and not to allow others to use your version of this file under the
+ * BSD license, indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by the GPL. If
+ * you do not delete the provisions above, a recipient may use your version
+ * of this file under either the BSD or the GPL.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <linux/vmalloc.h>
+#include <asm/string.h>
+
+struct lzf_ctx {
+	void * hbuf;
+	char * local_buffer;
+	char * page_buffer;
+	unsigned int bufofs;
+	int first_call;
+};
+
+/*
+ * size of hashtable is (1 << HLOG) * sizeof (char *)
+ * decompression is independent of the hash table size
+ * the difference between 15 and 14 is very small
+ * for small blocks (and 14 is also faster).
+ * For a low-memory configuration, use HLOG == 13;
+ * For best compression, use 15 or 16.
+ */
+#define HLOG 14
+
+/*
+ * sacrifice some compression quality in favour of compression speed.
+ * (roughly 1-2% worse compression for large blocks and
+ * 9-10% for small, redundant, blocks and >>20% better speed in both cases)
+ * In short: enable this for binary data, disable this for text data.
+ */
+#define ULTRA_FAST 1
+
+#define STRICT_ALIGN 0
+#define USE_MEMCPY 1
+#define INIT_HTAB 0
+
+#define HSIZE (1 << (HLOG))
+
+/*
+ * don't play with this unless you benchmark!
+ * decompression is not dependent on the hash function
+ * the hashing function might seem strange, just believe me
+ * it works ;)
+ */
+#define FRST(p) (((p[0]) << 8) + p[1])
+#define NEXT(v,p) (((v) << 8) + p[2])
+#define IDX(h) ((((h ^ (h << 5)) >> (3*8 - HLOG)) + h*3) & (HSIZE - 1))
+/*
+ * IDX works because it is very similar to a multiplicative hash, e.g.
+ * (h * 57321 >> (3*8 - HLOG))
+ * the next one is also quite good, albeit slow ;)
+ * (int)(cos(h & 0xffffff) * 1e6)
+ */
+
+#if 0
+/* original lzv-like hash function */
+# define FRST(p) (p[0] << 5) ^ p[1]
+# define NEXT(v,p) ((v) << 5) ^ p[2]
+# define IDX(h) ((h) & (HSIZE - 1))
+#endif
+
+#define        MAX_LIT        (1 <<  5)
+#define        MAX_OFF        (1 << 13)
+#define        MAX_REF        ((1 <<  8) + (1 << 3))
+
+/*
+ * compressed format
+ *
+ * 000LLLLL <L+1>    ; literal
+ * LLLOOOOO oooooooo ; backref L
+ * 111OOOOO LLLLLLLL oooooooo ; backref L+7
+ *
+ */
+
+static void lzf_compress_exit(void * context)
+{
+	struct lzf_ctx * ctx = (struct lzf_ctx *) context;
+
+	if (ctx->local_buffer) {
+		free_pages((unsigned long) ctx->local_buffer, 0);
+		ctx->local_buffer = NULL;
+	}
+
+	if (ctx->page_buffer) {
+		free_pages((unsigned long) ctx->page_buffer, 0);
+		ctx->page_buffer = NULL;
+	}
+	
+	if (ctx->hbuf) {
+		vfree(ctx->hbuf);
+		ctx->hbuf = NULL;
+	}
+
+	ctx->first_call = 0;
+}
+
+static int lzf_compress_init(void *context)
+{
+	struct lzf_ctx * ctx = (struct lzf_ctx *) context;
+
+	/* Get LZF ready to go */
+	ctx->hbuf = vmalloc_32((1<<HLOG)*sizeof(char *));
+	if (!ctx->hbuf) {
+		printk(KERN_WARNING
+			"Failed to allocate %d bytes for lzf workspace\n",
+			(1<<HLOG)*sizeof(char *));
+		return -ENOMEM;
+	}
+	
+	/* Allocate local buffer */
+	ctx->local_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+
+	if (!ctx->local_buffer) {
+		lzf_compress_exit(ctx);
+		return -ENOMEM;
+	}
+
+	/* Allocate page buffer */
+	ctx->page_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+
+	if (!ctx->page_buffer) {
+		free_pages((unsigned long) ctx->local_buffer, 0);
+		lzf_compress_exit(ctx);
+		return -ENOMEM;
+	}
+
+	ctx->first_call = 1;
+
+	return 0;
+}
+
+static int lzf_compress(void * context, const u8 *in_data, unsigned int in_len,
+	                    u8 *out_data, unsigned int *out_len)
+{
+  struct lzf_ctx * ctx = (struct lzf_ctx *) context;
+  const u8 **htab = ctx->hbuf;
+  const u8 **hslot;
+  const u8 *ip = in_data;
+        u8 *op = out_data;
+  const u8 *in_end  = ip + in_len;
+        u8 *out_end = op + *out_len - 3;
+  const u8 *ref;
+
+  unsigned int hval = FRST (ip);
+  unsigned long off;
+           int lit = 0;
+
+	if (ctx->first_call) {
+		ctx->first_call = 0;
+	}
+#if INIT_HTAB
+# if USE_MEMCPY
+    memset (htab, 0, sizeof (htab));
+# else
+    for (hslot = htab; hslot < htab + HSIZE; hslot++)
+      *hslot++ = ip;
+# endif
+#endif
+
+  for (;;)
+    {
+      if (ip < in_end - 2)
+        {
+          hval = NEXT (hval, ip);
+          hslot = htab + IDX (hval);
+          ref = *hslot; *hslot = ip;
+
+          if (1
+#if INIT_HTAB && !USE_MEMCPY
+              && ref < ip /* the next test will actually take care of this, but this is faster */
+#endif
+              && (off = ip - ref - 1) < MAX_OFF
+              && ip + 4 < in_end
+              && ref > in_data
+#if STRICT_ALIGN
+              && ref[0] == ip[0]
+              && ref[1] == ip[1]
+              && ref[2] == ip[2]
+#else
+              && *(u16 *)ref == *(u16 *)ip
+              && ref[2] == ip[2]
+#endif
+            )
+            {
+              /* match found at *ref++ */
+              unsigned int len = 2;
+              unsigned int maxlen = in_end - ip - len;
+              maxlen = maxlen > MAX_REF ? MAX_REF : maxlen;
+
+              do
+                len++;
+              while (len < maxlen && ref[len] == ip[len]);
+
+              if (op + lit + 1 + 3 >= out_end) {
+		*out_len = PAGE_SIZE;
+                return 0;
+	      }
+
+              if (lit)
+                {
+                  *op++ = lit - 1;
+                  lit = -lit;
+                  do
+                    *op++ = ip[lit];
+                  while (++lit);
+                }
+
+              len -= 2;
+              ip++;
+
+              if (len < 7)
+                {
+                  *op++ = (off >> 8) + (len << 5);
+                }
+              else
+                {
+                  *op++ = (off >> 8) + (  7 << 5);
+                  *op++ = len - 7;
+                }
+
+              *op++ = off;
+
+#if ULTRA_FAST
+              ip += len;
+              hval = FRST (ip);
+              hval = NEXT (hval, ip);
+              htab[IDX (hval)] = ip;
+              ip++;
+#else
+              do
+                {
+                  hval = NEXT (hval, ip);
+                  htab[IDX (hval)] = ip;
+                  ip++;
+                }
+              while (len--);
+#endif
+              continue;
+            }
+        }
+      else if (ip == in_end)
+        break;
+
+      /* one more literal byte we must copy */
+      lit++;
+      ip++;
+
+      if (lit == MAX_LIT)
+        {
+          if (op + 1 + MAX_LIT >= out_end) {
+            *out_len = PAGE_SIZE;
+            return 0;
+	  }
+
+          *op++ = MAX_LIT - 1;
+#if USE_MEMCPY
+          memcpy (op, ip - MAX_LIT, MAX_LIT);
+          op += MAX_LIT;
+          lit = 0;
+#else
+          lit = -lit;
+          do
+            *op++ = ip[lit];
+          while (++lit);
+#endif
+        }
+    }
+
+  if (lit)
+    {
+      if (op + lit + 1 >= out_end) {
+        *out_len = PAGE_SIZE;
+	return 0;
+      }
+
+      *op++ = lit - 1;
+      lit = -lit;
+      do
+	*op++ = ip[lit];
+      while (++lit);
+    }
+
+  *out_len = op - out_data;
+  return 0;
+}
+ 
+static int lzf_decompress(void * context, const u8 *src, unsigned int slen,
+                              u8 *dst, unsigned int *dlen)
+{
+	struct lzf_ctx * ctx = (struct lzf_ctx *) context;
+  u8 const *ip = src;
+  u8       *op = dst;
+  u8 const *const in_end  = ip + slen;
+  u8       *const out_end = op + *dlen;
+
+	if (ctx->first_call) {
+		ctx->first_call = 0;
+	}
+  do
+    {
+      unsigned int ctrl = *ip++;
+
+      if (ctrl < (1 << 5)) /* literal run */
+        {
+          ctrl++;
+
+          if (op + ctrl > out_end) {
+            *dlen = PAGE_SIZE;
+            return 0;
+	  }
+
+#if USE_MEMCPY
+          memcpy (op, ip, ctrl);
+          op += ctrl;
+          ip += ctrl;
+#else
+          do
+            *op++ = *ip++;
+          while (--ctrl);
+#endif
+        }
+      else /* back reference */
+        {
+          unsigned int len = ctrl >> 5;
+
+          u8 *ref = op - ((ctrl & 0x1f) << 8) - 1;
+
+          if (len == 7)
+            len += *ip++;
+          
+          ref -= *ip++;
+
+          if (op + len + 2 > out_end) {
+            *dlen = PAGE_SIZE;
+            return 0;
+	  }
+
+          if (ref < (u8 *)dst) {
+            *dlen = PAGE_SIZE;
+            return 0;
+	  }
+
+          *op++ = *ref++;
+          *op++ = *ref++;
+
+          do
+            *op++ = *ref++;
+          while (--len);
+        }
+    }
+  while (op < out_end && ip < in_end);
+
+  *dlen = op - (u8 *)dst;
+  return 0;
+}
+
+static struct crypto_alg alg = {
+	.cra_name		= "lzf",
+	.cra_flags		= CRYPTO_ALG_TYPE_COMPRESS,
+	.cra_ctxsize		= 0,
+	.cra_module		= THIS_MODULE,
+	.cra_list		= LIST_HEAD_INIT(alg.cra_list),
+	.cra_u			= { .compress = {
+	.coa_init		= lzf_compress_init,
+	.coa_exit		= lzf_compress_exit,
+	.coa_compress 		= lzf_compress,
+	.coa_decompress  	= lzf_decompress } }
+};
+
+static int __init init(void)
+{
+	return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+	crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LZF Compression Algorithm");
+MODULE_AUTHOR("Marc Alexander Lehmann & Nigel Cunningham");
+
diff -ruNp 625-crypto-api-work.patch-old/crypto/Makefile 625-crypto-api-work.patch-new/crypto/Makefile
--- 625-crypto-api-work.patch-old/crypto/Makefile	2005-06-20 11:46:49.000000000 +1000
+++ 625-crypto-api-work.patch-new/crypto/Makefile	2005-07-04 23:14:19.000000000 +1000
@@ -30,5 +30,6 @@ obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o
 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
 obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
+obj-$(CONFIG_CRYPTO_LZF) += lzf.o
 
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [47/48] Suspend2 2.1.9.8 for 2.6.12: 623-generic-block-io.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (40 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [39/48] Suspend2 2.1.9.8 for 2.6.12: 615-poweroff.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-10 18:24   ` Pavel Machek
  2005-07-06  2:20 ` [PATCH] [48/48] Suspend2 2.1.9.8 for 2.6.12: 624-filewriter.patch Nigel Cunningham
                   ` (9 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 624-filewriter.patch-old/kernel/power/suspend_file.c 624-filewriter.patch-new/kernel/power/suspend_file.c
--- 624-filewriter.patch-old/kernel/power/suspend_file.c	1970-01-01 10:00:00.000000000 +1000
+++ 624-filewriter.patch-new/kernel/power/suspend_file.c	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,1616 @@
+/*
+ * Filewriter.c
+ *
+ * Copyright 2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * Distributed under GPLv2.
+ * 
+ * This file encapsulates functions for usage of a simple file as a
+ * backing store. It is based upon the swapwriter, and shares the
+ * same basic working. Here, though, we have nothing to do with
+ * swapspace, and only one device to worry about.
+ *
+ * The user can just
+ *
+ * echo Suspend2 > /path/to/my_file
+ *
+ * and
+ *
+ * echo /path/to/my_file > /proc/software_suspend/filewriter_target
+ *
+ * then put what they find in /proc/software_suspend/resume2
+ * as their resume2= parameter in lilo.conf (and rerun lilo if using it).
+ *
+ * Having done this, they're ready to suspend and resume.
+ *
+ * TODO:
+ * - File resizing.
+ */
+
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/file.h>
+#include <linux/stat.h>
+#include <linux/mount.h>
+#include <linux/statfs.h>
+
+#include "suspend2_core/suspend.h"
+#include "suspend2_core/suspend2_common.h"
+#include "suspend2_core/version.h"
+#include "suspend2_core/proc.h"
+#include "suspend2_core/plugins.h"
+#include "suspend2_core/ui.h"
+#include "suspend2_core/extent.h"
+#include "suspend2_core/utility.h"
+#include "suspend2_core/io.h"
+
+#include "block_io.h"
+
+/*
+ *		General Declarations.
+ */
+
+static struct suspend_proc_data filewriter_proc_data[];
+static struct suspend_plugin_ops filewriterops;
+
+/*
+ *		External Declarations
+ */
+
+extern asmlinkage long sys_open(const char __user * filename, int flags, int mode);
+extern asmlinkage long sys_close(unsigned int fd);
+
+/*
+ *		Forward Declarations
+ */
+
+static int filewriter_invalidate_image(void);
+static int filewriter_storage_available(void);
+
+/*
+ *		Details of our target.
+ */
+
+char filewriter_target[256];
+static struct inode * target_inode;
+static int target_fd = -1;
+static struct block_device * target_bdev;
+static int used_devt = 0;
+static dev_t target_dev_t = 0;
+static int target_firstblock = 0;
+static int target_blocksize = PAGE_SIZE;
+static int target_storage_available = 0;
+static unsigned int target_blkbits;
+#define target_blockshift (PAGE_SHIFT - target_blkbits)
+#define target_blocksperpage (1 << target_blockshift)
+
+static int target_type = -1;
+
+/*
+static char * description[7] = {
+	"Socket",
+	"Link",
+	"Regular file",
+	"Block device",
+	"Directory",
+	"Character device",
+	"Fifo",
+};
+*/
+
+static char HaveImage[] = "HaveImage\n";
+static char NoImage[] =   "Suspend2\n";
+static const int resumed_before_byte = sizeof(HaveImage) + 1;
+#define sig_size resumed_before_byte
+
+/* Header_pages must be big enough for signature */
+static int header_pages, main_pages;
+
+static unsigned long * header_link = NULL;
+#define BYTES_PER_HEADER_PAGE (PAGE_SIZE - sizeof(sector_t))
+
+#define target_is_normal_file() (S_ISREG(target_inode->i_mode))
+
+/*
+ *		Readahead Variables
+ */
+
+// Higher Level
+static int readahead_index = 0, readahead_submit_index = 0;
+static int readahead_allocs = 0, readahead_frees = 0;
+
+static char * filewriter_buffer = NULL;
+static int filewriter_buffer_posn = 0;
+static int filewriter_page_index = 0;
+
+/*
+ * ---------------------------------------------------------------
+ *
+ *     Internal Data Structures
+ *
+ * ---------------------------------------------------------------
+ */
+
+/* header_data contains data that is needed to reload pagedir1, and
+ * is therefore saved in the suspend header.
+ *
+ * Pagedir2 data gets stored before pagedir1 (save order), and the first
+ * page for pagedir1 to use is set when pagedir2 is written (when we know how
+ * much storage it used). Since this first entry is almost certainly not at the
+ * start of a extent, the firstoffset variable below tells us where to start in
+ * the extent. All of this means we don't have to worry about getting different
+ * compression ratios for the kernel and cache (when compressing the image).
+ * We can simply allocate one pool of storage (size determined using expected
+ * compression ratio) and use it without worrying whether one pageset
+ * compresses better and the other worse (this is what happens). As long as the
+ * user gets the expected compression right, it will work.
+ */
+
+static struct {
+	/* Location of start of pagedir 1 */
+	struct extent * pd1start_block_extent;
+	int pd1start_extent_number;
+	unsigned long pd1start_block_offset;
+
+} filewriter_header_data;
+
+/* Extent chain for blocks */
+static struct extentchain block_chain;
+
+/*
+ * ---------------------------------------------------------------
+ *
+ *     Current state.
+ *
+ * ---------------------------------------------------------------
+ */
+
+/* Which pagedir are we saving/reloading? Needed so we can know whether to
+ * remember the last block used at the end of writing pageset2, and
+ * get that location when saving or reloading pageset1.*/
+static int current_stream = 0;
+
+/* Pointer to current entry being loaded/saved. */
+static struct extent * currentblockextent = NULL;
+static unsigned long currentblockoffset = 0;
+
+/* Header Page Information */
+static struct submit_params * first_header_submit_info = NULL,
+ * last_header_submit_info = NULL, * current_header_submit_info = NULL;
+
+/*
+ *		Helpers.
+ */
+
+/* 
+ * Return the type of target we have, an index into the descriptions
+ * above.
+ */
+static int get_target_type(struct inode * inode)
+{
+	switch (inode->i_mode & S_IFMT) {
+		case S_IFSOCK:
+			target_type = 0;
+			break;
+		case S_IFLNK:
+			target_type = 1;
+			break;
+		case S_IFREG:
+			target_type = 2;
+			break;
+		case S_IFBLK:
+			target_type = 3;
+			break;
+		case S_IFDIR:
+			target_type = 4;
+			break;
+		case S_IFCHR:
+			target_type = 5;
+			break;
+		case S_IFIFO:
+			target_type = 6;
+			break;
+	}
+	return target_type;
+}
+	
+#define target_is_usable (!(target_type == 1 || target_type == 4))
+#define target_num_sectors (target_inode->i_size >> target_blkbits)
+
+static int size_ignoring_sparseness(void)
+{
+	int mappable = 0, i;
+	
+	if (target_is_normal_file()) {
+		int extent_min = -1, extent_max = -1;
+
+		for (i = 0; i <= target_num_sectors; i++) {
+			sector_t new_sector = bmap(target_inode, i);
+			if (!new_sector) {
+				if (i == extent_max + 1)
+					extent_max++;
+				else
+					extent_min = extent_max = i;
+			} else
+				mappable++;
+		}
+	
+		return mappable >> (PAGE_SHIFT - target_blkbits);
+	} else
+		return filewriter_storage_available();
+}
+
+static void get_main_pool_phys_params(void)
+{
+	int i;
+	
+	if (block_chain.first)
+		put_extent_chain(&block_chain);
+
+	if (target_is_normal_file()) {
+		int header_sectors = (header_pages << target_blockshift);
+		int extent_min = -1, extent_max = -1, real_sector = 0;
+
+
+		for (i = 0; i <= target_num_sectors; i++) {
+			sector_t new_sector =
+				bmap(target_inode, header_sectors + i);
+			
+			/* 
+			 * I'd love to be able to fill in holes and resize 
+			 * files, but not yet...
+			 */
+
+			if (!new_sector)
+				continue;
+			
+			real_sector++;
+
+			if (real_sector < header_sectors)
+				continue;
+
+			if (new_sector == extent_max + 1)
+				extent_max++;
+			else {
+				if (extent_min > -1)
+					append_extent_to_extent_chain(
+						&block_chain,
+						extent_min, extent_max);
+				extent_min = extent_max = new_sector;
+			}
+		}
+		if (extent_min > -1)
+			append_extent_to_extent_chain(&block_chain,
+				       extent_min, extent_max);
+	} else
+		if (target_storage_available > 0) {
+			unsigned long new_start =
+			 last_header_submit_info ?
+			 last_header_submit_info->block[target_blocksperpage -1]
+				+ 1: 0;
+
+			append_extent_to_extent_chain(&block_chain,
+			 new_start, new_start +
+			 (min(main_pages, target_storage_available) << 
+			  		target_blockshift) - 1);
+		}
+}
+
+static void get_target_info(void)
+{
+	if (target_bdev) {
+		/* 
+		 * Don't replace the inode if we got the bdev from opening
+		 * a file.
+		 */
+		if (!target_inode)
+			target_inode = target_bdev->bd_inode;
+		target_type = get_target_type(target_inode);
+		target_blkbits = target_bdev->bd_inode->i_blkbits;
+		target_storage_available = size_ignoring_sparseness();
+	} else {
+		target_type = -1;
+		target_inode = NULL;
+		target_blkbits = 0;
+		target_storage_available = 0;
+	}	
+}
+
+static int set_target_blocksize(void)
+{
+	if ((suspend_bio_ops.get_block_size(target_bdev) 
+					!= target_blocksize) &&
+	    (suspend_bio_ops.set_block_size(target_bdev, target_blocksize)
+	    			 == -EINVAL)) {
+		printk(KERN_ERR name_suspend "Filewriter: Failed to set the blocksize.\n");
+		return 1;
+	}
+
+	return 0;
+		
+}
+
+static int try_to_open_target_device(void)
+{
+	if (!target_dev_t)
+		return 1;
+
+	if (!target_bdev) {
+		target_bdev = open_by_devnum(target_dev_t, FMODE_READ);
+
+		if (IS_ERR(target_bdev)) {
+			target_bdev = NULL;
+			return 1;
+		}
+		used_devt = 1;
+
+		if (set_target_blocksize()) {
+			blkdev_put(target_bdev);
+			target_bdev = NULL;
+			return 1;
+		}
+	}
+
+	get_target_info();
+
+	return 0;
+}
+
+static int try_to_parse_target_dev_t(char * commandline)
+{
+	struct kstat stat;
+	int error;
+
+	target_dev_t = name_to_dev_t(commandline);
+
+	if (!target_dev_t) {
+		error = vfs_stat(commandline, &stat);
+		if (!error)
+			target_dev_t = stat.rdev;
+	}
+
+	if (!target_dev_t) {
+		if (test_suspend_state(SUSPEND_TRYING_TO_RESUME))
+			suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+				"Failed to translate \"%s\" into a device id.\n",
+				commandline);
+		else
+			printk(name_suspend "Can't translate \"%s\" into a device id yet.\n",
+					commandline);
+		return 1;
+	}
+	
+	try_to_open_target_device();
+
+	if (IS_ERR(target_bdev)) {
+		printk("Open by devnum returned %p given %x.\n",
+				target_bdev, target_dev_t);
+		target_bdev = NULL;
+		if (test_suspend_state(SUSPEND_BOOT_TIME))
+			suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+				"Failed to get access to the device on which"
+				" Software Suspend's header should be found.");
+		else
+			printk("Failed to get access to the device on which "
+				"Software Suspend's header should be found.\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+static void filewriter_noresume_reset(void)
+{
+ 	/* 
+	 * If we have read part of the image, we might have filled header_data with
+	 * data that should be zeroed out.
+	 */
+
+	memset((char *) &filewriter_header_data, 0, sizeof(filewriter_header_data));
+}
+
+/*
+ *
+ */
+
+int parse_signature(char * header, int restore)
+{
+	int have_image = !memcmp(HaveImage, header, sizeof(HaveImage) - 1);
+	int non_image_header = !memcmp(NoImage, header, sizeof(NoImage) - 1);
+
+	if (!have_image && !non_image_header)
+		return -1;
+
+	if (non_image_header)
+		return 0;
+	
+	clear_suspend_state(SUSPEND_RESUMED_BEFORE);
+
+	if (header[resumed_before_byte] & 1)
+		set_suspend_state(SUSPEND_RESUMED_BEFORE);
+
+	/* Invalidate Image */
+	if (restore)
+		strcpy(header, NoImage);
+
+	return 1;
+}
+
+/*
+ * prepare_signature
+ */
+
+static int prepare_signature(struct submit_params * header_page_info,
+		char * current_header)
+{
+	/* 
+	 * Explicitly put the \0 that clears the 'tried to resume from
+	 * this image before' flag.
+	 */
+	strncpy(current_header, HaveImage, sizeof(HaveImage));
+	current_header[resumed_before_byte] = 0;
+	return 0;
+}
+
+static void free_header_data(void)
+{
+	if (!first_header_submit_info)
+		return;
+
+	while (first_header_submit_info) {
+		struct submit_params * next = first_header_submit_info->next;
+		kfree(first_header_submit_info);
+		first_header_submit_info = next;
+	}
+	
+	suspend_message(SUSPEND_WRITER, SUSPEND_LOW, 1,
+			" Freed swap pages in free_header_data.\n");
+	first_header_submit_info = last_header_submit_info = NULL;
+	return;
+}
+
+static int filewriter_storage_available(void)
+{
+	int result = 0;
+
+	if (!target_inode)
+		return 0;
+
+	switch (target_type) {
+		case 0:
+		case 5:
+		case 6: /* Socket, Char, Fifi */
+			return -1;
+		case 2: /* Regular file: current size - holes + free space on part */
+			result = target_storage_available;
+			break;
+		case 3: /* Block device */
+			if (target_bdev->bd_disk) {
+				if (target_bdev->bd_part)
+					result = (unsigned long)target_bdev->bd_part->nr_sects >> (PAGE_SHIFT - 9);
+				else
+					result = (unsigned long)target_bdev->bd_disk->capacity >> (PAGE_SHIFT - 9);
+			} else {
+				printk("bdev->bd_disk null.\n");
+				return 0;
+			}
+	}
+
+	return result;
+}
+
+static int filewriter_storage_allocated(void)
+{
+	int result;
+
+	if (!target_inode)
+		return 0;
+
+	if (target_is_normal_file()) {
+		result = (int) target_storage_available;
+	} else
+		result = header_pages + main_pages;
+
+	return result;
+}
+
+static int filewriter_initialise(int starting_cycle)
+{
+	if (!starting_cycle)
+		return 0;
+
+	target_fd = sys_open(filewriter_target, O_RDWR, 0);
+
+	if (target_fd < 0) {
+		printk("Open file %s returned %d.\n", filewriter_target, target_fd);
+		return target_fd;
+	}
+
+	target_inode = current->files->fd[target_fd]->f_dentry->d_inode;
+	BUG_ON(target_bdev);
+	target_bdev = target_inode->i_bdev ? target_inode->i_bdev : target_inode->i_sb->s_bdev;
+	set_target_blocksize();
+	get_target_info();
+
+	return 0;
+}
+
+static void filewriter_cleanup(int finishing_cycle)
+{
+	if (target_bdev) {
+		if (used_devt) {
+			blkdev_put(target_bdev);
+			used_devt = 0;
+		}
+		target_bdev = NULL;
+		get_target_info();
+	}
+
+	if (!finishing_cycle)
+		return;
+
+	if (target_fd >= 0)
+		sys_close(target_fd);
+
+	target_fd = -1;
+}
+
+static int filewriter_release_storage(void)
+{
+	if ((TEST_ACTION_STATE(SUSPEND_KEEP_IMAGE)) && test_suspend_state(SUSPEND_NOW_RESUMING))
+		return 0;
+
+	/* Free metadata */
+	free_header_data();
+
+	put_extent_chain(&block_chain);
+
+	header_pages = main_pages = 0;
+	return 0;
+}
+
+static int filewriter_allocate_header_space(int space_requested)
+{
+	int i, j, pages_to_get;
+	int ret = 0;
+
+	/* We only steal pages from the main pool. If it doesn't have any yet... */
+	
+	if (!block_chain.first)
+		return 0;
+
+	pages_to_get = space_requested - header_pages;
+
+	if (pages_to_get < 1)
+		return 0;
+
+	for (i= header_pages; i < space_requested; i++) {
+		struct submit_params * new_submit_param;
+
+		/* Get a submit structure */
+		new_submit_param = kmalloc(sizeof(struct submit_params), GFP_ATOMIC);
+		
+		if (!new_submit_param) {
+			printk("Failed to kmalloc a struct submit param.\n");
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		memset(new_submit_param, 0, sizeof(struct submit_params));
+
+		if (last_header_submit_info) {
+			last_header_submit_info->next = new_submit_param;
+			last_header_submit_info = new_submit_param;
+		} else
+			last_header_submit_info = first_header_submit_info =
+				new_submit_param;
+
+		for (j = 0; j < target_blocksperpage; j++) {
+			unsigned long newvalue;
+
+			/*
+			 *  Steal one from main extent chain. If, as a result,
+			 *  it is too small, more storage will be allocated or
+			 *  memory eaten.
+			 */
+
+			if (block_chain.first->minimum <
+					block_chain.first->maximum) {
+				newvalue = block_chain.first->minimum;
+				block_chain.first->minimum++;
+			} else {
+				struct extent * oldfirst =
+					block_chain.first;
+				block_chain.first = oldfirst->next;
+				block_chain.frees++;
+				if (block_chain.last == oldfirst)
+					block_chain.last = NULL;
+				newvalue = oldfirst->minimum;
+				put_extent(oldfirst);
+			}
+			
+			block_chain.size--;
+
+			new_submit_param->block[j] = newvalue;
+		}
+
+		new_submit_param->dev = target_bdev;
+		new_submit_param->readahead_index = -1;
+
+		header_pages++;
+
+		suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
+			" Got header page %d/%d. Dev is %x. Block is %lu. "
+			"Target block size is %d.\n",
+			i, space_requested,
+			new_submit_param->dev,
+			new_submit_param->block[0],
+			new_submit_param->dev->bd_block_size);
+
+		if (!block_chain.size)
+			break;
+	}
+out:
+	return ret;
+}
+
+static int filewriter_allocate_storage(int space_requested)
+{
+	int result = 0;
+	int blocks_to_get = (space_requested << target_blockshift) - block_chain.size;
+	
+	/* Only release_storage reduces the size */
+	if (blocks_to_get < 1)
+		return 0;
+
+	main_pages = space_requested;
+
+	get_main_pool_phys_params();
+
+	suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
+		"Finished with block_chain.size == %d.\n",
+		block_chain.size);
+
+	if (block_chain.size < ((header_pages + main_pages) << target_blockshift))
+		result = -ENOSPC;
+
+	return result;
+}
+
+static int filewriter_write_header_chunk(char * buffer, int buffer_size);
+static int filewriter_write_header_init(void)
+{
+	char new_sig[sig_size];
+	struct extent * extent;
+	
+	filewriter_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	header_link =
+		(unsigned long *) (filewriter_buffer + BYTES_PER_HEADER_PAGE);
+	filewriter_page_index = 1;
+	filewriter_buffer_posn = 0;
+
+	current_header_submit_info = first_header_submit_info;
+	
+	/* We change it once the whole header is written */
+	strcpy(new_sig, NoImage);
+	filewriter_write_header_chunk(new_sig, sig_size);
+
+	/* Must calculate extent number before writing the header! */
+	filewriter_header_data.pd1start_extent_number = 1;
+	extent = block_chain.first;
+
+	while (extent != filewriter_header_data.pd1start_block_extent) {
+		filewriter_header_data.pd1start_extent_number++;
+		extent = extent->next;
+	}
+
+	/* Info needed to bootstrap goes at the start of the header.
+	 * First we save the 'header_data' struct, including the number
+	 * of header pages. Then we save the structs containing data needed
+	 * for reading the header pages back.
+	 * Note that even if header pages take more than one page, when we
+	 * read back the info, we will have restored the location of the
+	 * next header page by the time we go to use it.
+	 */
+	filewriter_write_header_chunk((char *) &filewriter_header_data, 
+			sizeof(filewriter_header_data));
+
+	return 0;
+}
+
+static int filewriter_write_header_chunk(char * buffer, int buffer_size)
+{
+	int bytes_left = buffer_size;
+	
+	/* 
+	 * We buffer the writes until a page is full and to use the last
+	 * sizeof(swp_entry_t) bytes for links between pages. This is 
+	 * totally transparent to the caller.
+	 *
+	 * Note also that buffer_size can be > PAGE_SIZE.
+	 */
+
+	suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 0,
+		"\nStart of write_header_chunk loop with %d bytes to store.\n",
+		buffer_size);
+
+	while (bytes_left) {
+		char * source_start = buffer + buffer_size - bytes_left;
+		char * dest_start = filewriter_buffer + filewriter_buffer_posn;
+		int dest_capacity = BYTES_PER_HEADER_PAGE - filewriter_buffer_posn;
+		sector_t next_header_page;
+		if (bytes_left <= dest_capacity) {
+			memcpy(dest_start, source_start, bytes_left);
+			filewriter_buffer_posn += bytes_left;
+			return 0;
+		}
+	
+		/* A page is full */
+		memcpy(dest_start, source_start, dest_capacity);
+		bytes_left -= dest_capacity;
+
+		BUG_ON(!current_header_submit_info);
+
+		if (!current_header_submit_info->next) {
+			*header_link = 0;
+		} else {
+			next_header_page =
+				current_header_submit_info->next->block[0];
+
+			*header_link = next_header_page;
+		}
+
+		suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 0,
+			"Writing header page %d. "
+			"Dev is %x. Block is %lu. Blocksperpage is %d. Bd_block_size is %d.\n",
+			filewriter_page_index,
+			current_header_submit_info->dev->bd_dev,
+			current_header_submit_info->block[0],
+			target_blocksperpage,
+			current_header_submit_info->dev->bd_block_size);
+		
+		current_header_submit_info->page =
+			virt_to_page(filewriter_buffer);
+		check_shift_keys(0, NULL);
+		suspend_bio_ops.submit_io(WRITE, current_header_submit_info, 0);
+
+		filewriter_buffer_posn = 0;
+		filewriter_page_index++;
+		current_header_submit_info = current_header_submit_info->next;
+	}
+
+	return 0;
+}
+
+static int filewriter_write_header_cleanup(void)
+{
+	/* Write any unsaved data */
+	if (filewriter_buffer_posn) {
+		*header_link = 0;
+
+		suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 0,
+			"Writing header page %d. "
+			"Dev is %x. Block is %lu. Blocksperpage is %d.\n",
+			filewriter_page_index,
+			current_header_submit_info->dev->bd_dev,
+			current_header_submit_info->block[0],
+			target_blocksperpage);
+		
+		current_header_submit_info->page =
+			virt_to_page(filewriter_buffer);
+		suspend_bio_ops.submit_io(WRITE, 
+				current_header_submit_info, 0);
+	}
+
+	suspend_bio_ops.finish_all_io();
+
+	/* Adjust image header */
+	suspend_bio_ops.bdev_page_io(READ, target_bdev, target_firstblock,
+			virt_to_page(filewriter_buffer));
+
+	prepare_signature(first_header_submit_info, filewriter_buffer);
+		
+	suspend_bio_ops.bdev_page_io(WRITE, target_bdev, target_firstblock,
+			virt_to_page(filewriter_buffer));
+
+	free_pages((unsigned long) filewriter_buffer, 0);
+	filewriter_buffer = NULL;
+	header_link = NULL;
+	
+	suspend_bio_ops.finish_all_io();
+
+	return 0;
+}
+
+/* ------------------------- HEADER READING ------------------------- */
+
+/*
+ * read_header_init()
+ * 
+ * Description:
+ * 1. Attempt to read the device specified with resume2=.
+ * 2. Check the contents of the swap header for our signature.
+ * 3. Warn, ignore, reset and/or continue as appropriate.
+ * 4. If continuing, read the filewriter configuration section
+ *    of the header and set up block device info so we can read
+ *    the rest of the header & image.
+ *
+ * Returns:
+ * May not return if user choose to reboot at a warning.
+ * -EINVAL if cannot resume at this time. Booting should continue
+ * normally.
+ */
+
+static int filewriter_read_header_init(void)
+{
+	filewriter_page_index = 1;
+
+	filewriter_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	filewriter_buffer_posn = sig_size;
+
+	/* Read filewriter configuration */
+	suspend_bio_ops.bdev_page_io(READ, target_bdev, target_firstblock,
+			virt_to_page((unsigned long) filewriter_buffer));
+	
+	suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 0,
+		"Retrieving %d bytes from %x:%x to page %d, %p-%p.\n",
+		target_bdev->bd_dev, target_firstblock,
+		sizeof(filewriter_header_data),
+		filewriter_page_index,
+		filewriter_buffer, filewriter_buffer + sizeof(filewriter_header_data) - 1);
+	memcpy(&filewriter_header_data,
+			filewriter_buffer + filewriter_buffer_posn,
+			sizeof(filewriter_header_data));
+	
+	filewriter_buffer_posn += sizeof(filewriter_header_data);
+
+	return 0;
+}
+
+static int filewriter_read_header_chunk(char * buffer, int buffer_size)
+{
+	int bytes_left = buffer_size, ret = 0;
+	
+	/* Read a chunk of the header */
+	while ((bytes_left) && (!ret)) {
+		sector_t next =
+		   *((sector_t *) (filewriter_buffer + BYTES_PER_HEADER_PAGE));
+		char * dest_start = buffer + buffer_size - bytes_left;
+		char * source_start =
+			filewriter_buffer + filewriter_buffer_posn;
+		int source_capacity =
+			BYTES_PER_HEADER_PAGE - filewriter_buffer_posn;
+
+		if (bytes_left <= source_capacity) {
+			memcpy(dest_start, source_start, bytes_left);
+			filewriter_buffer_posn += bytes_left;
+			return buffer_size;
+		}
+
+		/* Next to read the next page */
+		memcpy(dest_start, source_start, source_capacity);
+		bytes_left -= source_capacity;
+
+		filewriter_page_index++;
+
+		suspend_bio_ops.bdev_page_io(READ, target_bdev,
+				next, virt_to_page(filewriter_buffer));
+
+		filewriter_buffer_posn = 0;
+	}
+
+	return buffer_size - bytes_left;
+}
+
+static int filewriter_read_header_cleanup(void)
+{
+	free_pages((unsigned long) filewriter_buffer, 0);
+	return 0;
+}
+
+static int filewriter_serialise_extents(void)
+{
+	serialise_extent_chain(&block_chain);
+	return 0;
+}
+
+static int filewriter_load_extents(void)
+{
+	int i = 1;
+	struct extent * extent;
+	
+	load_extent_chain(&block_chain);
+
+	extent = block_chain.first;
+
+	while (i < filewriter_header_data.pd1start_extent_number) {
+		extent = extent->next;
+		i++;
+	}
+
+	filewriter_header_data.pd1start_block_extent = extent;
+
+	return 0;
+}
+
+static int filewriter_write_init(int stream_number)
+{
+	if (stream_number == 1) {
+		currentblockextent = filewriter_header_data.pd1start_block_extent;
+		currentblockoffset = filewriter_header_data.pd1start_block_offset;
+	} else {
+		currentblockextent = block_chain.first;
+		currentblockoffset = currentblockextent->minimum;
+	}
+
+	BUG_ON(!currentblockextent);
+
+	filewriter_page_index = 1;
+	current_stream = stream_number;
+
+	suspend_bio_ops.reset_io_stats();
+
+	return 0;
+}
+
+static int filewriter_write_chunk(struct page * buffer_page)
+{
+	int i;
+	struct submit_params submit_params;
+
+	BUG_ON(!currentblockextent);
+	submit_params.readahead_index = -1;
+	submit_params.page = buffer_page;
+	submit_params.dev = target_bdev;
+		
+	/* Get the blocks */
+	for (i = 0; i < target_blocksperpage; i++) {
+		submit_params.block[i] = currentblockoffset;
+		GET_EXTENT_NEXT(currentblockextent, currentblockoffset);
+	}
+
+	if(!submit_params.block[0])
+		return -EIO;
+
+	if (TEST_ACTION_STATE(SUSPEND_TEST_FILTER_SPEED))
+		return 0;
+		
+	suspend_bio_ops.submit_io(WRITE, &submit_params, 0);
+
+	filewriter_page_index++;
+
+	return 0;
+}
+
+static int filewriter_write_cleanup(void)
+{
+	if (current_stream == 2) {
+		filewriter_header_data.pd1start_block_extent = currentblockextent;
+		filewriter_header_data.pd1start_block_offset = currentblockoffset;
+	}
+	
+	suspend_bio_ops.finish_all_io();
+	
+	suspend_bio_ops.check_io_stats();
+
+	return 0;
+}
+
+static int filewriter_read_init(int stream_number)
+{
+	if (stream_number == 1) {
+		currentblockextent = filewriter_header_data.pd1start_block_extent;
+		currentblockoffset = filewriter_header_data.pd1start_block_offset;
+	} else {
+		currentblockextent = NULL;
+		currentblockoffset = 0;
+		currentblockextent =
+			block_chain.first;
+		currentblockoffset = currentblockextent->minimum;
+	}
+
+	BUG_ON(!currentblockextent);
+
+	filewriter_page_index = 1;
+
+	suspend_bio_ops.reset_io_stats();
+
+	readahead_index = readahead_submit_index = -1;
+	readahead_allocs = readahead_frees = 0;
+
+	return 0;
+}
+
+static int filewriter_begin_read_chunk(struct page * page, 
+		int readahead_index, int sync)
+{
+	int i;
+	struct submit_params submit_params;
+
+	BUG_ON(!currentblockextent);
+	
+	submit_params.readahead_index = readahead_index;
+	submit_params.page = page;
+	submit_params.dev = target_bdev;
+		
+	/* Get the blocks. There is no chance that they span chains. */
+	for (i = 0; i < target_blocksperpage; i++) {
+		submit_params.block[i] = currentblockoffset;
+		GET_EXTENT_NEXT(currentblockextent, currentblockoffset);
+	}
+
+	if ((i = suspend_bio_ops.submit_io(READ, &submit_params, sync)))
+		return -EPERM;
+
+	filewriter_page_index++;
+
+	check_shift_keys(0, NULL);
+
+	return 0;
+}
+
+/* Note that we ignore the sync parameter. We are implementing
+ * read ahead, and will always wait until our readhead buffer has
+ * been read before returning.
+ */
+
+static int filewriter_read_chunk(struct page * buffer_page, int sync)
+{
+	static int last_result;
+	unsigned long * virt;
+
+	if (sync == SUSPEND_ASYNC)
+		return filewriter_begin_read_chunk(buffer_page, -1, sync);
+
+	/* Start new readahead while we wait for our page */
+	if (readahead_index == -1) {
+		last_result = 0;
+		readahead_index = readahead_submit_index = 0;
+	}
+
+	/* Start a new readahead? */
+	if (last_result) {
+		/* We failed to submit a read, and have cleaned up
+		 * all the readahead previously submitted */
+		if (readahead_submit_index == readahead_index)
+			return -EPERM;
+		goto wait;
+	}
+	
+	do {
+		if (suspend_bio_ops.prepare_readahead(readahead_submit_index))
+			break;
+
+		readahead_allocs++;
+
+		last_result = filewriter_begin_read_chunk(
+			suspend_bio_ops.readahead_pages[readahead_submit_index], 
+			readahead_submit_index, SUSPEND_ASYNC);
+		if (last_result) {
+			printk("Begin read chunk for page %d returned %d.\n",
+				readahead_submit_index, last_result);
+			suspend_bio_ops.cleanup_readahead(readahead_submit_index);
+			break;
+		}
+
+		readahead_submit_index++;
+
+		if (readahead_submit_index == MAX_READAHEAD)
+			readahead_submit_index = 0;
+
+	} while((!last_result) && (readahead_submit_index != readahead_index) &&
+			(!suspend_bio_ops.readahead_ready(readahead_index)));
+
+wait:
+	suspend_bio_ops.wait_on_readahead(readahead_index);
+
+	virt = kmap_atomic(buffer_page, KM_USER1);
+	memcpy(virt, page_address(suspend_bio_ops.readahead_pages[readahead_index]),
+			PAGE_SIZE);
+	kunmap_atomic(virt, KM_USER1);
+
+	suspend_bio_ops.cleanup_readahead(readahead_index);
+
+	readahead_frees++;
+
+	readahead_index++;
+	if (readahead_index == MAX_READAHEAD)
+		readahead_index = 0;
+
+	return 0;
+}
+
+static int filewriter_read_cleanup(void)
+{
+	suspend_bio_ops.finish_all_io();
+	while (readahead_index != readahead_submit_index) {
+		suspend_bio_ops.cleanup_readahead(readahead_index);
+		readahead_frees++;
+		readahead_index++;
+		if (readahead_index == MAX_READAHEAD)
+			readahead_index = 0;
+	}
+	suspend_bio_ops.check_io_stats();
+	BUG_ON(readahead_allocs != readahead_frees);
+	return 0;
+}
+
+/* filewriter_invalidate_image
+ * 
+ */
+static int filewriter_invalidate_image(void)
+{
+	char * cur;
+	int result = 0;
+	
+	cur = (char *) get_zeroed_page(GFP_ATOMIC);
+	if (!cur) {
+		printk("Unable to allocate a page for restoring the image signature.\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * If nr_suspends == 0, we must be booting, so no swap pages
+	 * will be recorded as used yet.
+	 */
+
+	if (nr_suspends > 0)
+		filewriter_release_storage();
+
+	/* 
+	 * We don't do a sanity check here: we want to restore the swap 
+	 * whatever version of kernel made the suspend image.
+	 * 
+	 * We need to write swap, but swap may not be enabled so
+	 * we write the device directly
+	 */
+	
+	suspend_bio_ops.bdev_page_io(READ, target_bdev,
+			target_firstblock, virt_to_page(cur));
+
+	result = parse_signature(cur, 1);
+		
+	if (result == -1)
+		goto out;
+
+	strcpy(cur, NoImage);
+	cur[resumed_before_byte] = 0;
+
+	suspend_bio_ops.bdev_page_io(WRITE, target_bdev, target_firstblock,
+			virt_to_page(cur));
+
+	if (!nr_suspends)
+		printk(KERN_WARNING name_suspend "Image invalidated.\n");
+out:
+	suspend_bio_ops.finish_all_io();
+	free_pages((unsigned long) cur, 0);
+	return 0;
+}
+
+/*
+ * workspace_size
+ *
+ * Description:
+ * Returns the number of bytes of RAM needed for this
+ * code to do its work. (Used when calculating whether
+ * we have enough memory to be able to suspend & resume).
+ *
+ */
+static unsigned long filewriter_memory_needed(void)
+{
+	return 0;
+}
+
+/* Print debug info
+ *
+ * Description:
+ */
+
+static int filewriter_print_debug_stats(char * buffer, int size)
+{
+	int len = 0;
+	struct sysinfo sysinfo;
+	
+	if (active_writer != &filewriterops) {
+		len = suspend_snprintf(buffer, size, "- Filewriter inactive.\n");
+		return len;
+	}
+
+	len = suspend_snprintf(buffer, size, "- Filewriter active.\n");
+
+	si_swapinfo(&sysinfo);
+	
+	len+= suspend_snprintf(buffer+len, size-len, "  Storage available for image: %ld pages.\n",
+			sysinfo.freeswap + filewriter_storage_allocated());
+
+	return len;
+	return 0;
+}
+
+/*
+ * Storage needed
+ *
+ * Returns amount of space in the image header required
+ * for the filewriter's data.
+ *
+ * We ensure the space is allocated, but actually save the
+ * data from write_header_init and therefore don't also define a
+ * save_config_info routine.
+ */
+static unsigned long filewriter_storage_needed(void)
+{
+	return strlen(filewriter_target) + 1;
+}
+
+/*
+ * Image_exists
+ *
+ */
+
+static int filewriter_image_exists(void)
+{
+	int signature_found;
+	char * diskpage;
+	
+	if (try_to_open_target_device())
+		return 0;
+
+	diskpage = (char *) get_zeroed_page(GFP_ATOMIC);
+
+	/* FIXME: Make sure bdev_page_io handles wrong parameters */
+	suspend_bio_ops.bdev_page_io(READ, target_bdev,
+			target_firstblock, virt_to_page(diskpage));
+	suspend_bio_ops.finish_all_io();
+	signature_found = parse_signature(diskpage, 0);
+	free_pages((unsigned long) diskpage, 0);
+
+	if (!signature_found) {
+		return 0;	/* non fatal error */
+	} else if (signature_found == -1) {
+		printk(KERN_ERR name_suspend
+			"Unable to find a signature. Could you have moved "
+			"the file?\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+/*
+ * Mark resume attempted.
+ *
+ * Record that we tried to resume from this image.
+ */
+
+static void filewriter_mark_resume_attempted(void)
+{
+	char * diskpage;
+	int signature_found;
+	
+	if (!target_dev_t) {
+		printk("Not even trying to record attempt at resuming"
+				" because target_dev_t is not set.\n");
+		return;
+	}
+	
+	diskpage = (char *) get_zeroed_page(GFP_ATOMIC);
+
+	/* FIXME: Make sure bdev_page_io handles wrong parameters */
+	suspend_bio_ops.bdev_page_io(READ, target_bdev, target_firstblock, virt_to_page(diskpage));
+	signature_found = parse_signature(diskpage, 0);
+
+	switch (signature_found) {
+		case 1:
+			diskpage[resumed_before_byte] |= 1;
+			break;
+	}
+	
+	suspend_bio_ops.bdev_page_io(WRITE, target_bdev, target_firstblock,
+			virt_to_page(diskpage));
+	suspend_bio_ops.finish_all_io();
+	free_pages((unsigned long) diskpage, 0);
+	return;
+}
+
+/*
+ * Parse Image Location
+ *
+ * Attempt to parse a resume2= parameter.
+ * Swap Writer accepts:
+ * resume2=swap:DEVNAME[:FIRSTBLOCK][@BLOCKSIZE]
+ *
+ * Where:
+ * DEVNAME is convertable to a dev_t by name_to_dev_t
+ * FIRSTBLOCK is the location of the first block in the swap file
+ * (specifying for a swap partition is nonsensical but not prohibited).
+ * BLOCKSIZE is the logical blocksize >= 512 & <= PAGE_SIZE, 
+ * mod 512 == 0 of the device.
+ * Data is validated by attempting to read a swap header from the
+ * location given. Failure will result in filewriter refusing to
+ * save an image, and a reboot with correct parameters will be
+ * necessary.
+ */
+
+static int filewriter_parse_image_location(char * commandline, int only_writer)
+{
+	char *thischar, *devstart = NULL, *colon = NULL, *at_symbol = NULL;
+	char * diskpage = NULL;
+	int signature_found, result = -EINVAL, temp_result;
+
+	if (strncmp(commandline, "file:", 5)) {
+		if (!only_writer)
+			return 1;
+	} else
+		commandline += 5;
+
+	devstart = thischar = commandline;
+	while ((*thischar != ':') && (*thischar != '@') &&
+		((thischar - commandline) < 250) && (*thischar))
+		thischar++;
+
+	if (*thischar == ':') {
+		colon = thischar;
+		*colon = 0;
+		thischar++;
+	}
+
+	while ((*thischar != '@') && ((thischar - commandline) < 250) && (*thischar))
+		thischar++;
+
+	if (*thischar == '@') {
+		at_symbol = thischar;
+		*at_symbol = 0;
+	}
+	
+	if (colon)
+		target_firstblock = (int) simple_strtoul(colon + 1, NULL, 0);
+	else
+		target_firstblock = 0;
+
+	if (at_symbol) {
+		target_blocksize = (int) simple_strtoul(at_symbol + 1, NULL, 0);
+		if (target_blocksize & 0x1FF)
+			printk("Filewriter: Blocksizes are usually a multiple of 512. Don't expect this to work!\n");
+	} else
+		target_blocksize = 4096;
+	
+	temp_result = try_to_parse_target_dev_t(devstart);
+
+	if (colon)
+		*colon = ':';
+	if (at_symbol)
+		*at_symbol = '@';
+
+	if (temp_result)
+		goto out;
+
+	diskpage = (char *) get_zeroed_page(GFP_ATOMIC);
+	temp_result = suspend_bio_ops.bdev_page_io(READ, target_bdev, target_firstblock, virt_to_page(diskpage));
+
+	suspend_bio_ops.finish_all_io();
+	
+	if (temp_result) {
+		printk(KERN_ERR name_suspend "Filewriter: Failed to submit I/O.\n");
+		goto out;
+	}
+
+	signature_found = parse_signature(diskpage, 0);
+
+	if (signature_found != -1) {
+		printk(KERN_ERR name_suspend "Filewriter: File signature found.\n");
+		result = 0;
+	} else
+		printk(KERN_ERR name_suspend "Filewriter: Sorry. No signature found at specified location.\n");
+
+out:
+	if (diskpage)
+		free_page((unsigned long) diskpage);
+	return result;
+}
+
+static void set_filewriter_target(int test_it)
+{
+	char * buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	char * buffer2 = (char *) get_zeroed_page(GFP_ATOMIC);
+	int offset = 0, fd;
+	int sector;
+
+	if(target_bdev)
+		filewriter_cleanup(0);
+
+	fd = sys_open(filewriter_target, O_RDONLY, 0);
+
+	if (fd < 0) {
+		printk("Filewriter: Unable to open %s.\n", filewriter_target);
+		goto cleanup1;
+	}
+
+	*resume2_file = 0;
+	
+	target_inode = current->files->fd[fd]->f_dentry->d_inode;
+	target_type = get_target_type(target_inode);
+	
+	if (!target_is_usable) {
+		printk("Filewriter: %s is a link or directory. You can't suspend to them!\n",
+				filewriter_target);
+		goto cleanup2;
+	}
+
+	target_bdev = target_inode->i_bdev ? target_inode->i_bdev : target_inode->i_sb->s_bdev;
+	sector = bmap(target_inode, 0);
+
+	if (target_bdev && sector) {
+
+		target_blkbits = target_bdev->bd_inode->i_blkbits;
+
+		suspend_bio_ops.bdev_page_io(READ, target_bdev, sector,
+			virt_to_page(buffer));
+
+		bdevname(target_bdev, buffer2);
+		offset += snprintf(buffer + offset, PAGE_SIZE - offset, 
+				"/dev/%s", buffer2);
+		
+		if (sector)
+			offset += snprintf(buffer + offset, PAGE_SIZE - offset,
+				":0x%x", sector);
+
+		if (target_inode->i_sb->s_blocksize != PAGE_SIZE)
+			offset += snprintf(buffer + offset, PAGE_SIZE - offset,
+				"@%lu", target_inode->i_sb->s_blocksize);
+		
+	} else
+		offset += snprintf(buffer + offset, PAGE_SIZE - offset,
+				"%s is not a valid target.", filewriter_target);
+			
+	sprintf(resume2_file, "file:%s", buffer);
+
+cleanup2:
+	if (test_it)
+		sys_close(fd);
+
+cleanup1:
+	free_pages((unsigned long) buffer, 0);
+	free_pages((unsigned long) buffer2, 0);
+}
+
+/* filewriter_save_config_info
+ *
+ * Description:	Save the target's name, not for resume time, but for all_settings.
+ * Arguments:	Buffer:		Pointer to a buffer of size PAGE_SIZE.
+ * Returns:	Number of bytes used for saving our data.
+ */
+
+static int filewriter_save_config_info(char * buffer)
+{
+	strcpy(buffer, filewriter_target);
+	return strlen(filewriter_target) + 1;
+}
+
+/* filewriter_load_config_info
+ *
+ * Description:	Reload target's name.
+ * Arguments:	Buffer:		Pointer to the start of the data.
+ *		Size:		Number of bytes that were saved.
+ */
+
+static void filewriter_load_config_info(char * buffer, int size)
+{
+	strcpy(filewriter_target, buffer);
+}
+
+static void test_filewriter_target(void)
+{
+	set_filewriter_target(1);
+}
+
+extern void attempt_to_parse_resume_device(void);
+
+static struct suspend_proc_data filewriter_proc_data[] = {
+
+	{
+	 .filename			= "filewriter_target",
+	 .permissions			= PROC_RW,
+	 .type				= SUSPEND_PROC_DATA_STRING,
+	 .data = {
+		 .string = {
+			 .variable	= filewriter_target,
+			 .max_length	= 256,
+		 }
+	 },
+	 .write_proc			= test_filewriter_target,
+	},
+
+	{ .filename			= "disable_filewriter",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_INTEGER,
+	  .data = {
+		.integer = {
+			.variable	= &filewriterops.disabled,
+			.minimum	= 0,
+			.maximum	= 1,
+		}
+	  },
+	  .write_proc			= attempt_to_parse_resume_device,
+	}
+};
+
+static struct suspend_plugin_ops filewriterops = {
+	.type					= WRITER_PLUGIN,
+	.name					= "File Writer",
+	.module					= THIS_MODULE,
+	.memory_needed				= filewriter_memory_needed,
+	.print_debug_info			= filewriter_print_debug_stats,
+	.save_config_info			= filewriter_save_config_info,
+	.load_config_info			= filewriter_load_config_info,
+	.storage_needed				= filewriter_storage_needed,
+	.initialise				= filewriter_initialise,
+	.cleanup				= filewriter_cleanup,
+
+	.write_init				= filewriter_write_init,
+	.write_cleanup				= filewriter_write_cleanup,
+	.read_init				= filewriter_read_init,
+	.read_cleanup				= filewriter_read_cleanup,
+
+	.ops = {
+		.writer = {
+		 .write_chunk		= filewriter_write_chunk,
+		 .read_chunk		= filewriter_read_chunk,
+		 .noresume_reset	= filewriter_noresume_reset,
+		 .storage_available 	= filewriter_storage_available,
+		 .storage_allocated	= filewriter_storage_allocated,
+		 .release_storage	= filewriter_release_storage,
+		 .allocate_header_space	= filewriter_allocate_header_space,
+		 .allocate_storage	= filewriter_allocate_storage,
+		 .image_exists		= filewriter_image_exists,
+		 .mark_resume_attempted	= filewriter_mark_resume_attempted,
+		 .write_header_init	= filewriter_write_header_init,
+		 .write_header_chunk	= filewriter_write_header_chunk,
+		 .write_header_cleanup	= filewriter_write_header_cleanup,
+		 .read_header_init	= filewriter_read_header_init,
+		 .read_header_chunk	= filewriter_read_header_chunk,
+		 .read_header_cleanup	= filewriter_read_header_cleanup,
+		 .serialise_extents	= filewriter_serialise_extents,
+		 .load_extents		= filewriter_load_extents,
+		 .invalidate_image	= filewriter_invalidate_image,
+		 .parse_image_location	= filewriter_parse_image_location,
+		}
+	}
+};
+
+/* ---- Registration ---- */
+static __init int filewriter_load(void)
+{
+	int result;
+	int i, numfiles = sizeof(filewriter_proc_data) / sizeof(struct suspend_proc_data);
+	
+	printk("Software Suspend FileWriter loading.\n");
+
+	if (!(result = suspend_register_plugin(&filewriterops))) {
+		for (i=0; i< numfiles; i++)
+			suspend_register_procfile(&filewriter_proc_data[i]);
+	} else
+		printk("Software Suspend FileWriter unable to register!\n");
+	return result;
+}
+
+#ifdef MODULE
+static __exit void filewriter_unload(void)
+{
+	int i, numfiles = sizeof(filewriter_proc_data) / sizeof(struct suspend_proc_data);
+
+	printk("Software Suspend FileWriter unloading.\n");
+
+	for (i=0; i< numfiles; i++)
+		suspend_unregister_procfile(&filewriter_proc_data[i]);
+	suspend_unregister_plugin(&filewriterops);
+}
+
+module_init(filewriter_load);
+module_exit(filewriter_unload);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nigel Cunningham");
+MODULE_DESCRIPTION("Suspend2 filewriter");
+#else
+late_initcall(filewriter_load);
+#endif


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [45/48] Suspend2 2.1.9.8 for 2.6.12: 621-swsusp-tidy.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (46 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [43/48] Suspend2 2.1.9.8 for 2.6.12: 619-userspace-nofreeze.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  9:55   ` Pekka Enberg
  2005-07-06  6:40 ` [0/48] Suspend2 2.1.9.8 for 2.6.12 Pekka Enberg
                   ` (3 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 622-swapwriter.patch-old/kernel/power/suspend_swap.c 622-swapwriter.patch-new/kernel/power/suspend_swap.c
--- 622-swapwriter.patch-old/kernel/power/suspend_swap.c	1970-01-01 10:00:00.000000000 +1000
+++ 622-swapwriter.patch-new/kernel/power/suspend_swap.c	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,1713 @@
+/*
+ * Swapwriter.c
+ *
+ * Copyright 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * Distributed under GPLv2.
+ * 
+ * This file encapsulates functions for usage of swap space as a
+ * backing store.
+ */
+
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/swapops.h>
+
+#include "suspend2_core/suspend.h"
+#include "suspend2_core/suspend2_common.h"
+#include "suspend2_core/version.h"
+#include "suspend2_core/proc.h"
+#include "suspend2_core/plugins.h"
+#include "suspend2_core/io.h"
+#include "suspend2_core/ui.h"
+#include "suspend2_core/extent.h"
+#include "suspend2_core/utility.h"
+
+#include "block_io.h"
+
+static struct suspend_plugin_ops swapwriterops;
+
+#define SIGNATURE_VER 6
+#define BYTES_PER_HEADER_PAGE (PAGE_SIZE - sizeof(swp_entry_t))
+
+/* --- Struct of pages stored on disk */
+
+struct swaplink {
+	char dummy[BYTES_PER_HEADER_PAGE];
+	swp_entry_t next;
+};
+
+union diskpage {
+	union swap_header swh;	/* swh.magic is the only member used */
+	struct swaplink link;
+	struct suspend_header sh;
+};
+
+union p_diskpage {
+	union diskpage *pointer;
+	char *ptr;
+        unsigned long address;
+};
+
+// Higher Level
+static int readahead_index = 0, readahead_submit_index = 0;
+static int readahead_allocs = 0, readahead_frees = 0;
+
+static char * swapwriter_buffer = NULL;
+static int swapwriter_buffer_posn = 0;
+static unsigned long * header_link = NULL;
+
+/*
+ * ---------------------------------------------------------------
+ *
+ *     Internal Data Structures
+ *
+ * ---------------------------------------------------------------
+ */
+
+/* header_data contains data that is needed to reload pagedir1, and
+ * is therefore saved in the suspend header.
+ *
+ * Pagedir2 swap comes before pagedir1 swap (save order), and the first swap
+ * entry for pagedir1 to use is set when pagedir2 is written (when we know how
+ * much swap it used). Since this first entry is almost certainly not at the
+ * start of a extent, the firstoffset variable below tells us where to start in
+ * the extent. All of this means we don't have to worry about getting different
+ * compression ratios for the kernel and cache (when compressing the image).
+ * We can simply allocate one pool of swap (size determined using expected
+ * compression ratio) and use it without worrying whether one pageset
+ * compresses better and the other worse (this is what happens). As long as the
+ * user gets the expected compression right, it will work.
+ */
+
+struct {
+	/* Extent chains for swap & blocks */
+	struct extentchain swapextents;
+	struct extentchain block_chain[MAX_SWAPFILES];
+	
+	/* Location of start of pagedir 1 */
+	struct extent * pd1start_block_extent;
+	int pd1start_chain;
+	int pd1start_extent_number;
+	unsigned long pd1start_block_offset;
+
+	/* Devices used for swap */
+	dev_t swapdevs[MAX_SWAPFILES];
+	char blocksizes[MAX_SWAPFILES];
+
+} header_data;
+
+static dev_t header_device = 0;
+static struct block_device * header_block_device = NULL;
+static int headerblocksize = PAGE_SIZE;
+static int headerblock;
+
+/* For swapfile automatically swapon/off'd. */
+static char swapfilename[256] = "";
+extern asmlinkage long sys_swapon(const char * specialfile, int swap_flags);
+extern asmlinkage long sys_swapoff(const char * specialfile);
+static int suspend_swapon_status = 0;
+
+/*
+ * ---------------------------------------------------------------
+ *
+ *     Current state.
+ *
+ * ---------------------------------------------------------------
+ */
+
+/* Which pagedir are we saving/reloading? Needed so we can know whether to
+ * remember the last swap entry used at the end of writing pageset2, and
+ * get that location when saving or reloading pageset1.*/
+static int current_stream = 0;
+
+/* Pointer to current swap entry being loaded/saved. */
+static struct extent * currentblockextent = NULL;
+static unsigned long currentblockoffset = 0;
+static int currentblockchain = 0;
+static int currentblocksperpage = 0;
+
+/* Header Page Information */
+static int header_pages_allocated = 0;
+static struct submit_params * first_header_submit_info = NULL,
+ * last_header_submit_info = NULL, * current_header_submit_info = NULL;
+
+/*
+ * ---------------------------------------------------------------
+ *
+ *     User Specified Parameters
+ *
+ * ---------------------------------------------------------------
+ */
+
+static int resume_firstblock = 0;
+static int resume_firstblocksize = PAGE_SIZE;
+static dev_t resume_device = 0;
+static struct block_device * resume_block_device = NULL;
+
+struct sysinfo swapinfo;
+static int swapwriter_invalidate_image(void);
+
+static void cleanup_opened_devices(int including_swapdevices)
+{
+	int i;
+
+	/* Cleanup our open_by_devnums.
+	 *
+	 * Other swap devices, opened when reading pageset1, are
+	 * either cleaned up by noresume_reset
+	 */
+
+	if (header_block_device && header_block_device != resume_block_device)
+		blkdev_put(header_block_device);
+
+	if (resume_block_device)
+		blkdev_put(resume_block_device);
+
+	/* When reading pageset1 header */
+	if (including_swapdevices) {
+		for (i = 0; i < MAX_SWAPFILES; i++) {
+			struct block_device * this_dev = swap_info[i].bdev;
+			if (this_dev && this_dev != resume_block_device &&
+					this_dev != header_block_device) {
+				blkdev_put(swap_info[i].bdev);
+				swap_info[i].bdev = NULL;
+			}
+		}
+	}
+	
+	header_block_device = resume_block_device = NULL;
+}
+/* Must be silent - might be called from cat /proc/suspend/debug_info
+ * Returns 0 if was off, -EBUSY if was on, error value otherwise.
+ */
+static int enable_swapfile(void)
+{
+	int activateswapresult = -EINVAL;
+
+	if (suspend_swapon_status)
+		return 0;
+
+	if (swapfilename[0]) {
+		/* Attempt to swap on with maximum priority */
+		activateswapresult = sys_swapon(swapfilename, 0xFFFF);
+		if ((activateswapresult) && (activateswapresult != -EBUSY))
+			printk(name_suspend
+				"The swapfile/partition specified by "
+				"/proc/suspend/swapfile (%s) could not"
+				" be turned on (error %d). Attempting "
+				"to continue.\n",
+				swapfilename, activateswapresult);
+		if (!activateswapresult)
+			suspend_swapon_status = 1;
+	}
+	return activateswapresult;
+}
+
+/* Returns 0 if was on, -EINVAL if was off, error value otherwise */
+static int disable_swapfile(void)
+{
+	int result = -EINVAL;
+	
+	if (!suspend_swapon_status)
+		return 0;
+
+	if (swapfilename[0]) {
+		result = sys_swapoff(swapfilename);
+		if (result == -EINVAL)
+	 		return 0;	/* Wasn't on */
+		if (!result)
+			suspend_swapon_status = 0;
+	}
+
+	return result;
+}
+
+static int manage_swapfile(int enable)
+{
+	static int result;
+
+	if (enable)
+		result = enable_swapfile();
+	else
+		result = disable_swapfile();
+
+	return result;
+}
+
+static void get_header_params(struct submit_params * headerpage)
+{
+	swp_entry_t entry = headerpage->swap_address;
+	int swapfilenum = swp_type(entry);
+	unsigned long offset = swp_offset(entry);
+	struct swap_info_struct * sis = get_swap_info_struct(swapfilenum);
+	sector_t sector = map_swap_page(sis, offset);
+
+	headerpage->dev = sis->bdev,
+	headerpage->block[0] = sector;
+	//headerpage->blocks_used = 1;
+	headerpage->readahead_index = -1;
+}
+
+static inline int get_blocks_per_page(int chain)
+{
+	int result = PAGE_SIZE /
+		suspend_bio_ops.get_block_size(swap_info[chain].bdev);
+	return result;
+}
+
+static int try_to_parse_header_device(void)
+{
+	header_block_device = open_by_devnum(header_device, FMODE_READ);
+
+	if (IS_ERR(header_block_device) || (!header_block_device)) {
+		if (suspend_early_boot_message(1,SUSPEND_CONTINUE_REQ,  
+				"Failed to get access to the "
+				"resume header device.\nYou could be "
+				"booting with a 2.6 kernel when you "
+				"suspended a 2.4 kernel."))
+			swapwriter_invalidate_image();
+		return -EINVAL;
+	}
+
+	if (set_blocksize(header_block_device, PAGE_SIZE) < 0) {
+		if (suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+			"Failed to set the blocksize for a swap device."))
+				do { } while(0);
+		swapwriter_invalidate_image();
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int try_to_open_resume_device(void)
+{
+	resume_block_device = open_by_devnum(resume_device, FMODE_READ);
+
+	if (IS_ERR(resume_block_device) || (!resume_block_device))
+		return 1;
+
+	return 0;
+}
+
+static int try_to_parse_resume_device(char * commandline)
+{
+	struct kstat stat;
+	int error;
+
+	resume_device = name_to_dev_t(commandline);
+
+	if (!resume_device) {
+		error = vfs_stat(commandline, &stat);
+		if (!error)
+			resume_device = stat.rdev;
+	}
+
+	if (!resume_device) {
+		if (test_suspend_state(SUSPEND_TRYING_TO_RESUME))
+			suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+				"Failed to translate \"%s\" into a device id.\n",
+				commandline);
+		else
+			printk(name_suspend "Can't translate \"%s\" into a device id yet.\n",
+					commandline);
+		return 1;
+	}
+
+	if (try_to_open_resume_device()) {
+		suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+			"Failed to get access to \"%s\", where"
+			" the swap header should be found.",
+			commandline);
+		return 1;
+	}
+
+	return 0;
+}
+
+static void open_other_swap_device(int i, dev_t thisdevice)
+{
+	if ((swap_info[i].bdev = open_by_devnum(thisdevice, FMODE_READ)))
+		set_blocksize(swap_info[i].bdev, PAGE_SIZE);
+}
+
+static inline char * get_path_for_swapfile(int which, char * path_page)
+{
+	return d_path(	swap_info[which].swap_file->f_dentry,
+			swap_info[which].swap_file->f_vfsmnt,
+			path_page,
+			PAGE_SIZE);
+}
+
+/* 
+ * If we have read part of the image, we might have filled header_data with
+ * data that should be zeroed out.
+ */
+static void swapwriter_noresume_reset(void)
+{
+	memset((char *) &header_data, 0, sizeof(header_data));
+	cleanup_opened_devices(1);
+}
+
+static int parse_signature(char * header, int restore)
+{
+	int type = -1;
+	
+	if (!memcmp("SWAP-SPACE",header,10))
+		return 0;
+	else if (!memcmp("SWAPSPACE2",header,10))
+		return 1;
+
+	else if (!memcmp("pmdisk", header,6))
+		type = 2;
+	
+	else if (!memcmp("S1SUSP",header,6))
+		type = 4;
+	else if (!memcmp("S2SUSP",header,6))
+		type = 5;
+	
+	else if (!memcmp("z",header,1))
+		type = 12;
+	else if (!memcmp("Z",header,1))
+		type = 13;
+	
+	/* 
+	 * Put bdev of suspend header in last byte of swap header
+	 * (unsigned short)
+	 */
+	if (type > 11) {
+		dev_t * header_ptr = (dev_t *) &header[1];
+		unsigned char * headerblocksize_ptr =
+			(unsigned char *) &header[5];
+		unsigned long * headerblock_ptr = (unsigned long *) &header[6];
+		header_device = *header_ptr;
+		/* 
+		 * We are now using the highest bit of the char to indicate
+		 * whether we have attempted to resume from this image before.
+		 */
+		clear_suspend_state(SUSPEND_RESUMED_BEFORE);
+		if (((int) *headerblocksize_ptr) & 0x80)
+			set_suspend_state(SUSPEND_RESUMED_BEFORE);
+		headerblocksize = 512 * (((int) *headerblocksize_ptr) & 0xf);
+		headerblock = *headerblock_ptr;
+	}
+
+	if ((restore) && (type > 5)) {
+		/* We only reset our own signatures */
+		if (type & 1)
+			memcpy(header,"SWAPSPACE2",10);
+		else
+			memcpy(header,"SWAP-SPACE",10);
+	}
+
+	return type;
+}
+
+/*
+ * prepare_signature
+ */
+
+static int prepare_signature(struct submit_params * header_page_info,
+		char * current_header)
+{
+	int current_type = parse_signature(current_header, 0);
+	dev_t * header_ptr = (dev_t *) (&current_header[1]);
+	unsigned char * headerblocksize_ptr =
+		(unsigned char *) (&current_header[5]);
+	unsigned long * headerblock_ptr =
+		(unsigned long *) (&current_header[6]);
+
+	if ((current_type > 1) && (current_type < 6))
+		return 1;
+
+	if (current_type & 1)
+		current_header[0] = 'Z';
+	else
+		current_header[0] = 'z';
+	*header_ptr = header_page_info->dev->bd_dev;
+	*headerblocksize_ptr =
+		(unsigned char) (header_page_info->dev->bd_block_size >> 9);
+	/* prev is the first/last swap page of the resume area */
+	*headerblock_ptr = (unsigned long) header_page_info->block[0]; 
+	return 0;
+}
+
+extern int signature_check(char * header, int fix);
+
+static int free_swap_pages_for_header(void)
+{
+	if (!first_header_submit_info)
+		return 1;
+
+	while (first_header_submit_info) {
+		struct submit_params * next = first_header_submit_info->next;
+		if (first_header_submit_info->swap_address.val)
+			swap_free(first_header_submit_info->swap_address);
+		kfree(first_header_submit_info);
+		first_header_submit_info = next;
+	}
+	
+	first_header_submit_info = last_header_submit_info = NULL;
+	header_pages_allocated = 0;
+	return 0;
+}
+
+static void get_main_pool_phys_params(void)
+{
+	struct extent * extentpointer = NULL;
+	unsigned long address;
+	int i;
+	int extent_min = -1, extent_max = -1;
+	int last_chain = -1;
+
+	for (i = 0; i < MAX_SWAPFILES; i++)
+		if (header_data.block_chain[i].first)
+			put_extent_chain(&header_data.block_chain[i]);
+
+	extent_for_each(&header_data.swapextents, extentpointer, address) {
+		swp_entry_t swap_address = extent_val_to_swap_entry(address);
+		int swapfilenum = swp_type(swap_address);
+		unsigned long offset = swp_offset(swap_address);
+		struct swap_info_struct * sis = get_swap_info_struct(swapfilenum);
+		sector_t new_sector = map_swap_page(sis, offset);
+
+		if ((new_sector == extent_max + 1) &&
+		    (last_chain == swapfilenum))
+			extent_max++;
+		else {
+			if (extent_min > 0)
+				append_extent_to_extent_chain(
+					&header_data.block_chain[last_chain],
+					extent_min, extent_max);
+			extent_min = extent_max = new_sector;
+			last_chain = swapfilenum;
+		}
+	}
+	if (extent_min > -1)
+		append_extent_to_extent_chain(
+			&header_data.block_chain[last_chain],
+			extent_min, extent_max);
+}
+
+static int swapwriter_storage_allocated(void)
+{
+	int result;
+	result = header_data.swapextents.size + header_pages_allocated;
+	return result;
+}
+
+static int swapwriter_storage_available(void)
+{
+	int result;
+	si_swapinfo(&swapinfo);
+	result = swapinfo.freeswap + swapwriter_storage_allocated();
+	return result;
+}
+
+static int swapwriter_initialise(int starting_cycle)
+{
+	if (starting_cycle)
+		manage_swapfile(1);
+
+	if (!resume_block_device && try_to_open_resume_device())
+		return 1;
+	
+	return 0;
+}
+
+static void swapwriter_cleanup(int ending_cycle)
+{
+	if (ending_cycle)
+		manage_swapfile(0);
+	
+	cleanup_opened_devices(0);
+}
+
+static int swapwriter_release_storage(void)
+{
+	int i = 0;
+
+	if ((TEST_ACTION_STATE(SUSPEND_KEEP_IMAGE)) && test_suspend_state(SUSPEND_NOW_RESUMING))
+		return 0;
+
+	free_swap_pages_for_header();
+	
+	if (header_data.swapextents.first) {
+		/* Free swap entries */
+		struct extent * extentpointer;
+		unsigned long extentvalue;
+		swp_entry_t entry;
+		extent_for_each(&header_data.swapextents, extentpointer, 
+				extentvalue) {
+			entry = extent_val_to_swap_entry(extentvalue);
+			swap_free(entry);
+		}
+		put_extent_chain(&header_data.swapextents);
+		
+		for (i = 0; i < MAX_SWAPFILES; i++)
+			if (header_data.block_chain[i].first)
+				put_extent_chain(&header_data.block_chain[i]);
+	}
+	
+	return 0;
+}
+
+static int swapwriter_allocate_header_space(int space_really_requested)
+{
+	/* space_requested was going to be in bytes... not yet */
+	int i;
+	int ret = 0;
+	long space_requested;
+
+	/* 
+	 * Up to here in the process, we haven't taken account of the fact
+	 * that we need an extra four bytes per 4092 bytes written for link
+	 * to the next page on which the header will be written. We factor
+	 * that in here.
+	 */
+	space_requested = ((long) space_really_requested) << PAGE_SHIFT;
+	space_requested = ((space_really_requested + 4091) / 4092);
+	space_requested = (space_requested * 4 + 4091) / 4092;
+	space_requested += space_really_requested;
+	
+	for (i=(header_pages_allocated+1); i<=space_requested; i++) {
+		struct submit_params * new_submit_param;
+		
+		/* Get a submit structure */
+		new_submit_param = kmalloc(sizeof(struct submit_params), GFP_ATOMIC);
+		
+		if (!new_submit_param) {
+			header_pages_allocated = i - 1;
+			printk("Failed to kmalloc a struct submit param.\n");
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		memset(new_submit_param, 0, sizeof(struct submit_params));
+
+		if (last_header_submit_info) {
+			last_header_submit_info->next = new_submit_param;
+			last_header_submit_info = new_submit_param;
+		} else
+			last_header_submit_info = first_header_submit_info =
+				new_submit_param;
+
+		/* Get swap entry */
+		new_submit_param->swap_address = get_swap_page();
+		
+		if ((!new_submit_param->swap_address.val) &&
+			       (header_data.swapextents.first)) {
+			/*
+			 *  Steal one from pageset swap chain. If, as a result,
+			 *  it is too small, more swap will be allocated or
+			 *  memory eaten.
+			 */
+
+			new_submit_param->swap_address =
+				extent_val_to_swap_entry(
+					header_data.swapextents.first->minimum);
+			if (header_data.swapextents.first->minimum <
+					header_data.swapextents.first->maximum)
+				header_data.swapextents.first->minimum++;
+			else {
+				struct extent * oldfirst =
+					header_data.swapextents.first;
+				header_data.swapextents.first = oldfirst->next;
+				header_data.swapextents.frees++;
+				if (header_data.swapextents.last == oldfirst)
+					header_data.swapextents.last = NULL;
+				put_extent(oldfirst);
+			}
+			
+			header_data.swapextents.size--;
+
+			/*
+			 * Recalculate block chains for main pool.
+			 * We don't assume blocks are at start of a chain and
+			 * don't know how many blocks per swap entry.
+			 */
+			get_main_pool_phys_params();
+		}
+		if (!new_submit_param->swap_address.val) {
+			free_swap_pages_for_header();
+			printk("Unable to allocate swap page for header.\n");
+			ret = -ENOMEM;
+			goto out;
+		}
+		
+		get_header_params(new_submit_param);
+	}
+	header_pages_allocated = space_requested;
+out:
+	return ret;
+}
+
+static int swapwriter_allocate_storage(int space_requested)
+{
+	int i, result = 0;
+	int pages_to_get = space_requested - header_data.swapextents.size;
+	int extent_min = -1, extent_max = -1;
+	
+	if (pages_to_get < 1)
+		return 0;
+
+	for(i=0; i < pages_to_get; i++) {
+		swp_entry_t entry;
+		int new_value;
+
+		entry = get_swap_page();
+		if (!entry.val) {
+			result = -ENOSPC;
+			goto out;
+		}
+		
+		new_value = swap_entry_to_extent_val(entry);
+		if (new_value == extent_max + 1)
+			extent_max++;
+		else {
+			if (extent_min > -1)
+				append_extent_to_extent_chain(
+					&header_data.swapextents,
+					extent_min, extent_max);
+			extent_min = extent_max = new_value;
+		}
+	}
+
+	if (extent_min > -1)
+		append_extent_to_extent_chain(
+			&header_data.swapextents,
+		       extent_min, extent_max);
+
+out:
+	get_main_pool_phys_params();
+	return result;
+}
+
+static int swapwriter_write_header_chunk(char * buffer, int buffer_size)
+{
+	int bytes_left = buffer_size;
+	
+	/* 
+	 * We buffer the writes until a page is full and to use the last
+	 * sizeof(swp_entry_t) bytes for links between pages. This is 
+	 * totally transparent to the caller.
+	 *
+	 * Note also that buffer_size can be > PAGE_SIZE.
+	 */
+
+	while (bytes_left) {
+		char * source_start = buffer + buffer_size - bytes_left;
+		char * dest_start = swapwriter_buffer + swapwriter_buffer_posn;
+		int dest_capacity = BYTES_PER_HEADER_PAGE - swapwriter_buffer_posn;
+		swp_entry_t next_header_page;
+		if (bytes_left <= dest_capacity) {
+			memcpy(dest_start, source_start, bytes_left);
+			swapwriter_buffer_posn += bytes_left;
+			return 0;
+		}
+	
+		/* A page is full */
+		memcpy(dest_start, source_start, dest_capacity);
+		bytes_left -= dest_capacity;
+
+		BUG_ON(!current_header_submit_info);
+
+		if (!current_header_submit_info->next)
+			*header_link = 0;
+		else {
+			next_header_page =
+				swp_entry(swp_type(
+				current_header_submit_info->next->swap_address),
+				current_header_submit_info->next->block[0]);
+
+			*header_link = next_header_page.val;
+		}
+
+		current_header_submit_info->page =
+			virt_to_page(swapwriter_buffer);
+		check_shift_keys(0, NULL);
+		suspend_bio_ops.submit_io(WRITE, current_header_submit_info, 0);
+
+		swapwriter_buffer_posn = 0;
+		current_header_submit_info = current_header_submit_info->next;
+	}
+
+	return 0;
+}
+
+static int swapwriter_write_header_init(void)
+{
+	int i;
+	struct extent * extent;
+
+	for (i = 0; i < MAX_SWAPFILES; i++)
+		if (swap_info[i].swap_file) {
+			header_data.swapdevs[i] = swap_info[i].bdev->bd_dev;
+			header_data.blocksizes[i] =
+				block_size(swap_info[i].bdev);
+		}
+
+	swapwriter_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	header_link =
+		(unsigned long *) (swapwriter_buffer + BYTES_PER_HEADER_PAGE);
+
+	current_header_submit_info = first_header_submit_info;
+	
+	header_data.pd1start_extent_number = 1;
+	extent = header_data.block_chain[header_data.pd1start_chain].first;
+
+	while (extent != header_data.pd1start_block_extent) {
+		header_data.pd1start_extent_number++;
+		extent = extent->next;
+	}
+
+	/* Info needed to bootstrap goes at the start of the header.
+	 * First we save the 'header_data' struct, including the number
+	 * of header pages. Then we save the structs containing data needed
+	 * for reading the header pages back.
+	 * Note that even if header pages take more than one page, when we
+	 * read back the info, we will have restored the location of the
+	 * next header page by the time we go to use it.
+	 */
+	return swapwriter_write_header_chunk((char *) &header_data, 
+			sizeof(header_data));
+}
+
+static int swapwriter_write_header_cleanup(void)
+{
+	/* Write any unsaved data */
+	if (swapwriter_buffer_posn) {
+		*header_link = 0;
+
+		current_header_submit_info->page =
+			virt_to_page(swapwriter_buffer);
+		suspend_bio_ops.submit_io(WRITE, 
+				current_header_submit_info, 0);
+	}
+
+	/* Adjust swap header */
+	suspend_bio_ops.bdev_page_io(READ, resume_block_device, resume_firstblock,
+			virt_to_page(swapwriter_buffer));
+
+	prepare_signature(first_header_submit_info,
+		((union swap_header *) swapwriter_buffer)->magic.magic);
+		
+	suspend_bio_ops.bdev_page_io(WRITE, resume_block_device, resume_firstblock,
+			virt_to_page(swapwriter_buffer));
+
+	free_pages((unsigned long) swapwriter_buffer, 0);
+	swapwriter_buffer = NULL;
+	header_link = NULL;
+	
+	suspend_bio_ops.finish_all_io();
+
+	return 0;
+}
+
+/* ------------------------- HEADER READING ------------------------- */
+
+/*
+ * read_header_init()
+ * 
+ * Description:
+ * 1. Attempt to read the device specified with resume2=.
+ * 2. Check the contents of the swap header for our signature.
+ * 3. Warn, ignore, reset and/or continue as appropriate.
+ * 4. If continuing, read the swapwriter configuration section
+ *    of the header and set up block device info so we can read
+ *    the rest of the header & image.
+ *
+ * Returns:
+ * May not return if user choose to reboot at a warning.
+ * -EINVAL if cannot resume at this time. Booting should continue
+ * normally.
+ */
+
+static int swapwriter_read_header_init(void)
+{
+	int i;
+	
+	BUG_ON(!resume_block_device);
+
+	swapwriter_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+
+	if (!header_device) {
+		printk("read_header_init called when we haven't "
+				"verified there is an image!\n");
+		return -EINVAL;
+	}
+
+	/* 
+	 * If the header is not on the resume_device, get the resume device first.
+	 */
+	if (header_device != resume_device) {
+		int result = try_to_parse_header_device();
+
+		if (result)
+			return result;
+	} else
+		header_block_device = resume_block_device;
+
+	/* Read swapwriter configuration */
+	suspend_bio_ops.bdev_page_io(READ, header_block_device, headerblock,
+			virt_to_page((unsigned long) swapwriter_buffer));
+	
+	memcpy(&header_data, swapwriter_buffer, sizeof(header_data));
+	
+	/* Restore device info */
+	for (i = 0; i < MAX_SWAPFILES; i++) {
+		dev_t thisdevice = header_data.swapdevs[i];
+		
+		swap_info[i].bdev = NULL;
+
+		if (!thisdevice)
+			continue;
+
+		if (thisdevice == resume_device) {
+			swap_info[i].bdev = resume_block_device;
+			/* Mark as used so the device doesn't get suspended. */
+			swap_info[i].swap_file = (struct file *) 0xffffff;
+			continue;
+		}
+
+		if (thisdevice == header_device) {
+			swap_info[i].bdev = header_block_device;
+			/* Mark as used so the device doesn't get suspended. */
+			swap_info[i].swap_file = (struct file *) 0xffffff;
+			continue;
+		}
+
+		open_other_swap_device(i, thisdevice);
+		swap_info[i].swap_file = (struct file *) 0xffffff;
+	}
+
+	swapwriter_buffer_posn = sizeof(header_data);
+
+	return 0;
+}
+
+static int swapwriter_read_header_chunk(char * buffer, int buffer_size)
+{
+	int bytes_left = buffer_size, ret = 0;
+	
+	check_shift_keys(0, "");
+
+	/* Read a chunk of the header */
+	while ((bytes_left) && (!ret)) {
+		swp_entry_t next =
+		   ((union p_diskpage) swapwriter_buffer).pointer->link.next;
+		struct block_device * dev = swap_info[swp_type(next)].bdev;
+		int pos = swp_offset(next);
+		char * dest_start = buffer + buffer_size - bytes_left;
+		char * source_start =
+			swapwriter_buffer + swapwriter_buffer_posn;
+		int source_capacity =
+			BYTES_PER_HEADER_PAGE - swapwriter_buffer_posn;
+
+		if (bytes_left <= source_capacity) {
+			memcpy(dest_start, source_start, bytes_left);
+			swapwriter_buffer_posn += bytes_left;
+			return buffer_size;
+		}
+
+		/* Next to read the next page */
+		memcpy(dest_start, source_start, source_capacity);
+		bytes_left -= source_capacity;
+
+		suspend_bio_ops.bdev_page_io(READ, dev, pos, virt_to_page(swapwriter_buffer));
+
+		swapwriter_buffer_posn = 0;
+	}
+
+	return buffer_size - bytes_left;
+}
+
+static int swapwriter_read_header_cleanup(void)
+{
+	free_pages((unsigned long) swapwriter_buffer, 0);
+	return 0;
+}
+
+static int swapwriter_serialise_extents(void)
+{
+	int i;
+
+	serialise_extent_chain(&header_data.swapextents);
+	
+	for (i = 0; i < MAX_SWAPFILES; i++)
+		serialise_extent_chain(&header_data.block_chain[i]);
+	
+	return 0;
+}
+
+static int swapwriter_load_extents(void)
+{
+	int i;
+	struct extent * extent;
+	
+	load_extent_chain(&header_data.swapextents);
+
+	for (i = 0; i < MAX_SWAPFILES; i++)
+		load_extent_chain(&header_data.block_chain[i]);
+
+	extent = header_data.block_chain[header_data.pd1start_chain].first;
+
+	i = 1;
+	while (i < header_data.pd1start_extent_number) {
+		extent = extent->next;
+		i++;
+	}
+
+	header_data.pd1start_block_extent = extent;
+
+	return 0;
+}
+
+static int swapwriter_write_init(int stream_number)
+{
+	current_stream = stream_number;
+
+	if (current_stream == 1) {
+		currentblockextent = header_data.pd1start_block_extent;
+		currentblockoffset = header_data.pd1start_block_offset;
+		currentblockchain = header_data.pd1start_chain;
+	} else
+		for (currentblockchain = 0; currentblockchain < MAX_SWAPFILES;
+				currentblockchain++)
+			if (header_data.block_chain[currentblockchain].first) {
+				currentblockextent =
+					header_data.
+					 block_chain[currentblockchain].first;
+				currentblockoffset = currentblockextent->minimum;
+				break;
+			}
+
+	BUG_ON(!currentblockextent);
+
+	currentblocksperpage = get_blocks_per_page(currentblockchain);
+
+	suspend_bio_ops.reset_io_stats();
+
+	return 0;
+}
+
+static int swapwriter_write_chunk(struct page * buffer_page)
+{
+	int i;
+	struct submit_params submit_params;
+
+	if (TEST_ACTION_STATE(SUSPEND_TEST_FILTER_SPEED))
+		return 0;
+		
+	if (currentblockchain == MAX_SWAPFILES) {
+		printk("Error! We have run out of blocks for writing data.\n");
+		return -ENOSPC;
+	}
+	
+	if (!currentblockextent) {
+		do {
+			currentblockchain++;
+		} while ((currentblockchain < MAX_SWAPFILES) &&
+		   (!header_data.block_chain[currentblockchain].first));
+
+		/* We can validly not have a new blockextent. We
+		 * might be compressing data and the user was
+		 * too optimistic in setting the compression
+		 * ratio or we're just copying the pageset. */
+
+		if (currentblockchain == MAX_SWAPFILES) {
+			printk("Argh. Ran out of block chains.\n");
+			return -ENOSPC;
+		}
+				
+		currentblockextent = 
+		 header_data.block_chain[currentblockchain].first;
+		currentblockoffset = currentblockextent->minimum;
+		currentblocksperpage = get_blocks_per_page(currentblockchain);
+	}
+
+	submit_params.readahead_index = -1;
+	submit_params.page = buffer_page;
+	submit_params.dev = swap_info[currentblockchain].bdev;
+		
+	/* Get the blocks */
+	submit_params.block[0] = currentblockoffset;
+	for (i = 0; i < currentblocksperpage; i++)
+		GET_EXTENT_NEXT(currentblockextent, currentblockoffset);
+
+	suspend_bio_ops.submit_io(WRITE, &submit_params, 0);
+
+	check_shift_keys(0, NULL);
+
+	return 0;
+}
+
+static int swapwriter_write_cleanup(void)
+{
+	if (current_stream == 2) {
+		header_data.pd1start_block_extent = currentblockextent;
+		header_data.pd1start_block_offset = currentblockoffset;
+		header_data.pd1start_chain = currentblockchain;
+	}
+	
+	suspend_bio_ops.finish_all_io();
+	
+	suspend_bio_ops.check_io_stats();
+
+	return 0;
+}
+
+static int swapwriter_read_init(int stream_number)
+{
+	current_stream = stream_number;
+
+	if (current_stream == 1) {
+		currentblockextent = header_data.pd1start_block_extent;
+		currentblockoffset = header_data.pd1start_block_offset;
+		currentblockchain = header_data.pd1start_chain;
+	} else {
+		currentblockextent = NULL;
+		currentblockoffset = 0;
+		currentblockchain = 0;
+		for (currentblockchain = 0; currentblockchain < MAX_SWAPFILES;
+			       currentblockchain++)
+			if (header_data.block_chain[currentblockchain].first) {
+				currentblockextent =
+					header_data.block_chain[currentblockchain].first;
+				currentblockoffset = currentblockextent->minimum;
+				break;
+			}
+
+		BUG_ON(!currentblockextent);
+	}
+	
+	currentblocksperpage = get_blocks_per_page(currentblockchain);
+
+	suspend_bio_ops.reset_io_stats();
+
+	readahead_index = readahead_submit_index = -1;
+	readahead_allocs = readahead_frees = 0;
+
+	return 0;
+}
+
+static int swapwriter_begin_read_chunk(struct page * page, 
+		int readahead_index, int sync)
+{
+	int i;
+	struct submit_params submit_params;
+
+	if (currentblockchain == MAX_SWAPFILES) {
+		/* Readahead might ask us to read too many blocks */
+		printk("Currentblockchain == MAX_SWAPFILES. Begin_read_chunk returning -ENODATA.\n");
+		return -ENODATA;
+	}
+
+	if (!currentblockextent) {
+		do {
+			currentblockchain++;
+		} while ((currentblockchain < MAX_SWAPFILES) &&
+			 (!header_data.block_chain[currentblockchain].first));
+
+		/* We can validly not have a new blockextent. We
+		 * might have allocated exactly the right amount
+		 * of swap for the image and be reading the last
+		 * block now.
+		 */
+
+		/* Readahead might ask us to read too many blocks */
+		if (currentblockchain == MAX_SWAPFILES)
+			return -ENODATA;
+
+		currentblockextent =
+		  header_data.block_chain[currentblockchain].first;
+		currentblockoffset = currentblockextent->minimum;
+		currentblocksperpage = get_blocks_per_page(currentblockchain);
+	}
+	
+	submit_params.readahead_index = readahead_index;
+	submit_params.page = page;
+	submit_params.dev = swap_info[currentblockchain].bdev;
+		
+	/* Get the blocks. There is no chance that they span chains. */
+	submit_params.block[0] = currentblockoffset;
+	for (i = 0; i < currentblocksperpage; i++)
+		GET_EXTENT_NEXT(currentblockextent, currentblockoffset);
+
+	if ((i = suspend_bio_ops.submit_io(READ, &submit_params, sync)))
+		return -EPERM;
+
+	check_shift_keys(0, NULL);
+
+	return 0;
+}
+
+/* Note that we ignore the sync parameter. We are implementing
+ * read ahead, and will always wait until our readhead buffer has
+ * been read before returning.
+ */
+
+static int swapwriter_read_chunk(struct page * buffer_page, int sync)
+{
+	static int last_result;
+	unsigned long * virt;
+
+	/* If we only use readahead when reading synchronously. */
+	if (sync == SUSPEND_ASYNC)
+		return swapwriter_begin_read_chunk(buffer_page, -1, sync);
+
+	/* Start new readahead while we wait for our page */
+	if (readahead_index == -1) {
+		last_result = 0;
+		readahead_index = readahead_submit_index = 0;
+	}
+
+	/* Start a new readahead? */
+	if (last_result) {
+		/* We failed to submit a read, and have cleaned up
+		 * all the readahead previously submitted */
+		if (readahead_submit_index == readahead_index)
+			return -EIO;
+		goto wait;
+	}
+	
+	do {
+		if (suspend_bio_ops.prepare_readahead(readahead_submit_index))
+			break;
+
+		readahead_allocs++;
+
+		last_result = swapwriter_begin_read_chunk(
+			suspend_bio_ops.readahead_pages[readahead_submit_index], 
+			readahead_submit_index, SUSPEND_ASYNC);
+		if (last_result) {
+			suspend_bio_ops.cleanup_readahead(readahead_submit_index);
+			readahead_frees++;
+			break;
+		}
+
+		readahead_submit_index++;
+
+		if (readahead_submit_index == MAX_READAHEAD)
+			readahead_submit_index = 0;
+
+	} while((!last_result) && (readahead_submit_index != readahead_index) &&
+			(!suspend_bio_ops.readahead_ready(readahead_index)));
+
+wait:
+	suspend_bio_ops.wait_on_readahead(readahead_index);
+
+	virt = kmap_atomic(buffer_page, KM_USER1);
+
+	memcpy(virt, page_address(suspend_bio_ops.readahead_pages[readahead_index]),
+			PAGE_SIZE);
+	kunmap_atomic(virt, KM_USER1);
+
+	suspend_bio_ops.cleanup_readahead(readahead_index);
+
+	readahead_frees++;
+
+	readahead_index++;
+	if (readahead_index == MAX_READAHEAD)
+		readahead_index = 0;
+
+	return 0;
+}
+
+static int swapwriter_read_cleanup(void)
+{
+	suspend_bio_ops.finish_all_io();
+	while (readahead_index != readahead_submit_index) {
+		suspend_bio_ops.cleanup_readahead(readahead_index);
+		readahead_frees++;
+		readahead_index++;
+		if (readahead_index == MAX_READAHEAD)
+			readahead_index = 0;
+	}
+	suspend_bio_ops.check_io_stats();
+	BUG_ON(readahead_allocs != readahead_frees);
+
+	return 0;
+}
+
+/* swapwriter_invalidate_image
+ * 
+ */
+static int swapwriter_invalidate_image(void)
+{
+	union p_diskpage cur;
+	int result = 0;
+	char newsig[11];
+	
+	cur.address = get_zeroed_page(GFP_ATOMIC);
+	if (!cur.address) {
+		printk("Unable to allocate a page for restoring the swap signature.\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * If nr_suspends == 0, we must be booting, so no swap pages
+	 * will be recorded as used yet.
+	 */
+
+	if (nr_suspends > 0)
+		swapwriter_release_storage();
+
+	/* 
+	 * We don't do a sanity check here: we want to restore the swap 
+	 * whatever version of kernel made the suspend image.
+	 * 
+	 * We need to write swap, but swap may not be enabled so
+	 * we write the device directly
+	 */
+	
+	suspend_bio_ops.bdev_page_io(READ, resume_block_device,
+			resume_firstblock, virt_to_page(cur.pointer));
+
+	result = parse_signature(cur.pointer->swh.magic.magic, 1);
+		
+	if (result < 4)
+		goto out;
+
+	strncpy(newsig, cur.pointer->swh.magic.magic, 10);
+	newsig[10] = 0;
+
+	suspend_bio_ops.bdev_page_io(WRITE, resume_block_device, resume_firstblock,
+			virt_to_page(cur.pointer));
+
+	if (!nr_suspends)
+		printk(KERN_WARNING name_suspend "Image invalidated.\n");
+out:
+	suspend_bio_ops.finish_all_io();
+	free_pages(cur.address, 0);
+	return 0;
+}
+
+/*
+ * workspace_size
+ *
+ * Description:
+ * Returns the number of bytes of RAM needed for this
+ * code to do its work. (Used when calculating whether
+ * we have enough memory to be able to suspend & resume).
+ *
+ */
+static unsigned long swapwriter_memory_needed(void)
+{
+	return 1;
+}
+
+/* Print debug info
+ *
+ * Description:
+ */
+
+static int swapwriter_print_debug_stats(char * buffer, int size)
+{
+	int len = 0;
+	struct sysinfo sysinfo;
+	
+	if (active_writer != &swapwriterops) {
+		len = suspend_snprintf(buffer, size, "- Swapwriter inactive.\n");
+		return len;
+	}
+
+	len = suspend_snprintf(buffer, size, "- Swapwriter active.\n");
+	if (swapfilename[0])
+		len+= suspend_snprintf(buffer+len, size-len,
+			"  Attempting to automatically swapon: %s.\n", swapfilename);
+
+	si_swapinfo(&sysinfo);
+	
+	len+= suspend_snprintf(buffer+len, size-len, "  Swap available for image: %ld pages.\n",
+			sysinfo.freeswap + swapwriter_storage_allocated());
+
+	return len;
+}
+
+/*
+ * Storage needed
+ *
+ * Returns amount of space in the swap header required
+ * for the swapwriter's data. This ignores the links between
+ * pages, which we factor in when allocating the space.
+ *
+ * We ensure the space is allocated, but actually save the
+ * data from write_header_init and therefore don't also define a
+ * save_config_info routine.
+ */
+static unsigned long swapwriter_storage_needed(void)
+{
+	return sizeof(header_data);
+}
+
+/*
+ * Image_exists
+ *
+ */
+
+static int swapwriter_image_exists(void)
+{
+	int signature_found;
+	union p_diskpage diskpage;
+	
+	if (!resume_device) {
+		printk("Not even trying to read header "
+				"because resume_device is not set.\n");
+		return 0;
+	}
+	
+	if (!resume_block_device && !try_to_open_resume_device())
+		return 0;
+
+	diskpage.address = get_zeroed_page(GFP_ATOMIC);
+
+	suspend_bio_ops.bdev_page_io(READ, resume_block_device,
+			resume_firstblock, virt_to_page(diskpage.ptr));
+	suspend_bio_ops.finish_all_io();
+
+	signature_found = parse_signature(diskpage.pointer->swh.magic.magic, 0);
+	free_pages(diskpage.address, 0);
+
+	if (signature_found < 2) {
+		return 0;	/* Normal swap space */
+	} else if (signature_found == -1) {
+		printk(KERN_ERR name_suspend
+			"Unable to find a signature. Could you have moved "
+			"a swap file?\n");
+		return 0;
+	} else if (signature_found < 6) {
+		if ((!(test_suspend_state(SUSPEND_NORESUME_SPECIFIED)))
+				&& suspend_early_boot_message(1,
+				SUSPEND_CONTINUE_REQ,
+				"Detected the signature of an alternate "
+				"implementation.\n"))
+			set_suspend_state(SUSPEND_NORESUME_SPECIFIED);
+		return 0;
+	} else if ((signature_found >> 1) != SIGNATURE_VER) {
+		if ((!(test_suspend_state(SUSPEND_NORESUME_SPECIFIED))) &&
+			suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+			 "Found a different style suspend image signature."))
+			set_suspend_state(SUSPEND_NORESUME_SPECIFIED);
+	}
+
+	return 1;
+}
+
+/*
+ * Mark resume attempted.
+ *
+ * Record that we tried to resume from this image.
+ */
+
+static void swapwriter_mark_resume_attempted(void)
+{
+	union p_diskpage diskpage;
+	int signature_found;
+	
+	if (!resume_device) {
+		printk("Not even trying to record attempt at resuming"
+				" because resume_device is not set.\n");
+		return;
+	}
+	
+	diskpage.address = get_zeroed_page(GFP_ATOMIC);
+
+	/* FIXME: Make sure bdev_page_io handles wrong parameters */
+	suspend_bio_ops.bdev_page_io(READ, resume_block_device, resume_firstblock, virt_to_page(diskpage.ptr));
+	signature_found = parse_signature(diskpage.pointer->swh.magic.magic, 0);
+
+	switch (signature_found) {
+		case 12:
+		case 13:
+			diskpage.pointer->swh.magic.magic[5] |= 0x80;
+			break;
+	}
+	
+	suspend_bio_ops.bdev_page_io(WRITE, resume_block_device, resume_firstblock,
+			virt_to_page(diskpage.ptr));
+	suspend_bio_ops.finish_all_io();
+	free_pages(diskpage.address, 0);
+	
+	cleanup_opened_devices(1);
+	return;
+}
+
+/*
+ * Parse Image Location
+ *
+ * Attempt to parse a resume2= parameter.
+ * Swap Writer accepts:
+ * resume2=swap:DEVNAME[:FIRSTBLOCK][@BLOCKSIZE]
+ *
+ * Where:
+ * DEVNAME is convertable to a dev_t by name_to_dev_t
+ * FIRSTBLOCK is the location of the first block in the swap file
+ * (specifying for a swap partition is nonsensical but not prohibited).
+ * BLOCKSIZE is the logical blocksize >= 512 & <= PAGE_SIZE, 
+ * mod 512 == 0 of the device.
+ * Data is validated by attempting to read a swap header from the
+ * location given. Failure will result in swapwriter refusing to
+ * save an image, and a reboot with correct parameters will be
+ * necessary.
+ */
+
+static int swapwriter_parse_image_location(char * commandline, int only_writer)
+{
+	char *thischar, *devstart = NULL, *colon = NULL, *at_symbol = NULL;
+	union p_diskpage diskpage;
+	int signature_found, result = -EINVAL, temp_result;
+
+	if (strncmp(commandline, "swap:", 5)) {
+		if (!only_writer)
+			return 1;
+	} else
+		commandline += 5;
+
+	devstart = thischar = commandline;
+	while ((*thischar != ':') && (*thischar != '@') &&
+		((thischar - commandline) < 250) && (*thischar))
+		thischar++;
+
+	if (*thischar == ':') {
+		colon = thischar;
+		*colon = 0;
+		thischar++;
+	}
+
+	while ((*thischar != '@') && ((thischar - commandline) < 250) && (*thischar))
+		thischar++;
+
+	if (*thischar == '@') {
+		at_symbol = thischar;
+		*at_symbol = 0;
+	}
+	
+	if (colon)
+		resume_firstblock = (int) simple_strtoul(colon + 1, NULL, 0);
+	else
+		resume_firstblock = 0;
+
+	if (at_symbol) {
+		resume_firstblocksize = (int) simple_strtoul(at_symbol + 1, NULL, 0);
+		if (resume_firstblocksize & 0x1FF)
+			printk("Swapwriter: Blocksizes are usually a multiple of 512. Don't expect this to work!\n");
+	} else
+		resume_firstblocksize = 4096;
+	
+	temp_result = try_to_parse_resume_device(devstart);
+
+	if (colon)
+		*colon = ':';
+	if (at_symbol)
+		*at_symbol = '@';
+
+	if (temp_result)
+		return -EINVAL;
+
+	diskpage.address = get_zeroed_page(GFP_ATOMIC);
+	if (!diskpage.address) {
+		printk(KERN_ERR name_suspend "Swapwriter: Failed to allocate a diskpage for I/O.\n");
+		return -ENOMEM;
+	}
+
+	if ((suspend_bio_ops.get_block_size(resume_block_device) 
+				!= resume_firstblocksize) &&
+	     (suspend_bio_ops.set_block_size(resume_block_device, resume_firstblocksize)
+	    			 == -EINVAL)) {
+		printk(KERN_ERR name_suspend "Swapwriter: Failed to set requested block size.\n");
+		goto invalid;
+	}
+
+	temp_result = suspend_bio_ops.bdev_page_io(READ, resume_block_device, resume_firstblock, virt_to_page(diskpage.ptr));
+	suspend_bio_ops.finish_all_io();
+	
+	if (temp_result) {
+		printk(KERN_ERR name_suspend "Swapwriter: Failed to submit I/O.\n");
+		goto invalid;
+	}
+	
+	signature_found = parse_signature(diskpage.pointer->swh.magic.magic, 0);
+
+	if (signature_found != -1) {
+		printk(KERN_ERR name_suspend "Swapwriter: Signature found.\n");
+		result = 0;
+	} else
+		printk(KERN_ERR name_suspend "Swapwriter: No swap signature found at specified location.\n");
+invalid:
+	free_page((unsigned long) diskpage.address);
+	return result;
+
+}
+
+static int header_locations_read_proc(char * page, char ** start, off_t off, int count,
+		int *eof, void *data)
+{
+	int i, printedpartitionsmessage = 0, len = 0, haveswap = 0, device_block_size;
+	struct inode *swapf = 0;
+	int zone;
+	char * path_page = (char *) __get_free_page(GFP_KERNEL);
+	char * path;
+	int path_len;
+	
+	*eof = 1;
+	if (!page)
+		return 0;
+
+	for (i = 0; i < MAX_SWAPFILES; i++) {
+		if (!swap_info[i].swap_file)
+			continue;
+		
+		if (S_ISBLK(swap_info[i].swap_file->f_dentry->d_inode->i_mode)) {
+			haveswap = 1;
+			if (!printedpartitionsmessage) {
+				len += sprintf(page + len, 
+					"For swap partitions, simply use the format: resume2=swap:/dev/hda1.\n");
+				printedpartitionsmessage = 1;
+			}
+		} else {
+			path_len = 0;
+			
+			path = get_path_for_swapfile(i, path_page);
+			path_len = sprintf(path_page, "%-31s ", path);
+			
+			haveswap = 1;
+			swapf = swap_info[i].swap_file->f_dentry->d_inode;
+			device_block_size = block_size(swap_info[i].bdev);
+			if (!(zone = bmap(swapf,0))) {
+				len+= sprintf(page + len, 
+					"Swapfile %-31s has been corrupted. Reuse mkswap on it and try again.\n",
+					path_page);
+			} else {
+				len+= sprintf(page + len, "For swapfile `%s`, use resume2=swap:/dev/<partition name>:0x%x@%d.\n",
+						path_page,
+						zone, device_block_size);
+			}
+
+		}
+	}
+	
+	if (!haveswap)
+		len = sprintf(page, "You need to turn on swap partitions before examining this file.\n");
+
+	free_pages((unsigned long) path_page, 0);
+	return len;
+}
+
+static struct suspend_proc_data swapwriter_proc_data[] = {
+	{
+	 .filename			= "swapfilename",
+	 .permissions			= PROC_RW,
+	 .type				= SUSPEND_PROC_DATA_STRING,
+	 .data = {
+		.string = {
+			.variable	= swapfilename,
+			.max_length	= 255,
+		}
+	 }
+	},
+
+	{
+	 .filename			= "headerlocations",
+	 .permissions			= PROC_READONLY,
+	 .type				= SUSPEND_PROC_DATA_CUSTOM,
+	 .data = {
+		 .special = {
+			.read_proc 	= header_locations_read_proc,
+		}
+	 }
+	},
+
+	{ .filename			= "disable_swapwriter",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_INTEGER,
+	  .data = {
+		.integer = {
+			.variable	= &swapwriterops.disabled,
+			.minimum	= 0,
+			.maximum	= 1,
+		}
+	  },
+	  .write_proc			= attempt_to_parse_resume_device,
+	}
+};
+
+static struct suspend_plugin_ops swapwriterops = {
+	.type					= WRITER_PLUGIN,
+	.name					= "Swap Writer",
+	.module					= THIS_MODULE,
+	.memory_needed				= swapwriter_memory_needed,
+	.print_debug_info			= swapwriter_print_debug_stats,
+	.storage_needed				= swapwriter_storage_needed,
+	.initialise				= swapwriter_initialise,
+	.cleanup				= swapwriter_cleanup,
+
+	.write_init				= swapwriter_write_init,
+	.write_cleanup				= swapwriter_write_cleanup,
+	.read_init				= swapwriter_read_init,
+	.read_cleanup				= swapwriter_read_cleanup,
+
+	.ops = {
+		.writer = {
+		 .write_chunk		= swapwriter_write_chunk,
+		 .read_chunk		= swapwriter_read_chunk,
+		 .noresume_reset	= swapwriter_noresume_reset,
+		 .storage_available 	= swapwriter_storage_available,
+		 .storage_allocated	= swapwriter_storage_allocated,
+		 .release_storage	= swapwriter_release_storage,
+		 .allocate_header_space	= swapwriter_allocate_header_space,
+		 .allocate_storage	= swapwriter_allocate_storage,
+		 .image_exists		= swapwriter_image_exists,
+		 .mark_resume_attempted	= swapwriter_mark_resume_attempted,
+		 .write_header_init	= swapwriter_write_header_init,
+		 .write_header_chunk	= swapwriter_write_header_chunk,
+		 .write_header_cleanup	= swapwriter_write_header_cleanup,
+		 .read_header_init	= swapwriter_read_header_init,
+		 .read_header_chunk	= swapwriter_read_header_chunk,
+		 .read_header_cleanup	= swapwriter_read_header_cleanup,
+		 .serialise_extents	= swapwriter_serialise_extents,
+		 .load_extents		= swapwriter_load_extents,
+		 .invalidate_image	= swapwriter_invalidate_image,
+		 .parse_image_location	= swapwriter_parse_image_location,
+		}
+	}
+};
+
+/* ---- Registration ---- */
+static __init int swapwriter_load(void)
+{
+	int result;
+	int i, numfiles = sizeof(swapwriter_proc_data) / sizeof(struct suspend_proc_data);
+	
+	printk("Software Suspend Swap Writer loading.\n");
+	if (!(result = suspend_register_plugin(&swapwriterops))) {
+
+		for (i=0; i< numfiles; i++)
+			suspend_register_procfile(&swapwriter_proc_data[i]);
+	} else
+		printk("Software Suspend Swap Writer unable to register!\n");
+	return result;
+}
+
+#ifdef MODULE
+static __exit void swapwriter_unload(void)
+{
+	int i, numfiles = sizeof(swapwriter_proc_data) / sizeof(struct suspend_proc_data);
+
+	printk("Software Suspend Swap Writer unloading.\n");
+
+	for (i=0; i< numfiles; i++)
+		suspend_unregister_procfile(&swapwriter_proc_data[i]);
+	suspend_unregister_plugin(&swapwriterops);
+}
+
+module_init(swapwriter_load);
+module_exit(swapwriter_unload);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nigel Cunningham");
+MODULE_DESCRIPTION("Suspend2 swap writer");
+#else
+late_initcall(swapwriter_load);
+#endif


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [46/48] Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (42 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [48/48] Suspend2 2.1.9.8 for 2.6.12: 624-filewriter.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  6:33   ` Pekka Enberg
  2005-07-07 13:32   ` [PATCH] [46/48] " Pekka Enberg
  2005-07-06  2:20 ` [PATCH] [42/48] Suspend2 2.1.9.8 for 2.6.12: 618-core.patch Nigel Cunningham
                   ` (7 subsequent siblings)
  51 siblings, 2 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 623-generic-block-io.patch-old/kernel/power/block_io.h 623-generic-block-io.patch-new/kernel/power/block_io.h
--- 623-generic-block-io.patch-old/kernel/power/block_io.h	1970-01-01 10:00:00.000000000 +1000
+++ 623-generic-block-io.patch-new/kernel/power/block_io.h	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,55 @@
+/*
+ * block_io.h
+ *
+ * Copyright 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * Distributed under GPLv2.
+ *
+ * This file contains declarations for functions exported from
+ * block_io.c, which contains low level io functions.
+ */
+
+/* 
+ * The maximum amount of I/O we submit at once.
+ */
+#define MAX_READAHEAD 1024
+
+/* Forward Declarations */
+
+/*
+ * submit_params
+ *
+ * The structure we use for tracking submitted I/O.
+ */
+struct submit_params {
+	swp_entry_t swap_address;
+	struct page * page;
+	struct block_device * dev;
+	long block[8];
+	int readahead_index;
+	struct submit_params * next;
+};
+
+
+/* 
+ * Our exported interface so the swapwriter and filewriter don't
+ * need these functions duplicated.
+ */
+struct suspend_bio_ops {
+	int (*set_block_size) (struct block_device * bdev, int size);
+	int (*get_block_size) (struct block_device * bdev);
+	int (*submit_io) (int rw, 
+		struct submit_params * submit_info, int syncio);
+	int (*bdev_page_io) (int rw, struct block_device * bdev, long pos,
+			struct page * page);
+	void (*wait_on_readahead) (int readahead_index);
+	void (*check_io_stats) (void);
+	void (*reset_io_stats) (void);
+	void (*finish_all_io) (void);
+	int (*prepare_readahead) (int index);
+	void (*cleanup_readahead) (int index);
+	struct page ** readahead_pages;
+	int (*readahead_ready) (int readahead_index);
+};
+
+extern struct suspend_bio_ops suspend_bio_ops;
diff -ruNp 623-generic-block-io.patch-old/kernel/power/suspend_block_io.c 623-generic-block-io.patch-new/kernel/power/suspend_block_io.c
--- 623-generic-block-io.patch-old/kernel/power/suspend_block_io.c	1970-01-01 10:00:00.000000000 +1000
+++ 623-generic-block-io.patch-new/kernel/power/suspend_block_io.c	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,817 @@
+/*
+ * block_io.c
+ *
+ * Copyright 2004-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * Distributed under GPLv2.
+ * 
+ * This file contains block io functions for suspend2. These are
+ * used by the swapwriter and it is planned that they will also
+ * be used by the NFSwriter.
+ *
+ */
+
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/highmem.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/kthread.h>
+
+#include "suspend2_core/suspend.h"
+#include "suspend2_core/proc.h"
+#include "suspend2_core/plugins.h"
+#include "suspend2_core/utility.h"
+#include "suspend2_core/prepare_image.h"
+
+#include "block_io.h"
+
+/* Bits in struct io_info->flags */
+#define IO_WRITING 1
+#define IO_RESTORE_PAGE_PROT 2
+#define IO_AWAITING_READ 3
+#define IO_AWAITING_WRITE 4
+#define IO_AWAITING_SUBMIT 5
+#define IO_AWAITING_CLEANUP 6
+#define IO_HANDLE_PAGE_PROT 7
+
+#define MAX_OUTSTANDING_IO 1024
+
+/*
+ * ---------------------------------------------------------------
+ *
+ *     IO in progress information storage and helpers
+ *
+ * ---------------------------------------------------------------
+ */
+
+struct io_info {
+	struct bio * sys_struct;
+	long block[PAGE_SIZE/512];
+	struct page * buffer_page;
+	struct page * data_page;
+	unsigned long flags;
+	struct block_device * dev;
+	struct list_head list;
+	int readahead_index;
+	struct work_struct work;
+};
+
+/* Locks separated to allow better SMP support.
+ * An io_struct moves through the lists as follows.
+ * free -> submit_batch -> busy -> ready_for_cleanup -> free
+ */
+static LIST_HEAD(ioinfo_free);
+static spinlock_t ioinfo_free_lock = SPIN_LOCK_UNLOCKED;
+
+static LIST_HEAD(ioinfo_ready_for_cleanup);
+static spinlock_t ioinfo_ready_lock = SPIN_LOCK_UNLOCKED;
+
+static LIST_HEAD(ioinfo_submit_batch);
+static spinlock_t ioinfo_submit_lock = SPIN_LOCK_UNLOCKED;
+
+static LIST_HEAD(ioinfo_busy);
+static spinlock_t ioinfo_busy_lock = SPIN_LOCK_UNLOCKED;
+
+static atomic_t submit_batch;
+static int submit_batch_size = 64;
+static int submit_batched(void);
+
+struct task_struct * suspend_bio_task;
+
+/* [Max] number of I/O operations pending */
+static atomic_t outstanding_io;
+static int max_outstanding_io = 0;
+static atomic_t buffer_allocs, buffer_frees;
+
+/* [Max] number of pages used for above struct */
+static int infopages = 0;
+static int maxinfopages = 0;
+
+#define BITS_PER_UL (8 * sizeof(unsigned long))
+static volatile unsigned long suspend_readahead_flags[(MAX_READAHEAD + BITS_PER_UL - 1) / BITS_PER_UL];
+static spinlock_t suspend_readahead_flags_lock = SPIN_LOCK_UNLOCKED;
+static struct page * suspend_readahead_pages[MAX_READAHEAD];
+
+static unsigned long nr_schedule_calls[8];
+
+static char * sch_caller[] = {
+	"get_io_info_struct #1    ",
+	"get_io_info_struct #2    ",
+	"get_io_info_struct #3    ",
+	"suspend_finish_all_io    ",
+	"wait_on_one_page         ",
+	"submit                   ",
+	"start_one                ",
+	"suspend_wait_on_readahead",
+};
+
+static int __suspend_io_cleanup(void * data);
+
+/* cleanup_some_completed_io
+ *
+ * NB: This is designed so that multiple callers can be in here simultaneously.
+ */
+
+static void cleanup_some_completed_io(void)
+{
+	int num_cleaned = 0;
+	struct io_info * first;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioinfo_ready_lock, flags);
+	while(!list_empty(&ioinfo_ready_for_cleanup)) {
+		int result;
+		first = list_entry(ioinfo_ready_for_cleanup.next, struct io_info, list);
+
+		BUG_ON(!test_and_clear_bit(IO_AWAITING_CLEANUP, &first->flags));
+
+		list_del_init(&first->list);
+
+		spin_unlock_irqrestore(&ioinfo_ready_lock, flags);
+
+		result = __suspend_io_cleanup((void *) first);
+
+		spin_lock_irqsave(&ioinfo_ready_lock, flags);
+		if (result)
+			continue;
+		num_cleaned++;
+		if (num_cleaned == submit_batch_size)
+			break;
+	}
+	spin_unlock_irqrestore(&ioinfo_ready_lock, flags);
+}
+
+/* do_bio_wait
+ *
+ * Actions taken when we want some I/O to get run.
+ * 
+ * Submit any I/O that's batched up, unplug queues, schedule
+ * and clean up whatever we can.
+ */
+static void do_bio_wait(int caller)
+{
+	int device;
+	int num_submitted = 0;
+
+	nr_schedule_calls[caller]++;
+	
+	/* Don't want to wait on I/O we haven't submitted! */
+	num_submitted = submit_batched();
+
+	for (device = 0; device < MAX_SWAPFILES; device++) {
+		struct block_device * bdev = swap_info[device].bdev;
+		/* Check for a potential oops here */
+		if (bdev && bdev->bd_disk) {
+			request_queue_t * q = bdev_get_queue(bdev);
+			if (q && q->unplug_fn)
+				q->unplug_fn(q);
+		}
+		/* kblockd_flush(); io_schedule(); */
+	}
+
+	schedule();
+
+	cleanup_some_completed_io();
+}
+
+/*
+ * cleanup_one
+ * 
+ * Description: Clean up after completing I/O on a page.
+ * Arguments:	struct io_info:	Data for I/O to be completed.
+ */
+static inline void cleanup_one(struct io_info * io_info)
+{
+	struct page * buffer_page;
+	struct page * data_page;
+	char *buffer_address, *data_address;
+	int reading;
+
+	buffer_page = io_info->buffer_page;
+	data_page = io_info->data_page;
+
+	reading = test_bit(IO_AWAITING_READ, &io_info->flags);
+	suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 0,
+		"Cleanup IO: [%p]\n", 
+		io_info);
+
+	if (reading && io_info->readahead_index == -1) {
+		/*
+		 * Copy the page we read into the buffer our caller provided.
+		 */
+		data_address = (char *) kmap(data_page);
+		buffer_address = (char *) kmap(buffer_page);
+		memcpy(data_address, buffer_address, PAGE_SIZE);
+		flush_dcache_page(data_page);
+		kunmap(data_page);
+		kunmap(buffer_page);
+	
+	}
+
+	if (!reading || io_info->readahead_index == -1) {
+		/* Sanity check */
+		if (page_count(buffer_page) != 2)
+			printk(KERN_EMERG "Cleanup IO: Page count on page %p is %d. Not good!\n",
+					buffer_page, page_count(buffer_page));
+		put_page(buffer_page);
+		__free_pages(buffer_page, 0);
+		atomic_inc(&buffer_frees);
+	} else
+		put_page(buffer_page);
+	
+	bio_put(io_info->sys_struct);
+	io_info->sys_struct = NULL;
+	io_info->flags = 0;
+}
+
+/*
+ * get_io_info_struct
+ *
+ * Description:	Get an I/O struct.
+ * Returns:	Pointer to the struct prepared for use.
+ */
+static struct io_info * get_io_info_struct(void)
+{
+	unsigned long newpage = 0, flags;
+	struct io_info * this = NULL;
+	int remaining = 0;
+
+	do {
+		while (atomic_read(&outstanding_io) >= MAX_OUTSTANDING_IO)
+			do_bio_wait(0);
+
+		/* Can start a new I/O. Is there a free one? */
+		if (!list_empty(&ioinfo_free)) {
+			/* Yes. Grab it. */
+			spin_lock_irqsave(&ioinfo_free_lock, flags);
+			break;
+		}
+
+		/* No. Need to allocate a new page for I/O info structs. */
+		newpage = get_zeroed_page(GFP_ATOMIC);
+		if (!newpage) {
+			do_bio_wait(1);
+			continue;
+		}
+
+		suspend_message(SUSPEND_MEMORY, SUSPEND_VERBOSE, 0,
+				"[NewIOPage %lx]", newpage);
+		infopages++;
+		if (infopages > maxinfopages)
+			maxinfopages++;
+
+		/* Prepare the new page for use. */
+		this = (struct io_info *) newpage;
+		remaining = PAGE_SIZE;
+		spin_lock_irqsave(&ioinfo_free_lock, flags);
+		while (remaining >= (sizeof(struct io_info))) {
+			list_add_tail(&this->list, &ioinfo_free);
+			this = (struct io_info *) (((char *) this) + 
+					sizeof(struct io_info));
+			remaining -= sizeof(struct io_info);
+		}
+		break;
+	} while (1);
+
+	/*
+	 * We have an I/O info struct. Remove it from the free list.
+	 * It will be added to the submit or busy list later.
+	 */
+	this = list_entry(ioinfo_free.next, struct io_info, list);
+	list_del_init(&this->list);
+	spin_unlock_irqrestore(&ioinfo_free_lock, flags);
+	return this;
+}
+
+/*
+ * suspend_finish_all_io
+ *
+ * Description:	Finishes all IO and frees all IO info struct pages.
+ */
+static void suspend_finish_all_io(void)
+{
+	struct io_info * this, * next = NULL;
+	unsigned long flags;
+
+	/* Wait for all I/O to complete. */
+	while (atomic_read(&outstanding_io))
+		do_bio_wait(2);
+
+	spin_lock_irqsave(&ioinfo_free_lock, flags);
+	
+	/* 
+	 * Two stages, to avoid using freed pages.
+	 *
+	 * First free all io_info structs on a page except the first.
+	 */
+	list_for_each_entry_safe(this, next, &ioinfo_free, list) {
+		if (((unsigned long) this) & ~PAGE_MASK)
+			list_del(&this->list);
+	}
+
+	/* 
+	 * Now we have only one reference to each page, and can safely
+	 * free pages, knowing we're not going to be trying to access the
+	 * same page after freeing it.
+	 */
+	list_for_each_entry_safe(this, next, &ioinfo_free, list) {
+		list_del(&this->list);
+		free_pages((unsigned long) this, 0);
+		infopages--;
+		suspend_message(SUSPEND_MEMORY, SUSPEND_VERBOSE, 0,
+				"[FreedIOPage %lx]", this);
+	}
+	
+	spin_unlock_irqrestore(&ioinfo_free_lock, flags);
+}
+
+/*
+ * wait_on_one_page
+ *
+ * Description:	Wait for a particular I/O to complete.
+ */
+static void wait_on_one_page(struct io_info * io_info)
+{
+	do { do_bio_wait(3); } while (io_info->flags);
+}
+
+/*
+ * suspend_reset_io_stats
+ *
+ * Description:	Reset all our sanity-checking statistics.
+ */
+static void suspend_reset_io_stats(void)
+{
+	int i;
+	
+	max_outstanding_io = 0;
+	maxinfopages = 0;
+	
+	for (i = 0; i < 8; i++)
+		nr_schedule_calls[i] = 0;
+}
+
+/*
+ * suspend_check_io_stats
+ *
+ * Description:	Check that our statistics look right and print
+ * 		any debugging info wanted.
+ */
+static void suspend_check_io_stats(void)
+{
+	int i;
+
+	BUG_ON(atomic_read(&outstanding_io));
+	BUG_ON(infopages);
+	BUG_ON(!list_empty(&ioinfo_submit_batch));
+	BUG_ON(!list_empty(&ioinfo_busy));
+	BUG_ON(!list_empty(&ioinfo_ready_for_cleanup));
+	BUG_ON(!list_empty(&ioinfo_free));
+	BUG_ON(atomic_read(&buffer_allocs) != atomic_read(&buffer_frees));
+
+	if (atomic_read(&outstanding_io))
+		suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
+			"Outstanding_io after writing is %d.\n",
+			atomic_read(&outstanding_io));
+	suspend_message(SUSPEND_WRITER, SUSPEND_LOW, 0,
+			"Maximum outstanding_io was %d.\n",
+			max_outstanding_io);
+	if (infopages)
+		suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
+				"Info pages is %d.\n",
+				infopages);
+	suspend_message(SUSPEND_WRITER, SUSPEND_LOW, 0,
+			"Max info pages was %d.\n",
+			maxinfopages);
+	if (atomic_read(&buffer_allocs) != atomic_read(&buffer_frees))
+		suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
+			"Buffer allocs (%d) != buffer frees (%d)",
+				atomic_read(&buffer_allocs),
+				atomic_read(&buffer_frees));
+	for(i = 0; i < 8; i++)
+		suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
+			"Nr schedule calls %s: %lu.\n", sch_caller[i], nr_schedule_calls[i]);
+}
+
+/* __suspend_io_cleanup
+ */
+
+static int __suspend_io_cleanup(void * data)
+{
+	struct io_info * io_info = (struct io_info *) data;
+	int readahead_index;
+	unsigned long flags;
+
+	/*
+	 * If this I/O was a readahead, remember its index.
+	 */
+	readahead_index = io_info->readahead_index;
+
+	/*
+	 * Add it to the free list.
+	 */
+	list_del_init(&io_info->list);
+	
+	/*
+	 * Do the cleanup.
+	 */
+	cleanup_one(io_info);
+
+	/*
+	 * Record the readahead as done.
+	 */
+	if (readahead_index > -1) {
+		int index = readahead_index/(8 * sizeof(unsigned long));
+		int bit = readahead_index - (index * 8 * sizeof(unsigned long));
+		spin_lock_irqsave(&suspend_readahead_flags_lock, flags);
+		set_bit(bit, &suspend_readahead_flags[index]);
+		spin_unlock_irqrestore(&suspend_readahead_flags_lock, flags);
+	}
+
+	spin_lock_irqsave(&ioinfo_free_lock, flags);
+	list_add_tail(&io_info->list, &ioinfo_free);
+	spin_unlock_irqrestore(&ioinfo_free_lock, flags);
+	
+	/* Important: Must be last thing we do to avoid a race with
+	 * finish_all_io when using keventd to do the cleanup */
+	atomic_dec(&outstanding_io);
+
+	return 0;
+}
+
+/*
+ * suspend_end_bio
+ *
+ * Description:	Function called by block driver from interrupt context when I/O
+ * 		is completed. This is the reason we use spinlocks in
+ * 		manipulating the io_info lists. 		
+ * 		Nearly the fs/buffer.c version, but we want to mark the page as 
+ * 		done in our own structures too.
+ */
+
+static int suspend_end_bio(struct bio * bio, unsigned int num, int err)
+{
+	struct io_info *io_info = (struct io_info *) bio->bi_private;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioinfo_busy_lock, flags);
+	list_del_init(&io_info->list);
+	spin_unlock_irqrestore(&ioinfo_busy_lock, flags);
+
+	set_bit(IO_AWAITING_CLEANUP, &io_info->flags);
+		
+	spin_lock_irqsave(&ioinfo_ready_lock, flags);
+	list_add_tail(&io_info->list, &ioinfo_ready_for_cleanup);
+	spin_unlock_irqrestore(&ioinfo_ready_lock, flags);
+	return 0;
+}
+
+/**
+ *	submit - submit BIO request.
+ *	@rw:	READ or WRITE.
+ *	@io_info: IO info structure.
+ *
+ * 	Based on Patrick's pmdisk code from long ago:
+ *	"Straight from the textbook - allocate and initialize the bio.
+ *	If we're writing, make sure the page is marked as dirty.
+ *	Then submit it and carry on."
+ *
+ *	With a twist, though - we handle block_size != PAGE_SIZE.
+ *	Caller has already checked that our page is not fragmented.
+ */
+
+static int submit(int rw, struct io_info * io_info)
+{
+	int error = 0;
+	struct bio * bio = NULL;
+	unsigned long flags;
+
+	while (!bio) {
+		bio = bio_alloc(GFP_ATOMIC,1);
+		if (!bio)
+			do_bio_wait(4);
+	}
+
+	bio->bi_bdev = io_info->dev;
+	bio->bi_sector = io_info->block[0] * (io_info->dev->bd_block_size >> 9);
+	bio->bi_private = io_info;
+	bio->bi_end_io = suspend_end_bio;
+	io_info->sys_struct = bio;
+
+	if (bio_add_page(bio, io_info->buffer_page, PAGE_SIZE, 0) < PAGE_SIZE) {
+		printk("ERROR: adding page to bio at %ld\n",
+				io_info->block[0]);
+		bio_put(bio);
+		return -EFAULT;
+	}
+
+	if (rw == WRITE)
+		bio_set_pages_dirty(bio);
+
+	spin_lock_irqsave(&ioinfo_busy_lock, flags);
+	list_add_tail(&io_info->list, &ioinfo_busy);
+	spin_unlock_irqrestore(&ioinfo_busy_lock, flags);
+	
+	submit_bio(rw,bio);
+
+	return error;
+}
+
+/*
+ * suspend_set_block_size
+ *
+ * Description: Set the blocksize for a bdev. This is a separate function
+ * 		because we have different versions for 2.4 and 2.6.
+ */
+static int suspend_set_block_size(struct block_device * bdev, int size)
+{
+	return set_blocksize(bdev, size);
+}
+
+static int suspend_get_block_size(struct block_device * bdev)
+{
+	return block_size(bdev);
+}
+
+/* 
+ * submit a batch
+ */
+static int submit_batched(void)
+{
+	struct io_info * first;
+	unsigned long flags;
+	int num_submitted = 0;
+
+	spin_lock_irqsave(&ioinfo_submit_lock, flags);
+	while(!list_empty(&ioinfo_submit_batch)) {
+		first = list_entry(ioinfo_submit_batch.next, struct io_info, list);
+
+		BUG_ON(!test_and_clear_bit(IO_AWAITING_SUBMIT, &first->flags));
+
+		list_del_init(&first->list);
+
+		atomic_dec(&submit_batch);
+
+		spin_unlock_irqrestore(&ioinfo_submit_lock, flags);
+
+		if (test_bit(IO_AWAITING_READ, &first->flags))
+			submit(READ, first);
+		else
+			submit(WRITE, first);
+
+		spin_lock_irqsave(&ioinfo_submit_lock, flags);
+		
+		num_submitted++;
+		if (num_submitted == submit_batch_size)
+			break;
+	}
+	spin_unlock_irqrestore(&ioinfo_submit_lock, flags);
+
+	return num_submitted;
+}
+static void add_to_batch(struct io_info * io_info)
+{
+	unsigned long flags;
+	
+	set_bit(IO_AWAITING_SUBMIT, &io_info->flags);
+
+	/* Put our prepared I/O struct on the batch list. */
+	spin_lock_irqsave(&ioinfo_submit_lock, flags);
+	list_add_tail(&io_info->list, &ioinfo_submit_batch);
+	spin_unlock_irqrestore(&ioinfo_submit_lock, flags);
+
+	atomic_inc(&submit_batch);
+
+	if ((!suspend_bio_task) && (atomic_read(&submit_batch) >= submit_batch_size))
+		submit_batched();
+}
+/*
+ * start_one
+ *
+ * Description:	Prepare and start a read or write operation.
+ * 		Note that we use our own buffer for reading or writing.
+ * 		This simplifies doing readahead and asynchronous writing.
+ * 		We can begin a read without knowing the location into which
+ * 		the data will eventually be placed, and the buffer passed
+ * 		for a write can be reused immediately (essential for the
+ * 		plugins system).
+ * 		Failure? What's that?
+ * Returns:	The io_info struct created.
+ */
+static struct io_info * start_one(int rw, struct submit_params * submit_info)
+{
+	struct io_info * io_info = get_io_info_struct();
+	unsigned long buffer_virt = 0;
+	char * to, * from;
+	struct page * buffer_page;
+
+	if (!io_info)
+		return NULL;
+
+	/* Get our local buffer */
+	suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 1,
+			"Start_IO: [%p]", io_info);
+	
+	/* Copy settings to the io_info struct */
+	io_info->data_page = submit_info->page;
+	io_info->readahead_index = submit_info->readahead_index;
+
+	if (io_info->readahead_index == -1) {
+		while (!(buffer_virt = get_zeroed_page(GFP_ATOMIC)))
+			do_bio_wait(5);
+
+		atomic_inc(&buffer_allocs);
+		suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 0,
+				"[ALLOC BUFFER]->%d",
+				real_nr_free_pages());
+		buffer_page = virt_to_page(buffer_virt);
+	
+		io_info->buffer_page = buffer_page;
+	} else {
+		unsigned long flags;
+		int index = io_info->readahead_index/(8 * sizeof(unsigned long));
+		int bit = io_info->readahead_index - index * 8 * sizeof(unsigned long);
+
+		spin_lock_irqsave(&suspend_readahead_flags_lock, flags);
+		clear_bit(bit, &suspend_readahead_flags[index]);
+		spin_unlock_irqrestore(&suspend_readahead_flags_lock, flags);
+
+		io_info->buffer_page = buffer_page = submit_info->page;
+	}
+
+	/* If writing, copy our data. The data is probably in
+	 * lowmem, but we cannot be certain. If there is no
+	 * compression/encryption, we might be passed the
+	 * actual source page's address. */
+	if (rw == WRITE) {
+		set_bit(IO_WRITING, &io_info->flags);
+
+		to = (char *) buffer_virt;
+		from = kmap_atomic(io_info->data_page, KM_USER1);
+		memcpy(to, from, PAGE_SIZE);
+		flush_dcache_page(io_info->data_page);
+		flush_dcache_page(buffer_page);
+		kunmap_atomic(from, KM_USER1);
+	}
+
+	/* Submit the page */
+	get_page(buffer_page);
+	
+	io_info->dev = submit_info->dev;
+	io_info->block[0] = submit_info->block[0];
+
+	if (rw == READ)
+		set_bit(IO_AWAITING_READ, &io_info->flags);
+	else
+		set_bit(IO_AWAITING_WRITE, &io_info->flags);
+
+	suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 1,
+			"-> (PRE BRW) %d\n",
+			real_nr_free_pages());
+
+	if (submit_batch_size > 1)
+		add_to_batch(io_info);
+	else
+	 	submit(rw, io_info);
+	
+	atomic_inc(&outstanding_io);
+	if (atomic_read(&outstanding_io) > max_outstanding_io)
+		max_outstanding_io++;
+	
+	return io_info;
+}
+
+static int suspend_do_io(int rw, 
+		struct submit_params * submit_info, int syncio)
+{
+	struct io_info * io_info = start_one(rw, submit_info);
+	if (!io_info)
+		return 1;
+	else if (syncio)
+		wait_on_one_page(io_info);
+
+	/* If we were the only one, clean everything up */
+	if (!atomic_read(&outstanding_io))
+		suspend_finish_all_io();
+	return 0;
+} 
+
+/* We used to use bread here, but it doesn't correctly handle
+ * blocksize != PAGE_SIZE. Now we create a submit_info to get the data we
+ * want and use our normal routines (synchronously).
+ */
+
+static int suspend_bdev_page_io(int rw, struct block_device * bdev, long pos,
+		struct page * page)
+{
+	struct submit_params submit_info;
+
+	submit_info.page = page;
+	submit_info.dev = bdev;
+	submit_info.block[0] = pos;
+	submit_info.readahead_index = -1;
+	return suspend_do_io(rw, &submit_info, 1);
+}
+
+/*
+ * wait_on_readahead
+ *
+ * Wait until a particular readahead is ready.
+ */
+static void suspend_wait_on_readahead(int readahead_index)
+{
+	int index = readahead_index/(8 * sizeof(unsigned long));
+	int bit = readahead_index - index * 8 * sizeof(unsigned long);
+
+	/* read_ahead_index is the one we want to return */
+	while (!test_bit(bit, &suspend_readahead_flags[index]))
+		do_bio_wait(6);
+}
+
+/*
+ * readahead_done
+ *
+ * Returns whether the readahead requested is ready.
+ */
+
+static int suspend_readahead_ready(int readahead_index)
+{
+	int index = readahead_index/(8 * sizeof(unsigned long));
+	int bit = readahead_index - (index * 8 * sizeof(unsigned long));
+
+	return test_bit(bit, &suspend_readahead_flags[index]);
+}
+
+/* suspend_readahead_prepare
+ * Set up for doing readahead on an image */
+static int suspend_prepare_readahead(int index)
+{
+	unsigned long new_page = get_zeroed_page(GFP_ATOMIC);
+
+	if(!new_page)
+		return -ENOMEM;
+
+	suspend_bio_ops.readahead_pages[index] = virt_to_page(new_page);
+	return 0;
+}
+
+/* suspend_readahead_cleanup
+ * Clean up structures used for readahead */
+static void suspend_cleanup_readahead(int page)
+{
+	__free_pages(suspend_bio_ops.readahead_pages[page], 0);
+	suspend_bio_ops.readahead_pages[page] = 0;
+	return;
+}
+
+static unsigned long suspend_bio_memory_needed(void)
+{
+	/* We want to have at least enough memory so as to have 128 I/O
+	 * transactions on the fly at once. If we can to more, fine. */
+	return (128 * (PAGE_SIZE + sizeof(struct request) +
+				sizeof(struct bio) + sizeof(struct io_info)));
+}
+
+struct suspend_bio_ops suspend_bio_ops = {
+	.set_block_size = suspend_set_block_size,
+	.get_block_size = suspend_get_block_size,
+	.submit_io = suspend_do_io,
+	.bdev_page_io = suspend_bdev_page_io,
+	.prepare_readahead = suspend_prepare_readahead,
+	.cleanup_readahead = suspend_cleanup_readahead,
+	.readahead_pages = suspend_readahead_pages,
+	.wait_on_readahead = suspend_wait_on_readahead,
+	.check_io_stats = suspend_check_io_stats,
+	.reset_io_stats = suspend_reset_io_stats,
+	.finish_all_io = suspend_finish_all_io,
+	.readahead_ready = suspend_readahead_ready,
+};
+
+static struct suspend_plugin_ops suspend_blockwriter_ops = 
+{
+	.name					= "Block I/O",
+	.type					= MISC_PLUGIN,
+	.module					= THIS_MODULE,
+	.memory_needed				= suspend_bio_memory_needed,
+};
+
+static __init int suspend_block_io_load(void)
+{
+	return suspend_register_plugin(&suspend_blockwriter_ops);
+}
+
+#ifdef MODULE
+static __exit void suspend_block_io_unload(void)
+{
+	suspend_unregister_plugin(&suspend_blockwriter_ops);
+}
+
+module_init(suspend_block_io_load);
+module_exit(suspend_block_io_unload);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nigel Cunningham");
+MODULE_DESCRIPTION("Suspend2 block io functions");
+#else
+late_initcall(suspend_block_io_load);
+#endif


^ permalink raw reply	[flat|nested] 187+ messages in thread

* [PATCH] [43/48] Suspend2 2.1.9.8 for 2.6.12: 619-userspace-nofreeze.patch
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (45 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [44/48] Suspend2 2.1.9.8 for 2.6.12: 620-userui.patch Nigel Cunningham
@ 2005-07-06  2:20 ` Nigel Cunningham
  2005-07-06  6:18   ` Pekka Enberg
  2005-07-10 23:15   ` Christoph Hellwig
  2005-07-06  2:20 ` [PATCH] [45/48] Suspend2 2.1.9.8 for 2.6.12: 621-swsusp-tidy.patch Nigel Cunningham
                   ` (4 subsequent siblings)
  51 siblings, 2 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  2:20 UTC (permalink / raw)
  To: linux-kernel

diff -ruNp 620-userui-header.patch-old/include/linux/netlink.h 620-userui-header.patch-new/include/linux/netlink.h
--- 620-userui-header.patch-old/include/linux/netlink.h	2005-06-20 11:47:29.000000000 +1000
+++ 620-userui-header.patch-new/include/linux/netlink.h	2005-07-04 23:14:19.000000000 +1000
@@ -14,6 +14,7 @@
 #define NETLINK_SELINUX		7	/* SELinux event notifications */
 #define NETLINK_ARPD		8
 #define NETLINK_AUDIT		9	/* auditing */
+#define NETLINK_SUSPEND2_USERUI	10	/* For suspend2's userui */
 #define NETLINK_ROUTE6		11	/* af_inet6 route comm channel */
 #define NETLINK_IP6_FW		13
 #define NETLINK_DNRTMSG		14	/* DECnet routing messages */
diff -ruNp 620-userui-header.patch-old/kernel/power/suspend2_core/ui.c 620-userui-header.patch-new/kernel/power/suspend2_core/ui.c
--- 620-userui-header.patch-old/kernel/power/suspend2_core/ui.c	1970-01-01 10:00:00.000000000 +1000
+++ 620-userui-header.patch-new/kernel/power/suspend2_core/ui.c	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,1186 @@
+/*
+ * kernel/power/ui.c
+ *
+ * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
+ * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr>
+ * Copyright (C) 2002-2005 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Routines for Software Suspend's user interface.
+ *
+ * The user interface code talks to a userspace program via a
+ * netlink socket.
+ *
+ * The kernel side:
+ * - starts the userui program;
+ * - sends text messages and progress bar status;
+ *
+ * The user space side:
+ * - passes messages regarding user requests (abort, toggle reboot etc)
+ *
+ */
+#define SUSPEND_CONSOLE_C
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/suspend.h>
+#include <linux/console.h>
+#include <linux/ctype.h>
+#include <linux/tty.h>
+#include <linux/vt_kern.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/kmod.h>
+#include <linux/netlink.h>
+#include <linux/security.h>
+#include <linux/syscalls.h>
+#include <net/sock.h>
+ 
+#include "proc.h"
+#include "plugins.h"
+#include "suspend.h"
+#include "suspend2_common.h"
+#include "ui.h"
+#include "version.h"
+#include "userui.h"
+
+#include "../power.h"
+
+static struct suspend_plugin_ops userui_ops;
+static int orig_loglevel;
+static int orig_default_message_loglevel;
+static int orig_kmsg;
+
+static char local_printf_buf[1024];	/* Same as printk - should be safe */
+static char lastheader[512];
+static int lastheader_message_len = 0;
+
+#define NUM_USERUI_SKBS 16 /* Number of preallocated skbs for emergencies */
+
+static char userui_program[256] = "";
+
+/* Number of distinct progress amounts that userspace can display */
+static int progress_granularity = 50;
+
+static struct sock *userui_nl;
+static u32 userui_sock_seq;
+static struct sk_buff *userui_skbs[NUM_USERUI_SKBS];
+static int next_free_userui_skb;
+static pid_t userui_pid = -1;
+
+DECLARE_WAIT_QUEUE_HEAD(userui_wait_for_process);
+DECLARE_WAIT_QUEUE_HEAD(userui_wait_for_key);
+
+void s2_userui_message(unsigned long section, unsigned long level,
+		int normally_logged,
+		const char *fmt, va_list args);
+unsigned long userui_update_progress(unsigned long value, unsigned long maximum,
+		const char *fmt, va_list args);
+void userui_prepare_console(void);
+void userui_cleanup_console(void);
+
+/* 
+ * Refill our pool of SKBs for use in emergencies (eg, when eating memory and none
+ * can be allocated).
+ */
+static void userui_replenish_skbs(void)
+{
+	while (next_free_userui_skb+1 < NUM_USERUI_SKBS) {
+		userui_skbs[next_free_userui_skb+1] =
+			alloc_skb(NLMSG_SPACE(sizeof(struct userui_msg_params)), GFP_ATOMIC);
+		if (userui_skbs[next_free_userui_skb+1])
+			next_free_userui_skb++;
+		else
+			break;
+	}
+}
+
+/* 
+ * Return a single skbuff either from our pool, or try to allocate one if
+ * the pool is exhausted.
+ */
+static struct sk_buff * userui_get_skb(void)
+{
+	struct sk_buff *skb;
+	if (next_free_userui_skb == -1)
+		skb = alloc_skb(NLMSG_SPACE(sizeof(struct userui_msg_params)), GFP_ATOMIC);
+	else {
+		skb = userui_skbs[next_free_userui_skb];
+		userui_skbs[next_free_userui_skb] = NULL;
+		next_free_userui_skb--;
+	}
+
+	userui_replenish_skbs();
+
+	return skb;
+}
+
+static void userui_notify_userspace(void* data)
+{
+	struct task_struct *t;
+	read_lock(&tasklist_lock);
+	if ((t = find_task_by_pid(userui_pid)))
+		wake_up_process(t);
+	read_unlock(&tasklist_lock);
+}
+
+DECLARE_WORK(userui_notify_userspace_work, userui_notify_userspace, NULL);
+
+static void userui_send_message(int type, void* params, size_t len)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh;
+	void *dest;
+
+	skb = userui_get_skb();
+	if (!skb) {
+		printk("suspend_userui: Can't allocate skb!\n");
+		return;
+	}
+
+	/* NLMSG_PUT contains a hidden goto nlmsg_failure */
+	nlh = NLMSG_PUT(skb, 0, userui_sock_seq, type, len);
+	userui_sock_seq++;
+
+	dest = NLMSG_DATA(nlh);
+	if (params && len > 0)
+		memcpy(dest, params, len);
+
+	netlink_unicast(userui_nl, skb, userui_pid, 0);
+
+	/* We may be in an interrupt context so defer waking up userspace */
+	schedule_work(&userui_notify_userspace_work);
+
+	return;
+
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+}
+
+/*
+ * Set the PF_NOFREEZE flag on the given process to ensure it can run whilst we
+ * are suspending.
+ */
+static int userui_nl_set_nofreeze(int pid)
+{
+	struct task_struct *t;
+	userui_pid = pid;
+
+	read_lock(&tasklist_lock);
+	if ((t = find_task_by_pid(userui_pid)) == NULL) {
+		read_unlock(&tasklist_lock);
+		return -EINVAL;
+	}
+
+	t->flags |= PF_NOFREEZE;
+
+	read_unlock(&tasklist_lock);
+
+	userui_send_message(USERUI_MSG_NOFREEZE_ACK, NULL, 0);
+
+	return 0;
+}
+
+#if CONFIG_PM_DEBUG
+static int is_debugging = 1;
+#else
+static int is_debugging = 0;
+#endif
+
+static void send_whether_debugging(void)
+{
+	userui_send_message(USERUI_MSG_IS_DEBUGGING, &is_debugging, sizeof(int));
+}
+
+/*
+ * Called when the userspace process has informed us that it's ready to roll.
+ */
+static int userui_nl_ready(int version)
+{
+	int ret = 0;
+	if (version != SUSPEND_USERUI_INTERFACE_VERSION) {
+		printk("suspend_userui: Userspace process using invalid interface version\n");
+		SET_RESULT_STATE(SUSPEND_ABORTED);
+		ret = -EINVAL;
+	}
+
+	wake_up_interruptible(&userui_wait_for_process);
+
+	return ret;
+}
+
+static int userui_nl_set_state(int n)
+{
+	/* Only let them change certain settings */
+	static const int suspend_action_mask =
+		(1 << SUSPEND_REBOOT) | (1 << SUSPEND_PAUSE) | (1 << SUSPEND_SLOW) |
+		(1 << SUSPEND_LOGALL) | (1 << SUSPEND_SINGLESTEP) |
+		(1 << SUSPEND_PAUSE_NEAR_PAGESET_END);
+
+	suspend_action = (suspend_action & (~suspend_action_mask)) |
+		(n & suspend_action_mask);
+
+	return 0;
+}
+
+static int userui_nl_set_progress_granularity(int n)
+{
+	if (n < 1) n = 1;
+	progress_granularity = n;
+	return 0;
+}
+
+static int userui_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
+{
+	int type;
+	int *data;
+
+	*errp = 0;
+
+	if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
+		return 0;
+
+	type = nlh->nlmsg_type;
+
+	/* A control message: ignore them */
+	if (type < USERUI_MSG_BASE)
+		return 0;
+
+	/* Unknown message: reply with EINVAL */
+	if (type >= USERUI_MSG_MAX) {
+		*errp = -EINVAL;
+		return -1;
+	}
+
+	/* All operations require privileges, even GET */
+	if (security_netlink_recv(skb)) {
+		*errp = -EPERM;
+		return -1;
+	}
+
+	/* Only allow one task to receive NOFREEZE privileges */
+	if (type == USERUI_MSG_NOFREEZE_ME && userui_pid != -1) {
+		*errp = -EBUSY;
+		return -1;
+	}
+
+	data = (int*)NLMSG_DATA(nlh);
+
+	switch (type) {
+		case USERUI_MSG_NOFREEZE_ME:
+			if ((*errp = userui_nl_set_nofreeze(nlh->nlmsg_pid)))
+				return -1;
+			break;
+		case USERUI_MSG_READY:
+			if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int))) {
+				*errp = -EINVAL;
+				return -1;
+			}
+			if ((*errp = userui_nl_ready(*data)))
+				return -1;
+			break;
+		case USERUI_MSG_ABORT:
+			request_abort_suspend();
+			break;
+		case USERUI_MSG_GET_STATE:
+			userui_send_message(USERUI_MSG_GET_STATE, &suspend_action,
+					sizeof(suspend_action));
+			break;
+		case USERUI_MSG_SET_STATE:
+			if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int))) {
+				*errp = -EINVAL;
+				return -1;
+			}
+			if ((*errp = userui_nl_set_state(*data)))
+				return -1;
+			break;
+		case USERUI_MSG_SET_PROGRESS_GRANULARITY:
+			if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(int))) {
+				*errp = -EINVAL;
+				return -1;
+			}
+			if ((*errp = userui_nl_set_progress_granularity(*data)))
+				return -1;
+			break;
+		case USERUI_MSG_SPACE:
+			wake_up_interruptible(&userui_wait_for_key);
+			break;
+		case USERUI_MSG_GET_DEBUGGING:
+			send_whether_debugging();
+			break;
+	}
+
+	return 0;
+}
+
+static int userui_user_rcv_skb(struct sk_buff *skb)
+{
+	int err;
+	struct nlmsghdr *nlh;
+
+	while (skb->len >= NLMSG_SPACE(0)) {
+		u32 rlen;
+
+		nlh = (struct nlmsghdr *) skb->data;
+		if (nlh->nlmsg_len < sizeof(*nlh) ||
+		    skb->len < nlh->nlmsg_len)
+			return 0;
+		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+		if (rlen > skb->len)
+			rlen = skb->len;
+		if (userui_user_rcv_msg(skb, nlh, &err) < 0) {
+			if (err == 0)
+				return -1;
+			netlink_ack(skb, nlh, err);
+		} else if (nlh->nlmsg_flags & NLM_F_ACK)
+			netlink_ack(skb, nlh, 0);
+		skb_pull(skb, rlen);
+	}
+
+	return 0;
+}
+
+static void userui_netlink_input(struct sock *sk, int len)
+{
+	do {
+		struct sk_buff *skb;
+		while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+			if (userui_user_rcv_skb(skb)) {
+				if (skb->len)
+					skb_queue_head(&sk->sk_receive_queue, skb);
+				else
+					kfree_skb(skb);
+				break;
+			}
+			kfree_skb(skb);
+		}
+	} while (userui_nl && userui_nl->sk_receive_queue.qlen);
+}
+
+static int open_userui_netlink(void)
+{
+	int i;
+
+	userui_sock_seq = 0x42c0ffee;
+	userui_nl = netlink_kernel_create(NETLINK_SUSPEND2_USERUI, userui_netlink_input);
+	if (!userui_nl) {
+		printk("suspend_userui: Failed to allocate netlink socket.\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < NUM_USERUI_SKBS; i++)
+		userui_skbs[i] = NULL;
+
+	next_free_userui_skb = -1;
+
+	userui_replenish_skbs();
+
+	return 0;
+}
+
+static void close_userui_netlink(void)
+{
+	int i;
+
+	if (userui_nl) {
+		sock_release(userui_nl->sk_socket);
+		userui_nl = NULL;
+	}
+
+	for (i = 0; i < NUM_USERUI_SKBS; i++)
+		if (userui_skbs[i])
+			kfree_skb(userui_skbs[i]);
+}
+
+static int launch_userui_program(void)
+{
+	int retval;
+	static char *envp[] = {
+			"HOME=/",
+			"TERM=linux",
+			"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+			NULL };
+	static char *argv[] = { userui_program, NULL };
+
+	retval = call_usermodehelper(userui_program, argv, envp, 0);
+
+	if (retval)
+		printk("suspend_userui: Failed to launch userui program: Error %d\n", retval);
+
+	return retval;
+}
+
+static int wait_for_userui_contact(void) 
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(&userui_wait_for_process, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	/* Wait 2 seconds for the userspace UI process to make contact */
+	if (userui_pid == -1 && !TEST_RESULT_STATE(SUSPEND_ABORTED))
+		interruptible_sleep_on_timeout(&userui_wait_for_process, 2*HZ);
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&userui_wait_for_process, &wait);
+
+	return 0;
+}
+
+void userui_redraw(void)
+{
+	if (userui_pid == -1)
+		return;
+
+	userui_send_message(USERUI_MSG_REDRAW, NULL, 0);
+}
+
+void userui_prepare_console(void)
+{
+	userui_pid = -1;
+
+	if (!*userui_program) {
+		printk("suspend_userui: userui_program not configured. suspend_userui disabled.\n");
+		return;
+	}
+
+	if (open_userui_netlink() < 0)
+		return;
+
+	if (launch_userui_program() < 0)
+		goto out_close;
+
+	if (wait_for_userui_contact() < 0)
+		goto out_close;
+
+	if (userui_pid == -1) {
+		printk("suspend_userui: Failed to contact userui process. suspend_userui disabled.\n");
+		goto out_close;
+	}
+
+	return;
+
+out_close:
+	close_userui_netlink();
+}
+
+void userui_cleanup_console(void)
+{
+	struct task_struct *t;
+
+	if (userui_pid == -1)
+		return;
+
+	userui_send_message(USERUI_MSG_CLEANUP, NULL, 0);
+
+	read_lock(&tasklist_lock);
+	if ((t = find_task_by_pid(userui_pid)))
+		t->flags &= ~PF_NOFREEZE;
+	read_unlock(&tasklist_lock);
+
+	close_userui_netlink();
+
+	userui_pid = -1;
+}
+
+static unsigned long userui_storage_needed(void)
+{
+	return sizeof(userui_program);
+}
+
+static int userui_save_config_info(char *buf)
+{
+	*((int *) buf) = progress_granularity;
+	memcpy(buf + sizeof(int), userui_program, sizeof(userui_program));
+	return sizeof(userui_program) + sizeof(int);
+}
+
+static void userui_load_config_info(char *buf, int size)
+{
+	/* Don't load the saved path if one has already been set */
+	if (userui_program[0])
+		return;
+
+	progress_granularity = *((int *) buf);
+	size -= sizeof(int);
+	
+	if (size > sizeof(userui_program))
+		size = sizeof(userui_program);
+
+	memcpy(userui_program, buf + sizeof(int), size);
+	userui_program[sizeof(userui_program)-1] = '\0';
+}
+
+static unsigned long userui_memory_needed(void)
+{
+	/* ball park figure of 128 pages */
+	return (128 * PAGE_SIZE);
+}
+
+unsigned long userui_update_progress(unsigned long value, unsigned long maximum,
+		const char *fmt, va_list args)
+{
+	static int last_step = -1;
+	struct userui_msg_params msg;
+	int bitshift = generic_fls(maximum) - 16;
+	int this_step;
+	unsigned long next_update;
+
+	if (userui_pid == -1)
+		return 0;
+
+	if ((!maximum) || (!progress_granularity))
+		return maximum;
+
+	if (value < 0)
+		value = 0;
+
+	if (value > maximum)
+		value = maximum;
+
+	/* Try to avoid math problems - we can't do 64 bit math here
+	 * (and shouldn't need it - anyone got screen resolution
+	 * of 65536 pixels or more?) */
+	if (bitshift > 0) {
+		unsigned long temp_maximum = maximum >> bitshift;
+		unsigned long temp_value = value >> bitshift;
+		this_step = (int) (temp_value * progress_granularity / temp_maximum);
+		next_update = (((this_step + 1) * temp_maximum / progress_granularity) + 1) << bitshift;
+	} else {
+		this_step = (int) (value * progress_granularity / maximum);
+		next_update = ((this_step + 1) * maximum / progress_granularity) + 1;
+	}
+
+	if (this_step == last_step)
+		return next_update;
+
+	memset(&msg, 0, sizeof(msg));
+
+	msg.a = this_step;
+	msg.b = progress_granularity;
+
+	if (fmt) {
+		vsnprintf(msg.text, sizeof(msg.text), fmt, args);
+		msg.text[sizeof(msg.text)-1] = '\0';
+	}
+
+	userui_send_message(USERUI_MSG_PROGRESS, &msg, sizeof(msg));
+	last_step = this_step;
+
+	return next_update;
+}
+
+/* __suspend_message.
+ *
+ * Description:	This function is intended to do the same job as printk, but
+ * 		without normally logging what is printed. The point is to be
+ * 		able to get debugging info on screen without filling the logs
+ * 		with "1/534. ^M 2/534^M. 3/534^M"
+ *
+ * 		It may be called from an interrupt context - can't sleep!
+ *
+ * Arguments:	int mask: The debugging section(s) this message belongs to.
+ * 		int level: The level of verbosity of this message.
+ * 		int restartline: Whether to output a \r or \n with this line
+ * 			(\n if we're logging all output).
+ * 		const char *fmt, ...: Message to be displayed a la printk.
+ */
+void __suspend_message(unsigned long section, unsigned long level,
+		int normally_logged,
+		const char *fmt, ...)
+{
+	struct userui_msg_params msg;
+
+	va_list args;
+
+	if ((level) && (level > console_loglevel))
+		return;
+
+	if (userui_pid == -1)
+		return;
+
+	memset(&msg, 0, sizeof(msg));
+
+	msg.a = section;
+	msg.b = level;
+	msg.c = normally_logged;
+
+	if (fmt) {
+		va_start(args, fmt);
+		vsnprintf(msg.text, sizeof(msg.text), fmt, args);
+		va_end(args);
+		msg.text[sizeof(msg.text)-1] = '\0';
+	}
+
+	userui_send_message(USERUI_MSG_MESSAGE, &msg, sizeof(msg));
+}
+
+static void wait_for_key_via_userui(void)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(&userui_wait_for_key, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	interruptible_sleep_on(&userui_wait_for_key);
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&userui_wait_for_key, &wait);
+}
+
+char suspend_wait_for_keypress(int timeout)
+{
+	int fd;
+	char key = '\0';
+	struct termios t, t_backup;
+
+	if (userui_pid != -1) {
+		wait_for_key_via_userui();
+		key = 32;
+		goto out;
+	}
+	
+	/* We should be guaranteed /dev/console exists after populate_rootfs() in
+	 * init/main.c
+	 */
+	if ((fd = sys_open("/dev/console", O_RDONLY, 0)) < 0)
+		goto out;
+
+	if (sys_ioctl(fd, TCGETS, (long)&t) < 0)
+		goto out_close;
+
+	memcpy(&t_backup, &t, sizeof(t));
+
+	t.c_lflag &= ~(ISIG|ICANON|ECHO);
+	t.c_cc[VMIN] = 0;
+	if (timeout)
+		t.c_cc[VTIME] = timeout*10;
+
+	if (sys_ioctl(fd, TCSETS, (long)&t) < 0)
+		goto out_restore;
+
+	while (1) {
+		if (sys_read(fd, &key, 1) <= 0) {
+			key = '\0';
+			break;
+		}
+		key = tolower(key);
+		if (test_suspend_state(SUSPEND_SANITY_CHECK_PROMPT)) {
+			if (key == 'c') {
+				set_suspend_state(SUSPEND_CONTINUE_REQ);
+				break;
+			} else if (key == ' ')
+				break;
+		} else
+			break;
+	}
+
+out_restore:
+	sys_ioctl(fd, TCSETS, (long)&t_backup);
+
+out_close:
+	sys_close(fd);
+out:
+	return key;
+}
+
+/* abort_suspend
+ *
+ * Description: Begin to abort a cycle. If this wasn't at the user's request
+ * 		(and we're displaying output), tell the user why and wait for
+ * 		them to acknowledge the message.
+ * Arguments:	A parameterised string (imagine this is printk) to display,
+ *	 	telling the user why we're aborting.
+ */
+
+void abort_suspend(const char *fmt, ...)
+{
+	va_list args;
+	int printed_len = 0;
+
+	if (!TEST_RESULT_STATE(SUSPEND_ABORTED)) {
+		if (!TEST_RESULT_STATE(SUSPEND_ABORT_REQUESTED)) {
+			va_start(args, fmt);
+			printed_len = vsnprintf(local_printf_buf, 
+					sizeof(local_printf_buf), fmt, args);
+			va_end(args);
+			if (userui_pid != -1)
+				printed_len = sprintf(local_printf_buf + printed_len,
+					" (Press SPACE to continue)");
+			suspend2_prepare_status(1, 1, local_printf_buf);
+
+			/* 
+			 * Make sure message seen - wait for shift to be
+			 * released if being pressed 
+			 */
+			if (userui_pid != -1)
+				suspend_wait_for_keypress(0);
+		}
+		/* Turn on aborting flag */
+		SET_RESULT_STATE(SUSPEND_ABORTED);
+	}
+}
+
+/* suspend2_prepare_status
+ * Description:	Prepare the 'nice display', drawing the header and version,
+ * 		along with the current action and perhaps also resetting the
+ * 		progress bar.
+ * Arguments:	int printalways: Whether to print the action when debugging
+ * 		is on.
+ * 		int clearbar: Whether to reset the progress bar.
+ * 		const char *fmt, ...: The action to be displayed.
+ */
+void suspend2_prepare_status(int printalways, int clearbar, const char *fmt, ...)
+{
+	va_list args;
+
+	if (fmt) {
+		va_start(args, fmt);
+		lastheader_message_len = vsnprintf(lastheader, 512, fmt, args);
+		va_end(args);
+	}
+
+	if (clearbar)
+		userui_update_progress(0, 1, NULL, NULL);
+
+	__suspend_message(0, SUSPEND_STATUS, 1, lastheader, NULL);
+
+	if (userui_pid == -1)
+		printk("%s\n", lastheader);
+}
+
+/* update_status
+ *
+ * Description: Update the progress bar and (if on) in-bar message.
+ * Arguments:	UL value, maximum: Current progress percentage (value/max).
+ * 		const char *fmt, ...: Message to be displayed in the middle
+ * 		of the progress bar.
+ * 		Note that a NULL message does not mean that any previous
+ * 		message is erased! For that, you need suspend2_prepare_status with
+ * 		clearbar on.
+ * Returns:	Unsigned long: The next value where status needs to be updated.
+ * 		This is to reduce unnecessary calls to update_status.
+ */
+unsigned long suspend2_update_status(unsigned long value, unsigned long maximum,
+		const char *fmt, ...)
+{
+	unsigned long next_update = maximum;
+	va_list args;
+
+	if (!maximum)
+		return maximum;
+
+	if (value < 0)
+		value = 0;
+
+	if (value > maximum)
+		value = maximum;
+
+	va_start(args, fmt);
+
+	next_update = userui_update_progress(value, maximum, fmt, args);
+
+	va_end(args);
+
+	return next_update;
+}
+
+static struct waiting_message
+{
+	int message;
+	struct waiting_message * next;
+} * waiting_messages = NULL;
+
+/* display_suspend_message
+ *
+ * Description:	Display a message as a result of the user pressing a key
+ * 		and the key being processed in an interrupt handler.
+ */
+
+int display_suspend_messages(void)
+{
+	int did_work = (waiting_messages != NULL);
+
+	while (waiting_messages) {
+		struct waiting_message * this_message = waiting_messages;
+
+		switch(waiting_messages->message) {
+			case 5:
+				suspend2_prepare_status(1, 1,
+					"--- ESCAPE PRESSED AGAIN :"
+					" TRYING HARDER TO ABORT ---");
+				break;
+			case 6:
+				suspend2_prepare_status(1, 1, "--- ESCAPE PRESSED :"
+						" ABORTING PROCESS ---");
+				break;
+		}
+
+		waiting_messages = this_message->next;
+		kfree(this_message);
+	}
+	return did_work;
+}
+
+/* suspend2_schedule_message
+ *
+ * Description:
+ * 
+ */
+
+void suspend2_schedule_message(int message_number)
+{
+	struct waiting_message * new_message =
+		kmalloc(sizeof(struct waiting_message), GFP_ATOMIC);
+
+	if (!new_message) {
+		printk("Argh. Unable to allocate memory for "
+				"scheduling the display of a message.\n");
+		return;
+	}
+
+	new_message->message = message_number;
+	new_message->next = waiting_messages;
+
+	waiting_messages = new_message;
+	return;
+}
+
+/* request_abort_suspend
+ *
+ * Description:	Handle the user requesting the cancellation of a suspend by
+ * 		pressing escape. Note that on a second press, we try a little
+ * 		harder, attempting to forcefully thaw processes. This shouldn't
+ * 		been needed, and may result in an oops (if we've overwritten
+ * 		memory), but has been useful on ocassion.
+ * Callers:	Invoked from a netlink packet from userspace when the user presses
+ *  	escape.
+ */
+void request_abort_suspend(void)
+{
+	if (test_suspend_state(SUSPEND_NOW_RESUMING) || (TEST_RESULT_STATE(SUSPEND_ABORT_REQUESTED)))
+		return;
+
+	if (TEST_RESULT_STATE(SUSPEND_ABORTED)) {
+		suspend2_schedule_message(5);
+		show_state();
+		thaw_processes(FREEZER_ALL_THREADS);
+	} else {
+		suspend2_schedule_message(6);
+		SET_RESULT_STATE(SUSPEND_ABORTED);
+		SET_RESULT_STATE(SUSPEND_ABORT_REQUESTED);
+	}
+}
+
+/* check_shift_keys
+ * 
+ * Description:	Potentially pause and wait for the user to tell us to continue.
+ * 		We normally only pause when @pause is set.
+ * Arguments:	int pause: Whether we normally pause.
+ * 		char * message: The message to display. Not parameterised
+ * 		 because it's normally a constant.
+ */
+
+void check_shift_keys(int pause, char * message)
+{
+#ifdef CONFIG_PM_DEBUG
+	int displayed_message = 0, last_key = 0;
+	
+	display_suspend_messages();
+	while (last_key != 32 &&
+		userui_pid != -1 &&
+		((TEST_ACTION_STATE(SUSPEND_PAUSE) && pause) || 
+		 (TEST_ACTION_STATE(SUSPEND_SINGLESTEP)))) {
+		if (!displayed_message) {
+			suspend2_prepare_status(1, 0, 
+			   "%s Press SPACE to continue.%s",
+			   message ? message : "",
+			   (TEST_ACTION_STATE(SUSPEND_SINGLESTEP)) ? 
+			   " Single step on." : "");
+			displayed_message = 1;
+		}
+		last_key = suspend_wait_for_keypress(0);
+		display_suspend_messages();
+	}
+#else
+	display_suspend_messages();
+#endif
+	schedule();
+}
+
+extern asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, 
+		unsigned long arg);
+
+/* suspend2_prepare_console
+ *
+ * Description:	Prepare a console for use, save current settings.
+ * Returns:	Boolean: Whether an error occured. Errors aren't
+ * 		treated as fatal, but a warning is printed.
+ */
+int suspend2_prepare_console(void)
+{
+	orig_loglevel = console_loglevel;
+	orig_default_message_loglevel = default_message_loglevel;
+	orig_kmsg = kmsg_redirect;
+	kmsg_redirect = fg_console + 1;
+	default_message_loglevel = 1;
+	console_loglevel = suspend_default_console_level;
+	userui_prepare_console();
+
+	return 0;
+}
+
+/* suspend2_restore_console
+ *
+ * Description: Restore the settings we saved above.
+ */
+
+void suspend2_cleanup_console(void)
+{
+	userui_cleanup_console();
+	suspend_default_console_level = console_loglevel;
+	console_loglevel = orig_loglevel;
+	kmsg_redirect = orig_kmsg;
+	default_message_loglevel = orig_default_message_loglevel;
+}
+
+/* suspend_early_boot_message()
+ * Description:	Handle errors early in the process of booting.
+ * 		The user may press C to continue booting, perhaps
+ * 		invalidating the image,  or space to reboot. 
+ * 		This works from either the serial console or normally 
+ * 		attached keyboard.
+ *
+ * 		Note that we come in here from init, while the kernel is
+ * 		locked. If we want to get events from the serial console,
+ * 		we need to temporarily unlock the kernel.
+ *
+ * 		suspend_early_boot_message may also be called post-boot.
+ * 		In this case, it simply printks the message and returns.
+ *
+ * Arguments:	int	Whether we are able to erase the image.
+ * 		int	default_answer. What to do when we timeout. This
+ * 			will normally be continue, but the user might
+ * 			provide command line options (__setup) to override
+ * 			particular cases.
+ * 		Char *. Pointer to a string explaining why we're moaning.
+ */
+
+#define say(message, a...) printk(KERN_EMERG message, ##a)
+#define message_timeout 25 /* message_timeout * 10 must fit in 8 bits */
+
+int suspend_early_boot_message(int can_erase_image, int default_answer, char *warning_reason, ...)
+{
+	unsigned long orig_state = get_suspend_state(), continue_req = 0;
+	va_list args;
+	int printed_len;
+
+	if (warning_reason) {
+		va_start(args, warning_reason);
+		printed_len = vsnprintf(local_printf_buf, 
+				sizeof(local_printf_buf), 
+				warning_reason,
+				args);
+		va_end(args);
+	}
+
+	if (!test_suspend_state(SUSPEND_BOOT_TIME)) {
+		printk(name_suspend "%s", local_printf_buf);
+		return default_answer;
+	}
+
+	/* We might be called directly from do_mounts_initrd if the
+	 * user fails to set up their initrd properly. We need to
+	 * enable the keyboard handler by setting the running flag */
+	set_suspend_state(SUSPEND_RUNNING);
+
+#if defined(CONFIG_VT) || defined(CONFIG_SERIAL_CONSOLE)
+	console_loglevel = 7;
+
+	say("=== Software Suspend ===\n\n");
+	if (warning_reason) {
+		say("BIG FAT WARNING!! %s\n\n", local_printf_buf);
+		if (can_erase_image) {
+			say("If you want to use the current suspend image, reboot and try\n");
+			say("again with the same kernel that you suspended from. If you want\n");
+			say("to forget that image, continue and the image will be erased.\n");
+		} else {
+			say("If you continue booting, note that any image WILL NOT BE REMOVED.\n");
+			say("Suspend is unable to do so because the appropriate modules aren't\n");
+			say("loaded. You should manually remove the image to avoid any\n");
+			say("possibility of corrupting your filesystem(s) later.\n");
+		}
+		say("Press SPACE to reboot or C to continue booting with this kernel\n\n");
+		say("Default action if you don't select one in %d seconds is: %s.\n",
+			message_timeout,
+			default_answer == SUSPEND_CONTINUE_REQ ?
+			"continue booting" : "reboot");
+	} else {
+		say("BIG FAT WARNING!!\n\n");
+		say("You have tried to resume from this image before.\n");
+		say("If it failed once, may well fail again.\n");
+		say("Would you like to remove the image and boot normally?\n");
+		say("This will be equivalent to entering noresume2 on the\n");
+		say("kernel command line.\n\n");
+		say("Press SPACE to remove the image or C to continue resuming.\n\n");
+		say("Default action if you don't select one in %d seconds is: %s.\n",
+			message_timeout,
+			!!default_answer ?
+			"continue resuming" : "remove the image");
+	}
+	
+	set_suspend_state(SUSPEND_SANITY_CHECK_PROMPT);
+	clear_suspend_state(SUSPEND_CONTINUE_REQ);
+
+	if (suspend_wait_for_keypress(message_timeout) == 0) /* We timed out */
+		continue_req = !!default_answer;
+	else
+		continue_req = test_suspend_state(SUSPEND_CONTINUE_REQ);
+
+	if ((warning_reason) && (!continue_req))
+		machine_restart(NULL);
+	
+	restore_suspend_state(orig_state);
+	if (continue_req)
+		set_suspend_state(SUSPEND_CONTINUE_REQ);
+
+#endif // CONFIG_VT or CONFIG_SERIAL_CONSOLE
+	return -EPERM;
+}
+#undef say
+
+/*
+ * User interface specific /proc/suspend entries.
+ */
+
+static struct suspend_proc_data proc_params[] = {
+#ifdef CONFIG_PROC_FS
+	{ .filename			= "default_console_level",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_INTEGER,
+	  .data = {
+		  .integer = {
+			  .variable	= &suspend_default_console_level,
+			  .minimum	= 0,
+#ifdef CONFIG_PM_DEBUG
+			  .maximum	= 7,
+#else
+			  .maximum	= 1,
+#endif
+
+		  }
+	  }
+	},
+
+	{ .filename			= "enable_escape",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_CAN_CANCEL,
+		  }
+	  }
+	},
+
+#ifdef CONFIG_PM_DEBUG
+	{ .filename			= "debug_sections",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_UL,
+	  .data = {
+		  .ul = {
+			  .variable	= &suspend_debug_state,
+			  .minimum	= 0,
+			  .maximum	= 2 << 30,
+		  }
+	  }
+	},
+
+	{ .filename			= "log_everything",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_LOGALL,
+		  }
+	  }
+	},
+	  
+	{ .filename			= "pause_between_steps",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_PAUSE,
+		  }
+	  }
+	},
+#endif
+	{ .filename			= "disable_userui_support",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_INTEGER,
+	  .data = {
+		.integer = {
+			.variable	= &userui_ops.disabled,
+			.minimum	= 0,
+			.maximum	= 1,
+		}
+	  }
+	},
+	{ .filename			= "userui_progress_granularity",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_INTEGER,
+	  .data = {
+		.integer = {
+			.variable	= &progress_granularity,
+			.minimum	= 1,
+			.maximum	= 2048,
+		}
+	  }
+	},
+	{ .filename			= "userui_program",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_STRING,
+	  .data = {
+		.string = {
+			.variable	= userui_program,
+			.max_length	= 255,
+		}
+	  }
+	}
+#endif
+};
+
+static struct suspend_plugin_ops userui_ops = {
+	.type				= MISC_PLUGIN,
+	.name				= "Userspace UI Support",
+	.module				= THIS_MODULE,
+	.storage_needed			= userui_storage_needed,
+	.save_config_info		= userui_save_config_info,
+	.load_config_info		= userui_load_config_info,
+	.memory_needed			= userui_memory_needed,
+};
+
+/* suspend_console_proc_init
+ * Description: Boot time initialisation for user interface.
+ */
+static __init int suspend_console_proc_init(void)
+{
+	int result, i, numfiles = sizeof(proc_params) / sizeof(struct suspend_proc_data);
+
+	if (!(result = suspend_register_plugin(&userui_ops)))
+		for (i=0; i< numfiles; i++)
+			suspend_register_procfile(&proc_params[i]);
+
+	userui_nl = NULL;
+	userui_program[0] = '\0';
+
+	return result;
+}
+
+late_initcall(suspend_console_proc_init);
diff -ruNp 620-userui-header.patch-old/kernel/power/suspend2_core/ui.h 620-userui-header.patch-new/kernel/power/suspend2_core/ui.h
--- 620-userui-header.patch-old/kernel/power/suspend2_core/ui.h	1970-01-01 10:00:00.000000000 +1000
+++ 620-userui-header.patch-new/kernel/power/suspend2_core/ui.h	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,20 @@
+/*
+ *
+ */
+
+extern int suspend2_prepare_console(void);
+extern void suspend2_cleanup_console(void);
+
+extern void check_shift_keys(int pause, char * message);
+
+extern void suspend2_prepare_status(int printalways, int clearbar, const char *fmt, ...);
+extern void check_shift_keys(int pause, char * message);
+extern unsigned long suspend2_update_status(unsigned long value, unsigned long maximum,
+		const char *fmt, ...);
+
+extern void request_abort_suspend(void);
+extern void abort_suspend(const char *fmt, ...);
+
+extern void suspend2_schedule_message (int message_number);
+
+extern void userui_redraw(void);
diff -ruNp 620-userui-header.patch-old/kernel/power/suspend2_core/userui.h 620-userui-header.patch-new/kernel/power/suspend2_core/userui.h
--- 620-userui-header.patch-old/kernel/power/suspend2_core/userui.h	1970-01-01 10:00:00.000000000 +1000
+++ 620-userui-header.patch-new/kernel/power/suspend2_core/userui.h	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,36 @@
+#ifndef _SUSPEND_USERUI_H_
+#define _SUSPEND_USERUI_H_
+
+#define SUSPEND_USERUI_INTERFACE_VERSION 5
+
+enum {
+	USERUI_MSG_BASE = 0x10,
+
+	/* Userspace -> Kernel */
+	USERUI_MSG_READY = 0x10,
+	USERUI_MSG_ABORT = 0x11,
+	USERUI_MSG_SET_STATE = 0x12,
+	USERUI_MSG_GET_STATE = 0x13,
+	USERUI_MSG_NOFREEZE_ME = 0x16,
+	USERUI_MSG_SET_PROGRESS_GRANULARITY = 0x17,
+	USERUI_MSG_SPACE = 0x18,
+	USERUI_MSG_GET_DEBUGGING = 0x19,
+
+	/* Kernel -> Userspace */
+	USERUI_MSG_MESSAGE = 0x21,
+	USERUI_MSG_PROGRESS = 0x22,
+	USERUI_MSG_CLEANUP = 0x24,
+	USERUI_MSG_REDRAW = 0x25,
+	USERUI_MSG_KEYPRESS = 0x26,
+	USERUI_MSG_NOFREEZE_ACK = 0x27,
+	USERUI_MSG_IS_DEBUGGING = 0x28,
+
+	USERUI_MSG_MAX,
+};
+
+struct userui_msg_params {
+	unsigned long a, b, c, d;
+	char text[80];
+};
+
+#endif /* _SUSPEND_USERUI_H_ */


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch
  2005-07-06  2:20 ` [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch Nigel Cunningham
@ 2005-07-06  3:34   ` Zwane Mwaikambo
  2005-07-06  3:43     ` Nigel Cunningham
  2005-07-06  8:08   ` Pavel Machek
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 187+ messages in thread
From: Zwane Mwaikambo @ 2005-07-06  3:34 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

On Wed, 6 Jul 2005, Nigel Cunningham wrote:

> 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
> --- 353-disable-highmem-tlb-flush-for-copyback.patch-old/mm/highmem.c	2005-06-20 11:47:32.000000000 +1000
> +++ 353-disable-highmem-tlb-flush-for-copyback.patch-new/mm/highmem.c	2005-07-04 23:14:20.000000000 +1000
> @@ -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)

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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [11/48] Suspend2 2.1.9.8 for 2.6.12: 401-e820-table-support.patch
  2005-07-06  2:20 ` [PATCH] [11/48] Suspend2 2.1.9.8 for 2.6.12: 401-e820-table-support.patch Nigel Cunningham
@ 2005-07-06  3:35   ` Zwane Mwaikambo
  2005-07-06  3:44     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Zwane Mwaikambo @ 2005-07-06  3:35 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux Kernel, shaohua.li

On Wed, 6 Jul 2005, Nigel Cunningham wrote:

> 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
> --- 402-mtrr-remove-sysdev.patch-old/arch/i386/kernel/cpu/mtrr/main.c	2005-06-20 11:46:42.000000000 +1000
> +++ 402-mtrr-remove-sysdev.patch-new/arch/i386/kernel/cpu/mtrr/main.c	2005-07-04 23:14:19.000000000 +1000
> @@ -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;
>  }

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

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [24/48] Suspend2 2.1.9.8 for 2.6.12: 601-kernel_power_power-header.patch
  2005-07-06  2:20 ` [PATCH] [24/48] Suspend2 2.1.9.8 for 2.6.12: 601-kernel_power_power-header.patch Nigel Cunningham
@ 2005-07-06  3:42   ` Zwane Mwaikambo
  2005-07-06  3:45     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Zwane Mwaikambo @ 2005-07-06  3:42 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

On Wed, 6 Jul 2005, Nigel Cunningham wrote:

> diff -ruNp 602-smp.patch-old/kernel/power/suspend2_core/smp.c 602-smp.patch-new/kernel/power/suspend2_core/smp.c
> --- 602-smp.patch-old/kernel/power/suspend2_core/smp.c	1970-01-01 10:00:00.000000000 +1000
> +++ 602-smp.patch-new/kernel/power/suspend2_core/smp.c	2005-07-04 23:14:19.000000000 +1000
> @@ -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);
> +}

Do we really need to wrap these?


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch
  2005-07-06  3:34   ` Zwane Mwaikambo
@ 2005-07-06  3:43     ` Nigel Cunningham
  2005-07-06 13:27       ` Zwane Mwaikambo
  0 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  3:43 UTC (permalink / raw)
  To: Zwane Mwaikambo; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Wed, 2005-07-06 at 13:34, Zwane Mwaikambo wrote:
> On Wed, 6 Jul 2005, Nigel Cunningham wrote:
> 
> > 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
> > --- 353-disable-highmem-tlb-flush-for-copyback.patch-old/mm/highmem.c	2005-06-20 11:47:32.000000000 +1000
> > +++ 353-disable-highmem-tlb-flush-for-copyback.patch-new/mm/highmem.c	2005-07-04 23:14:20.000000000 +1000
> > @@ -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)
> 
> 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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [17/48] Suspend2 2.1.9.8 for 2.6.12: 500-version-specific-i386.patch
  2005-07-06  2:20 ` [PATCH] [17/48] Suspend2 2.1.9.8 for 2.6.12: 500-version-specific-i386.patch Nigel Cunningham
@ 2005-07-06  3:43   ` YOSHIFUJI Hideaki / 吉藤英明
  0 siblings, 0 replies; 187+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2005-07-06  3:43 UTC (permalink / raw)
  To: nigel; +Cc: linux-kernel, yoshfuji

In article <11206164413380@foobar.com> (at Wed, 6 Jul 2005 12:20:41 +1000), Nigel Cunningham <nigel@suspend2.net> says:

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

You should remove ";".

>  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);
>  

ditto

--yoshfuji

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [11/48] Suspend2 2.1.9.8 for 2.6.12: 401-e820-table-support.patch
  2005-07-06  3:35   ` Zwane Mwaikambo
@ 2005-07-06  3:44     ` Nigel Cunningham
  2005-07-06  8:04       ` Pavel Machek
  2005-07-06 13:29       ` Zwane Mwaikambo
  0 siblings, 2 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  3:44 UTC (permalink / raw)
  To: Zwane Mwaikambo; +Cc: Nigel Cunningham, Linux Kernel Mailing List, shaohua.li

Hi.

On Wed, 2005-07-06 at 13:35, Zwane Mwaikambo wrote:
> On Wed, 6 Jul 2005, Nigel Cunningham wrote:
> 
> > 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
> > --- 402-mtrr-remove-sysdev.patch-old/arch/i386/kernel/cpu/mtrr/main.c	2005-06-20 11:46:42.000000000 +1000
> > +++ 402-mtrr-remove-sysdev.patch-new/arch/i386/kernel/cpu/mtrr/main.c	2005-07-04 23:14:19.000000000 +1000
> > @@ -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;
> >  }
> 
> 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

-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [24/48] Suspend2 2.1.9.8 for 2.6.12: 601-kernel_power_power-header.patch
  2005-07-06  3:42   ` Zwane Mwaikambo
@ 2005-07-06  3:45     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  3:45 UTC (permalink / raw)
  To: Zwane Mwaikambo; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Wed, 2005-07-06 at 13:42, Zwane Mwaikambo wrote:
> On Wed, 6 Jul 2005, Nigel Cunningham wrote:
> 
> > diff -ruNp 602-smp.patch-old/kernel/power/suspend2_core/smp.c 602-smp.patch-new/kernel/power/suspend2_core/smp.c
> > --- 602-smp.patch-old/kernel/power/suspend2_core/smp.c	1970-01-01 10:00:00.000000000 +1000
> > +++ 602-smp.patch-new/kernel/power/suspend2_core/smp.c	2005-07-04 23:14:19.000000000 +1000
> > @@ -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);
> > +}
> 
> 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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch
  2005-07-06  2:20 ` [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch Nigel Cunningham
@ 2005-07-06  3:49   ` Nigel Cunningham
  2005-07-06  5:30     ` hugang
  2005-07-06  3:53   ` Zwane Mwaikambo
  2005-07-06  5:58   ` Pekka Enberg
  2 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  3:49 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux Kernel Mailing List

Hi.

This patch came from Hu Gang.

Regards,

Nigel

On Wed, 2005-07-06 at 12:20, Nigel Cunningham wrote:
> 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
> --- 520-version-specific-x86_64.patch-old/arch/x86_64/kernel/asm-offsets.c	2005-06-20 11:46:49.000000000 +1000
> +++ 520-version-specific-x86_64.patch-new/arch/x86_64/kernel/asm-offsets.c	2005-07-04 23:14:19.000000000 +1000
> @@ -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
> --- 520-version-specific-x86_64.patch-old/arch/x86_64/kernel/Makefile	2005-06-20 11:46:49.000000000 +1000
> +++ 520-version-specific-x86_64.patch-new/arch/x86_64/kernel/Makefile	2005-07-04 23:14:19.000000000 +1000
> @@ -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
> --- 520-version-specific-x86_64.patch-old/arch/x86_64/kernel/suspend.c	2004-11-03 21:53:44.000000000 +1100
> +++ 520-version-specific-x86_64.patch-new/arch/x86_64/kernel/suspend.c	2005-07-04 23:14:19.000000000 +1000
> @@ -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
> --- 520-version-specific-x86_64.patch-old/arch/x86_64/mm/init.c	2005-06-20 11:46:49.000000000 +1000
> +++ 520-version-specific-x86_64.patch-new/arch/x86_64/mm/init.c	2005-07-04 23:14:19.000000000 +1000
> @@ -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
> --- 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend2.h	1970-01-01 10:00:00.000000000 +1000
> +++ 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend2.h	2005-07-05 23:56:15.000000000 +1000
> @@ -0,0 +1,432 @@
> + /*
> +  * Copyright 2005 Nigel Cunningham <nigel@suspend2.net>
> +  * Based on code
> +  * Copyright 2001-2002 Pavel Machek <pavel@suse.cz>
> +  * Based on code
> +  * Copyright 2001 Patrick Mochel <mochel@osdl.org>
> +  */
> +#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
> --- 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend.h	2005-06-20 11:47:28.000000000 +1000
> +++ 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend.h	2005-07-04 23:14:19.000000000 +1000
> @@ -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 majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch
  2005-07-06  2:20 ` [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch Nigel Cunningham
  2005-07-06  3:49   ` Nigel Cunningham
@ 2005-07-06  3:53   ` Zwane Mwaikambo
  2005-07-06  3:59     ` Nigel Cunningham
  2005-07-06  5:58   ` Pekka Enberg
  2 siblings, 1 reply; 187+ messages in thread
From: Zwane Mwaikambo @ 2005-07-06  3:53 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

On Wed, 6 Jul 2005, Nigel Cunningham wrote:

> +	/*
> +	 * eflags
> +	 */
> +	asm volatile ("pushfl ; popl (%0)" : "=m" (suspend2_saved_context.eflags));

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

> +
> +	/*
> +	 * 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?

> + * 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");

Shouldn't that be KERNEL_DS?

> +	asm volatile ("pushl %0 ; popfl" :: "m" (suspend2_saved_context.eflags));

pushq/popfq?

> +	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?

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch
  2005-07-06  3:53   ` Zwane Mwaikambo
@ 2005-07-06  3:59     ` Nigel Cunningham
  2005-07-06 13:40       ` Zwane Mwaikambo
  0 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  3:59 UTC (permalink / raw)
  To: Zwane Mwaikambo; +Cc: Linux Kernel Mailing List

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

On Wed, 2005-07-06 at 13:53, Zwane Mwaikambo wrote:
> On Wed, 6 Jul 2005, Nigel Cunningham wrote:
> 
> > +	/*
> > +	 * eflags
> > +	 */
> > +	asm volatile ("pushfl ; popl (%0)" : "=m" (suspend2_saved_context.eflags));
> 
> To be future proof you probably want to do pushfq/popq
> 
> > +
> > +	/*
> > +	 * 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?
> 
> > + * 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");
> 
> Shouldn't that be KERNEL_DS?
> 
> > +	asm volatile ("pushl %0 ; popfl" :: "m" (suspend2_saved_context.eflags));
> 
> pushq/popfq?
> 
> > +	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?
> 
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch
  2005-07-06  3:49   ` Nigel Cunningham
@ 2005-07-06  5:30     ` hugang
  2005-07-06  6:03       ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: hugang @ 2005-07-06  5:30 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Nigel Cunningham, Linux Kernel Mailing List

On Wed, Jul 06, 2005 at 01:49:22PM +1000, Nigel Cunningham wrote:
> Hi.
> 
> This patch came from Hu Gang.
> 
> Regards,
> 
> Nigel

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

-- 
Hu Gang       .-.
              /v\
             // \\ 
Linux User  /(   )\  [204016]
GPG Key ID   ^^-^^   http://soulinfo.com/~hugang/hugang.asc

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch
  2005-07-06  2:20 ` [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch Nigel Cunningham
  2005-07-06  3:49   ` Nigel Cunningham
  2005-07-06  3:53   ` Zwane Mwaikambo
@ 2005-07-06  5:58   ` Pekka Enberg
  2005-07-06  6:21     ` Nigel Cunningham
  2005-07-06 10:04     ` Nigel Cunningham
  2 siblings, 2 replies; 187+ messages in thread
From: Pekka Enberg @ 2005-07-06  5:58 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> 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
> --- 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000
> +++ 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000
> @@ -0,0 +1,432 @@
> +#undef inline
> +#define inline __inline__ __attribute__((always_inline))

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

> +
> +/* 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

Please drop the #ifdef

> +       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).

> +
> +#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.

> +#endif
> +
> +#ifndef CONFIG_SMP
> +#undef cpu_clear
> +#define cpu_clear(a, b) do { } while(0)

Same here.

> +#endif
> +
> +extern struct suspend2_saved_context suspend2_saved_context;   /* temporary storage */

Move comment up.

> +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.

> +/*
> + * 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.

> 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
> --- 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend.h  2005-06-20 11:47:28.000000000 +1000
> +++ 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend.h  2005-07-04 23:14:19.000000000 +1000
> @@ -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.

> 
>  #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 majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch
  2005-07-06  5:30     ` hugang
@ 2005-07-06  6:03       ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  6:03 UTC (permalink / raw)
  To: hugang; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Ah my bad.

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

Nigel

On Wed, 2005-07-06 at 15:30, hugang@soulinfo.com wrote:
> On Wed, Jul 06, 2005 at 01:49:22PM +1000, Nigel Cunningham wrote:
> > Hi.
> > 
> > This patch came from Hu Gang.
> > 
> > Regards,
> > 
> > Nigel
> 
> :), Maybe you are wrong, I just do a ppc port not x86_64.
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [43/48] Suspend2 2.1.9.8 for 2.6.12: 619-userspace-nofreeze.patch
  2005-07-06  2:20 ` [PATCH] [43/48] Suspend2 2.1.9.8 for 2.6.12: 619-userspace-nofreeze.patch Nigel Cunningham
@ 2005-07-06  6:18   ` Pekka Enberg
  2005-07-10 23:15   ` Christoph Hellwig
  1 sibling, 0 replies; 187+ messages in thread
From: Pekka Enberg @ 2005-07-06  6:18 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> diff -ruNp 620-userui-header.patch-old/kernel/power/suspend2_core/ui.c 620-userui-header.patch-new/kernel/power/suspend2_core/ui.c
> --- 620-userui-header.patch-old/kernel/power/suspend2_core/ui.c 1970-01-01 10:00:00.000000000 +1000

Is a directory this deep really necessary? Please consider putting
this under kernel/power/.

> +++ 620-userui-header.patch-new/kernel/power/suspend2_core/ui.c 2005-07-05 23:48:59.000000000 +1000
> @@ -0,0 +1,1186 @@
> +/*
> + * kernel/power/ui.c
> + *
> + * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
> + * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
> + * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr>
> + * Copyright (C) 2002-2005 Nigel Cunningham <nigel@suspend2.net>
> + *
> + * This file is released under the GPLv2.
> + *
> + * Routines for Software Suspend's user interface.
> + *
> + * The user interface code talks to a userspace program via a
> + * netlink socket.
> + *
> + * The kernel side:
> + * - starts the userui program;
> + * - sends text messages and progress bar status;
> + *
> + * The user space side:
> + * - passes messages regarding user requests (abort, toggle reboot etc)
> + *
> + */
> +#define SUSPEND_CONSOLE_C
> +
> +#include "../power.h"

Please either move this file under kernel/power/ or move the header to
include/linux/.

> +void s2_userui_message(unsigned long section, unsigned long level,
> +               int normally_logged,
> +               const char *fmt, va_list args);
> +unsigned long userui_update_progress(unsigned long value, unsigned long maximum,
> +               const char *fmt, va_list args);
> +void userui_prepare_console(void);
> +void userui_cleanup_console(void);

Shouldn't these be extern and in a header file?

> +static int userui_nl_set_state(int n)
> +{
> +       /* Only let them change certain settings */
> +       static const int suspend_action_mask =
> +               (1 << SUSPEND_REBOOT) | (1 << SUSPEND_PAUSE) | (1 << SUSPEND_SLOW) |
> +               (1 << SUSPEND_LOGALL) | (1 << SUSPEND_SINGLESTEP) |
> +               (1 << SUSPEND_PAUSE_NEAR_PAGESET_END);
> +
> +       suspend_action = (suspend_action & (~suspend_action_mask)) |
> +               (n & suspend_action_mask);
> +
> +       return 0;

Always returns zero so drop the return value.

> +}
> +
> +static int userui_nl_set_progress_granularity(int n)
> +{
> +       if (n < 1) n = 1;
> +       progress_granularity = n;
> +       return 0;

Same here.

> +}
> +
> +static int userui_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
> +{
> +       int type;
> +       int *data;
> +
> +       *errp = 0;
> +
> +       if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
> +               return 0;
> +
> +       type = nlh->nlmsg_type;
> +
> +       /* A control message: ignore them */
> +       if (type < USERUI_MSG_BASE)
> +               return 0;
> +
> +       /* Unknown message: reply with EINVAL */
> +       if (type >= USERUI_MSG_MAX) {
> +               *errp = -EINVAL;
> +               return -1;

Just return the error value and errp can go away.

> +static unsigned long userui_memory_needed(void)
> +{
> +       /* ball park figure of 128 pages */
> +       return (128 * PAGE_SIZE);

Where does this magic 128 come from?

> +}
> +
> +unsigned long userui_update_progress(unsigned long value, unsigned long maximum,
> +               const char *fmt, va_list args)
> +{
> +       static int last_step = -1;
> +       struct userui_msg_params msg;
> +       int bitshift = generic_fls(maximum) - 16;

What's this magic 16?

> +char suspend_wait_for_keypress(int timeout)
> +{
> +       int fd;
> +       char key = '\0';
> +       struct termios t, t_backup;
> +
> +       if (userui_pid != -1) {
> +               wait_for_key_via_userui();
> +               key = 32;

What's this magic 32?

> +/* abort_suspend
> + *
> + * Description: Begin to abort a cycle. If this wasn't at the user's request
> + *             (and we're displaying output), tell the user why and wait for
> + *             them to acknowledge the message.
> + * Arguments:  A parameterised string (imagine this is printk) to display,
> + *             telling the user why we're aborting.
> + */

Please use proper kerneldoc format instead of inventing your own.

> +void suspend2_schedule_message(int message_number)
> +{
> +       struct waiting_message * new_message =
> +               kmalloc(sizeof(struct waiting_message), GFP_ATOMIC);
> +
> +       if (!new_message) {
> +               printk("Argh. Unable to allocate memory for "
> +                               "scheduling the display of a message.\n");

KERN_* constants please.

> +extern asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd,
> +               unsigned long arg);

Looks as if you're doing quite a bit of sys_* calls in the kernel.
Could this stuff be pushed out to userspace by any chance?

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch
  2005-07-06  5:58   ` Pekka Enberg
@ 2005-07-06  6:21     ` Nigel Cunningham
  2005-07-06 10:04     ` Nigel Cunningham
  1 sibling, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  6:21 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Nigel Cunningham, Linux Kernel Mailing List, Pekka Enberg

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

On Wed, 2005-07-06 at 15:58, Pekka Enberg wrote:
> On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> > 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
> > --- 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000
> > +++ 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000
> > @@ -0,0 +1,432 @@
> > +#undef inline
> > +#define inline __inline__ __attribute__((always_inline))
> 
> Please drop this macro. <linux/compiler.h> takes care of it already.
> 
> > +
> > +/* 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
> 
> Please drop the #ifdef
> 
> > +       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).
> 
> > +
> > +#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.
> 
> > +#endif
> > +
> > +#ifndef CONFIG_SMP
> > +#undef cpu_clear
> > +#define cpu_clear(a, b) do { } while(0)
> 
> Same here.
> 
> > +#endif
> > +
> > +extern struct suspend2_saved_context suspend2_saved_context;   /* temporary storage */
> 
> Move comment up.
> 
> > +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.
> 
> > +/*
> > + * 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.
> 
> > 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
> > --- 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend.h  2005-06-20 11:47:28.000000000 +1000
> > +++ 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend.h  2005-07-04 23:14:19.000000000 +1000
> > @@ -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.
> 
> > 
> >  #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 majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> >
> 
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [46/48] Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch
  2005-07-06  2:20 ` [PATCH] [46/48] Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch Nigel Cunningham
@ 2005-07-06  6:33   ` Pekka Enberg
  2005-07-07 12:40     ` Nigel Cunningham
  2005-07-07 13:32   ` [PATCH] [46/48] " Pekka Enberg
  1 sibling, 1 reply; 187+ messages in thread
From: Pekka Enberg @ 2005-07-06  6:33 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> diff -ruNp 623-generic-block-io.patch-old/kernel/power/suspend_block_io.c 623-generic-block-io.patch-new/kernel/power/suspend_block_io.c
> --- 623-generic-block-io.patch-old/kernel/power/suspend_block_io.c      1970-01-01 10:00:00.000000000 +1000
> +++ 623-generic-block-io.patch-new/kernel/power/suspend_block_io.c      2005-07-05 23:48:59.000000000 +1000
> @@ -0,0 +1,817 @@
> +#include "suspend2_core/suspend.h"
> +#include "suspend2_core/proc.h"
> +#include "suspend2_core/plugins.h"
> +#include "suspend2_core/utility.h"
> +#include "suspend2_core/prepare_image.h"

You've got circular dependencies. kernel/power/suspend2_core depends
on kernel/power and vice versa. Please just consider putting them all
in kernel/power/

> +/* Bits in struct io_info->flags */
> +#define IO_WRITING 1
> +#define IO_RESTORE_PAGE_PROT 2
> +#define IO_AWAITING_READ 3
> +#define IO_AWAITING_WRITE 4
> +#define IO_AWAITING_SUBMIT 5
> +#define IO_AWAITING_CLEANUP 6
> +#define IO_HANDLE_PAGE_PROT 7

Please use enums instead.

> +
> +#define MAX_OUTSTANDING_IO 1024
> +
> +/*
> + * ---------------------------------------------------------------
> + *
> + *     IO in progress information storage and helpers
> + *
> + * ---------------------------------------------------------------
> + */

Could we please drop the above banner. Hurts my eyes...

> +
> +struct io_info {
> +       struct bio * sys_struct;
> +       long block[PAGE_SIZE/512];

You're hardcoding sector size here, no?

> +       struct page * buffer_page;
> +       struct page * data_page;
> +       unsigned long flags;
> +       struct block_device * dev;
> +       struct list_head list;
> +       int readahead_index;
> +       struct work_struct work;
> +};
> +
> +/* Locks separated to allow better SMP support.
> + * An io_struct moves through the lists as follows.
> + * free -> submit_batch -> busy -> ready_for_cleanup -> free
> + */
> +static LIST_HEAD(ioinfo_free);
> +static spinlock_t ioinfo_free_lock = SPIN_LOCK_UNLOCKED;

Please use DEFINE_SPINLOCK instead. It is preferred as some automatic
lock checkers need it.

> +#define BITS_PER_UL (8 * sizeof(unsigned long))
> +static volatile unsigned long suspend_readahead_flags[(MAX_READAHEAD + BITS_PER_UL - 1) / BITS_PER_UL];

<asm/types.h> has BITS_PER_LONG. Use it.

> +static int suspend_end_bio(struct bio * bio, unsigned int num, int err)
> +{
> +       struct io_info *io_info = (struct io_info *) bio->bi_private;

Redundant cast.

> +static void suspend_wait_on_readahead(int readahead_index)
> +{
> +       int index = readahead_index/(8 * sizeof(unsigned long));
> +       int bit = readahead_index - index * 8 * sizeof(unsigned long);

Use BITS_PER_LONG here.

> +
> +       /* read_ahead_index is the one we want to return */
> +       while (!test_bit(bit, &suspend_readahead_flags[index]))
> +               do_bio_wait(6);
> +}
> +
> +/*
> + * readahead_done
> + *
> + * Returns whether the readahead requested is ready.
> + */
> +
> +static int suspend_readahead_ready(int readahead_index)
> +{
> +       int index = readahead_index/(8 * sizeof(unsigned long));
> +       int bit = readahead_index - (index * 8 * sizeof(unsigned long));

Ditto.

> +
> +       return test_bit(bit, &suspend_readahead_flags[index]);
> +}
> +
> +/* suspend_readahead_prepare
> + * Set up for doing readahead on an image */
> +static int suspend_prepare_readahead(int index)
> +{
> +       unsigned long new_page = get_zeroed_page(GFP_ATOMIC);
> +
> +       if(!new_page)
> +               return -ENOMEM;
> +
> +       suspend_bio_ops.readahead_pages[index] = virt_to_page(new_page);
> +       return 0;
> +}
> +
> +/* suspend_readahead_cleanup
> + * Clean up structures used for readahead */
> +static void suspend_cleanup_readahead(int page)
> +{
> +       __free_pages(suspend_bio_ops.readahead_pages[page], 0);
> +       suspend_bio_ops.readahead_pages[page] = 0;
> +       return;
> +}
> +
> +static unsigned long suspend_bio_memory_needed(void)
> +{
> +       /* We want to have at least enough memory so as to have 128 I/O
> +        * transactions on the fly at once. If we can to more, fine. */
> +       return (128 * (PAGE_SIZE + sizeof(struct request) +
> +                               sizeof(struct bio) + sizeof(struct io_info)));

Where did the magic 128 come from?

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [1/48] Suspend2 2.1.9.8 for 2.6.12: submit_intro
  2005-07-06  2:20 ` [PATCH] [1/48] Suspend2 2.1.9.8 for 2.6.12: submit_intro Nigel Cunningham
@ 2005-07-06  6:37   ` Pekka Enberg
  2005-07-06  8:12   ` Pavel Machek
  1 sibling, 0 replies; 187+ messages in thread
From: Pekka Enberg @ 2005-07-06  6:37 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> diff -ruNp 300-reboot-handler-hook.patch-old/kernel/sys.c 300-reboot-handler-hook.patch-new/kernel/sys.c
> --- 300-reboot-handler-hook.patch-old/kernel/sys.c      2005-06-20 11:47:32.000000000 +1000
> +++ 300-reboot-handler-hook.patch-new/kernel/sys.c      2005-07-04 23:14:18.000000000 +1000
> @@ -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;

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

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (47 preceding siblings ...)
  2005-07-06  2:20 ` [PATCH] [45/48] Suspend2 2.1.9.8 for 2.6.12: 621-swsusp-tidy.patch Nigel Cunningham
@ 2005-07-06  6:40 ` Pekka Enberg
  2005-07-07 12:19   ` Nigel Cunningham
  2005-07-06  8:21 ` Pavel Machek
                   ` (2 subsequent siblings)
  51 siblings, 1 reply; 187+ messages in thread
From: Pekka Enberg @ 2005-07-06  6:40 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

Hi Nigel,

On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> 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.

Please consider putting diffstat in the patches. They make navigating
large patchsets easier.

                               Pekka

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [16/48] Suspend2 2.1.9.8 for 2.6.12: 406-dynamic-pageflags.patch
  2005-07-06  2:20 ` [PATCH] [16/48] Suspend2 2.1.9.8 for 2.6.12: 406-dynamic-pageflags.patch Nigel Cunningham
@ 2005-07-06  7:46   ` Shaohua Li
  2005-07-06  8:13     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Shaohua Li @ 2005-07-06  7:46 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

On Wed, 2005-07-06 at 12:20 +1000, Nigel Cunningham wrote:
> +
> +/*
> + * 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);
> +		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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [11/48] Suspend2 2.1.9.8 for 2.6.12: 401-e820-table-support.patch
  2005-07-06  3:44     ` Nigel Cunningham
@ 2005-07-06  8:04       ` Pavel Machek
  2005-07-06 13:29       ` Zwane Mwaikambo
  1 sibling, 0 replies; 187+ messages in thread
From: Pavel Machek @ 2005-07-06  8:04 UTC (permalink / raw)
  To: Nigel Cunningham
  Cc: Zwane Mwaikambo, Nigel Cunningham, Linux Kernel Mailing List, shaohua.li

Hi!

> > > @@ -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;
> > >  }
> > 
> > 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.

I *think* it is in -mm already.
								Pavel
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch
  2005-07-06  2:20 ` [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch Nigel Cunningham
  2005-07-06  3:34   ` Zwane Mwaikambo
@ 2005-07-06  8:08   ` Pavel Machek
  2005-07-06  9:52   ` Russell King
  2005-07-10 23:07   ` Christoph Hellwig
  3 siblings, 0 replies; 187+ messages in thread
From: Pavel Machek @ 2005-07-06  8:08 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> 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
> --- 353-disable-highmem-tlb-flush-for-copyback.patch-old/mm/highmem.c	2005-06-20 11:47:32.000000000 +1000
> +++ 353-disable-highmem-tlb-flush-for-copyback.patch-new/mm/highmem.c	2005-07-04 23:14:20.000000000 +1000
> @@ -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)

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

										Pavel
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [1/48] Suspend2 2.1.9.8 for 2.6.12: submit_intro
  2005-07-06  2:20 ` [PATCH] [1/48] Suspend2 2.1.9.8 for 2.6.12: submit_intro Nigel Cunningham
  2005-07-06  6:37   ` Pekka Enberg
@ 2005-07-06  8:12   ` Pavel Machek
  1 sibling, 0 replies; 187+ messages in thread
From: Pavel Machek @ 2005-07-06  8:12 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

On St 06-07-05 12:20:39, Nigel Cunningham wrote:
> diff -ruNp 300-reboot-handler-hook.patch-old/kernel/sys.c 300-reboot-handler-hook.patch-new/kernel/sys.c
> --- 300-reboot-handler-hook.patch-old/kernel/sys.c	2005-06-20 11:47:32.000000000 +1000
> +++ 300-reboot-handler-hook.patch-new/kernel/sys.c	2005-07-04 23:14:18.000000000 +1000
> @@ -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

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


								Pavel
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [16/48] Suspend2 2.1.9.8 for 2.6.12: 406-dynamic-pageflags.patch
  2005-07-06  7:46   ` Shaohua Li
@ 2005-07-06  8:13     ` Nigel Cunningham
  2005-07-06  8:30       ` Shaohua Li
  0 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  8:13 UTC (permalink / raw)
  To: Li Shaohua; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Wed, 2005-07-06 at 17:46, Shaohua Li wrote:
> 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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [14/48] Suspend2 2.1.9.8 for 2.6.12: 404-check-mounts-support.patch
  2005-07-06  2:20 ` [PATCH] [14/48] Suspend2 2.1.9.8 for 2.6.12: 404-check-mounts-support.patch Nigel Cunningham
@ 2005-07-06  8:15   ` Pavel Machek
  2005-07-06  8:30     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-06  8:15 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

On St 06-07-05 12:20:40, Nigel Cunningham wrote:
> diff -ruNp 405-clear-swapfile-bdev-in-swapoff.patch-old/mm/swapfile.c 405-clear-swapfile-bdev-in-swapoff.patch-new/mm/swapfile.c
> --- 405-clear-swapfile-bdev-in-swapoff.patch-old/mm/swapfile.c	2005-07-06 11:22:01.000000000 +1000
> +++ 405-clear-swapfile-bdev-in-swapoff.patch-new/mm/swapfile.c	2005-07-04 23:14:19.000000000 +1000
> @@ -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
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (48 preceding siblings ...)
  2005-07-06  6:40 ` [0/48] Suspend2 2.1.9.8 for 2.6.12 Pekka Enberg
@ 2005-07-06  8:21 ` Pavel Machek
  2005-07-06  8:22 ` Pavel Machek
  2005-07-10 23:06 ` Christoph Hellwig
  51 siblings, 0 replies; 187+ messages in thread
From: Pavel Machek @ 2005-07-06  8:21 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

On St 06-07-05 12:20:39, Nigel Cunningham wrote:
> 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.

It still has quite a big impact outside kernel/power :-(.

								Pavel
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (49 preceding siblings ...)
  2005-07-06  8:21 ` Pavel Machek
@ 2005-07-06  8:22 ` Pavel Machek
  2005-07-06  8:33   ` Nigel Cunningham
  2005-07-07  0:27   ` Nigel Cunningham
  2005-07-10 23:06 ` Christoph Hellwig
  51 siblings, 2 replies; 187+ messages in thread
From: Pavel Machek @ 2005-07-06  8:22 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> 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.

Is swsusp1 expected to be functional after these are applied? You
removed *some* of its hooks, but not all, so I'm confused.

								Pavel
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [16/48] Suspend2 2.1.9.8 for 2.6.12: 406-dynamic-pageflags.patch
  2005-07-06  8:13     ` Nigel Cunningham
@ 2005-07-06  8:30       ` Shaohua Li
  0 siblings, 0 replies; 187+ messages in thread
From: Shaohua Li @ 2005-07-06  8:30 UTC (permalink / raw)
  To: ncunningham; +Cc: Nigel Cunningham, Linux Kernel Mailing List

On Wed, 2005-07-06 at 18:13 +1000, Nigel Cunningham wrote:
> Hi.
> 
> On Wed, 2005-07-06 at 17:46, Shaohua Li wrote:
> > 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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [14/48] Suspend2 2.1.9.8 for 2.6.12: 404-check-mounts-support.patch
  2005-07-06  8:15   ` Pavel Machek
@ 2005-07-06  8:30     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  8:30 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux Kernel Mailing List

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

On Wed, 2005-07-06 at 18:15, Pavel Machek wrote:
> On St 06-07-05 12:20:40, Nigel Cunningham wrote:
> > diff -ruNp 405-clear-swapfile-bdev-in-swapoff.patch-old/mm/swapfile.c 405-clear-swapfile-bdev-in-swapoff.patch-new/mm/swapfile.c
> > --- 405-clear-swapfile-bdev-in-swapoff.patch-old/mm/swapfile.c	2005-07-06 11:22:01.000000000 +1000
> > +++ 405-clear-swapfile-bdev-in-swapoff.patch-new/mm/swapfile.c	2005-07-04 23:14:19.000000000 +1000
> > @@ -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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-06  8:22 ` Pavel Machek
@ 2005-07-06  8:33   ` Nigel Cunningham
  2005-07-07  0:27   ` Nigel Cunningham
  1 sibling, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  8:33 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Wed, 2005-07-06 at 18:22, Pavel Machek wrote:
> Hi!
> 
> > 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.
> 
> Is swsusp1 expected to be functional after these are applied? You
> removed *some* of its hooks, but not all, so I'm confused.

It should definitely still be functional.

In the past I've gone with the logic that if people go to the trouble of
patching suspend2 in, they probably want to use it instead of swsusp.
I'm happy for the reboot and acpi patches to be left out for now.

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [4/48] Suspend2 2.1.9.8 for 2.6.12: 302-init-hooks.patch
  2005-07-06  8:38   ` Shaohua Li
@ 2005-07-06  8:35     ` Nigel Cunningham
  2005-07-06 15:38     ` Bernard Blackham
  1 sibling, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06  8:35 UTC (permalink / raw)
  To: Li Shaohua; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Wed, 2005-07-06 at 18:38, Shaohua Li wrote:
> On Wed, 2005-07-06 at 12:20 +1000, Nigel Cunningham wrote:
> > diff -ruNp 350-workthreads.patch-old/drivers/acpi/osl.c 350-workthreads.patch-new/drivers/acpi/osl.c
> > --- 350-workthreads.patch-old/drivers/acpi/osl.c	2005-06-20 11:46:50.000000000 +1000
> > +++ 350-workthreads.patch-new/drivers/acpi/osl.c	2005-07-04 23:14:18.000000000 +1000
> > @@ -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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [4/48] Suspend2 2.1.9.8 for 2.6.12: 302-init-hooks.patch
  2005-07-06  2:20 ` [PATCH] [4/48] Suspend2 2.1.9.8 for 2.6.12: 302-init-hooks.patch Nigel Cunningham
@ 2005-07-06  8:38   ` Shaohua Li
  2005-07-06  8:35     ` Nigel Cunningham
  2005-07-06 15:38     ` Bernard Blackham
  0 siblings, 2 replies; 187+ messages in thread
From: Shaohua Li @ 2005-07-06  8:38 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

On Wed, 2005-07-06 at 12:20 +1000, Nigel Cunningham wrote:
> diff -ruNp 350-workthreads.patch-old/drivers/acpi/osl.c 350-workthreads.patch-new/drivers/acpi/osl.c
> --- 350-workthreads.patch-old/drivers/acpi/osl.c	2005-06-20 11:46:50.000000000 +1000
> +++ 350-workthreads.patch-new/drivers/acpi/osl.c	2005-07-04 23:14:18.000000000 +1000
> @@ -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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch
  2005-07-06  2:20 ` [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch Nigel Cunningham
  2005-07-06  3:34   ` Zwane Mwaikambo
  2005-07-06  8:08   ` Pavel Machek
@ 2005-07-06  9:52   ` Russell King
  2005-07-10 23:07   ` Christoph Hellwig
  3 siblings, 0 replies; 187+ messages in thread
From: Russell King @ 2005-07-06  9:52 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

On Wed, Jul 06, 2005 at 12:20:40PM +1000, Nigel Cunningham wrote:
> 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
> --- 353-disable-highmem-tlb-flush-for-copyback.patch-old/mm/highmem.c	2005-06-20 11:47:32.000000000 +1000
> +++ 353-disable-highmem-tlb-flush-for-copyback.patch-new/mm/highmem.c	2005-07-04 23:14:20.000000000 +1000
> @@ -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();

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.

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [45/48] Suspend2 2.1.9.8 for 2.6.12: 621-swsusp-tidy.patch
  2005-07-06  2:20 ` [PATCH] [45/48] Suspend2 2.1.9.8 for 2.6.12: 621-swsusp-tidy.patch Nigel Cunningham
@ 2005-07-06  9:55   ` Pekka Enberg
  0 siblings, 0 replies; 187+ messages in thread
From: Pekka Enberg @ 2005-07-06  9:55 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> diff -ruNp 622-swapwriter.patch-old/kernel/power/suspend_swap.c 622-swapwriter.patch-new/kernel/power/suspend_swap.c
> --- 622-swapwriter.patch-old/kernel/power/suspend_swap.c        1970-01-01 10:00:00.000000000 +1000
> +++ 622-swapwriter.patch-new/kernel/power/suspend_swap.c        2005-07-05 23:48:59.000000000 +1000
> +/*
> + * ---------------------------------------------------------------
> + *
> + *     Internal Data Structures
> + *
> + * ---------------------------------------------------------------
> + */

Can we please tone down this banner?

> +struct {
> +       /* Extent chains for swap & blocks */
> +       struct extentchain swapextents;
> +       struct extentchain block_chain[MAX_SWAPFILES];
> +
> +       /* Location of start of pagedir 1 */
> +       struct extent * pd1start_block_extent;
> +       int pd1start_chain;
> +       int pd1start_extent_number;
> +       unsigned long pd1start_block_offset;
> +
> +       /* Devices used for swap */
> +       dev_t swapdevs[MAX_SWAPFILES];
> +       char blocksizes[MAX_SWAPFILES];
> +
> +} header_data;
> +
> +static dev_t header_device = 0;
> +static struct block_device * header_block_device = NULL;
> +static int headerblocksize = PAGE_SIZE;
> +static int headerblock;
> +
> +/* For swapfile automatically swapon/off'd. */
> +static char swapfilename[256] = "";

<linux/suspend.h> already has SWAP_FILENAME_MAXLENGTH. Use that.

> +extern asmlinkage long sys_swapon(const char * specialfile, int swap_flags);
> +extern asmlinkage long sys_swapoff(const char * specialfile);
> +static int suspend_swapon_status = 0;
> +
> +/*
> + * ---------------------------------------------------------------
> + *
> + *     Current state.
> + *
> + * ---------------------------------------------------------------
> + */

Could we please tone down this banner?

> +
> +/* Which pagedir are we saving/reloading? Needed so we can know whether to
> + * remember the last swap entry used at the end of writing pageset2, and
> + * get that location when saving or reloading pageset1.*/
> +static int current_stream = 0;

No need to set to zero. The compiler will do it for you.

> +
> +/* Pointer to current swap entry being loaded/saved. */
> +static struct extent * currentblockextent = NULL;
> +static unsigned long currentblockoffset = 0;
> +static int currentblockchain = 0;
> +static int currentblocksperpage = 0;
> +
> +/* Header Page Information */
> +static int header_pages_allocated = 0;
> +static struct submit_params * first_header_submit_info = NULL,
> + * last_header_submit_info = NULL, * current_header_submit_info = NULL;

Ditto. (applies to NULL as well)

> +static void get_header_params(struct submit_params * headerpage)
> +{
> +       swp_entry_t entry = headerpage->swap_address;
> +       int swapfilenum = swp_type(entry);
> +       unsigned long offset = swp_offset(entry);
> +       struct swap_info_struct * sis = get_swap_info_struct(swapfilenum);
> +       sector_t sector = map_swap_page(sis, offset);
> +
> +       headerpage->dev = sis->bdev,
> +       headerpage->block[0] = sector;
> +       //headerpage->blocks_used = 1;

Please drop commented out code.

> +static int try_to_open_resume_device(void)
> +{
> +       resume_block_device = open_by_devnum(resume_device, FMODE_READ);
> +
> +       if (IS_ERR(resume_block_device) || (!resume_block_device))

The second set of parenthesis are redundant.

> +       /*
> +        * Put bdev of suspend header in last byte of swap header
> +        * (unsigned short)
> +        */
> +       if (type > 11) {
> +               dev_t * header_ptr = (dev_t *) &header[1];
> +               unsigned char * headerblocksize_ptr =
> +                       (unsigned char *) &header[5];
> +               unsigned long * headerblock_ptr = (unsigned long *) &header[6];
> +               header_device = *header_ptr;
> +               /*
> +                * We are now using the highest bit of the char to indicate
> +                * whether we have attempted to resume from this image before.
> +                */
> +               clear_suspend_state(SUSPEND_RESUMED_BEFORE);
> +               if (((int) *headerblocksize_ptr) & 0x80)
> +                       set_suspend_state(SUSPEND_RESUMED_BEFORE);
> +               headerblocksize = 512 * (((int) *headerblocksize_ptr) & 0xf);

Hardcoded sector size?

> +
> +       /* Restore device info */
> +       for (i = 0; i < MAX_SWAPFILES; i++) {
> +               dev_t thisdevice = header_data.swapdevs[i];
> +
> +               swap_info[i].bdev = NULL;
> +
> +               if (!thisdevice)
> +                       continue;
> +
> +               if (thisdevice == resume_device) {
> +                       swap_info[i].bdev = resume_block_device;
> +                       /* Mark as used so the device doesn't get suspended. */
> +                       swap_info[i].swap_file = (struct file *) 0xffffff;

Please use constants instead of magic numbers.

> +static int swapwriter_write_init(int stream_number)
> +{
> +       current_stream = stream_number;
> +
> +       if (current_stream == 1) {
> +               currentblockextent = header_data.pd1start_block_extent;
> +               currentblockoffset = header_data.pd1start_block_offset;
> +               currentblockchain = header_data.pd1start_chain;
> +       } else

See below.

> +               for (currentblockchain = 0; currentblockchain < MAX_SWAPFILES;
> +                               currentblockchain++)
> +                       if (header_data.block_chain[currentblockchain].first) {
> +                               currentblockextent =
> +                                       header_data.
> +                                        block_chain[currentblockchain].first;
> +                               currentblockoffset = currentblockextent->minimum;
> +                               break;
> +                       }

Braces would make sense here.


> +
> +       currentblocksperpage = get_blocks_per_page(currentblockchain);
> +
> +       suspend_bio_ops.reset_io_stats();
> +
> +       return 0;
> +}
> +
> +static int swapwriter_write_chunk(struct page * buffer_page)
> +{
> +       int i;
> +       struct submit_params submit_params;
> +
> +       if (TEST_ACTION_STATE(SUSPEND_TEST_FILTER_SPEED))
> +               return 0;
> +
> +       if (currentblockchain == MAX_SWAPFILES) {
> +               printk("Error! We have run out of blocks for writing data.\n");
> +               return -ENOSPC;
> +       }
> +
> +       if (!currentblockextent) {
> +               do {
> +                       currentblockchain++;
> +               } while ((currentblockchain < MAX_SWAPFILES) &&
> +                  (!header_data.block_chain[currentblockchain].first));
> +
> +               /* We can validly not have a new blockextent. We
> +                * might be compressing data and the user was
> +                * too optimistic in setting the compression
> +                * ratio or we're just copying the pageset. */
> +
> +               if (currentblockchain == MAX_SWAPFILES) {
> +                       printk("Argh. Ran out of block chains.\n");
> +                       return -ENOSPC;
> +               }
> +
> +               currentblockextent =
> +                header_data.block_chain[currentblockchain].first;
> +               currentblockoffset = currentblockextent->minimum;
> +               currentblocksperpage = get_blocks_per_page(currentblockchain);
> +       }
> +
> +       submit_params.readahead_index = -1;
> +       submit_params.page = buffer_page;
> +       submit_params.dev = swap_info[currentblockchain].bdev;
> +
> +       /* Get the blocks */
> +       submit_params.block[0] = currentblockoffset;
> +       for (i = 0; i < currentblocksperpage; i++)
> +               GET_EXTENT_NEXT(currentblockextent, currentblockoffset);
> +
> +       suspend_bio_ops.submit_io(WRITE, &submit_params, 0);
> +
> +       check_shift_keys(0, NULL);
> +
> +       return 0;
> +}
> +
> +static int swapwriter_write_cleanup(void)
> +{
> +       if (current_stream == 2) {

Where did that magic number two come from?

> +               header_data.pd1start_block_extent = currentblockextent;
> +               header_data.pd1start_block_offset = currentblockoffset;
> +               header_data.pd1start_chain = currentblockchain;
> +       }
> +
> +       suspend_bio_ops.finish_all_io();
> +
> +       suspend_bio_ops.check_io_stats();
> +
> +       return 0;
> +}
> +
> +static int swapwriter_read_init(int stream_number)
> +{
> +       current_stream = stream_number;
> +
> +       if (current_stream == 1) {

Ditto.

> +static int swapwriter_parse_image_location(char * commandline, int only_writer)
> +{
> +       char *thischar, *devstart = NULL, *colon = NULL, *at_symbol = NULL;
> +       union p_diskpage diskpage;
> +       int signature_found, result = -EINVAL, temp_result;
> +
> +       if (strncmp(commandline, "swap:", 5)) {
> +               if (!only_writer)
> +                       return 1;
> +       } else
> +               commandline += 5;
> +
> +       devstart = thischar = commandline;
> +       while ((*thischar != ':') && (*thischar != '@') &&
> +               ((thischar - commandline) < 250) && (*thischar))

What's the magic 250 here?

> +               thischar++;
> +
> +       if (*thischar == ':') {
> +               colon = thischar;
> +               *colon = 0;
> +               thischar++;
> +       }
> +
> +       while ((*thischar != '@') && ((thischar - commandline) < 250) && (*thischar))

And here?

> +               thischar++;
> +
> +       if (*thischar == '@') {
> +               at_symbol = thischar;
> +               *at_symbol = 0;
> +       }
> +
> +       if (colon)
> +               resume_firstblock = (int) simple_strtoul(colon + 1, NULL, 0);
> +       else
> +               resume_firstblock = 0;
> +
> +       if (at_symbol) {
> +               resume_firstblocksize = (int) simple_strtoul(at_symbol + 1, NULL, 0);
> +               if (resume_firstblocksize & 0x1FF)
> +                       printk("Swapwriter: Blocksizes are usually a multiple of 512. Don't expect this to work!\n");

Then why do we allow it?

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [41/48] Suspend2 2.1.9.8 for 2.6.12: 617-proc.patch
  2005-07-06  2:20 ` [PATCH] [41/48] Suspend2 2.1.9.8 for 2.6.12: 617-proc.patch Nigel Cunningham
@ 2005-07-06 10:03   ` Pekka Enberg
  0 siblings, 0 replies; 187+ messages in thread
From: Pekka Enberg @ 2005-07-06 10:03 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> diff -ruNp 618-core.patch-old/kernel/power/suspend2_core/suspend.c 618-core.patch-new/kernel/power/suspend2_core/suspend.c
> --- 618-core.patch-old/kernel/power/suspend2_core/suspend.c     1970-01-01
> +#define SNPRINTF(a...)         len += suspend_snprintf(debug_info_buffer + len, \
> +               PAGE_SIZE - len - 1, ## a)

Please don't introduce subsystem specific wrappers for generic string
manipulation functions. Put them to lib/.

                      Pekka

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch
  2005-07-06  5:58   ` Pekka Enberg
  2005-07-06  6:21     ` Nigel Cunningham
@ 2005-07-06 10:04     ` Nigel Cunningham
  1 sibling, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06 10:04 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Nigel Cunningham, Linux Kernel Mailing List, Pekka Enberg

Requested changes applied.

Thanks!

Nigel

On Wed, 2005-07-06 at 15:58, Pekka Enberg wrote:
> On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> > 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
> > --- 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend2.h 1970-01-01 10:00:00.000000000 +1000
> > +++ 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend2.h 2005-07-05 23:56:15.000000000 +1000
> > @@ -0,0 +1,432 @@
> > +#undef inline
> > +#define inline __inline__ __attribute__((always_inline))
> 
> Please drop this macro. <linux/compiler.h> takes care of it already.
> 
> > +
> > +/* 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
> 
> Please drop the #ifdef
> 
> > +       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).
> 
> > +
> > +#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.
> 
> > +#endif
> > +
> > +#ifndef CONFIG_SMP
> > +#undef cpu_clear
> > +#define cpu_clear(a, b) do { } while(0)
> 
> Same here.
> 
> > +#endif
> > +
> > +extern struct suspend2_saved_context suspend2_saved_context;   /* temporary storage */
> 
> Move comment up.
> 
> > +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.
> 
> > +/*
> > + * 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.
> 
> > 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
> > --- 520-version-specific-x86_64.patch-old/include/asm-x86_64/suspend.h  2005-06-20 11:47:28.000000000 +1000
> > +++ 520-version-specific-x86_64.patch-new/include/asm-x86_64/suspend.h  2005-07-04 23:14:19.000000000 +1000
> > @@ -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.
> 
> > 
> >  #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 majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> >
> 
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [48/48] Suspend2 2.1.9.8 for 2.6.12: 624-filewriter.patch
  2005-07-06  2:20 ` [PATCH] [48/48] Suspend2 2.1.9.8 for 2.6.12: 624-filewriter.patch Nigel Cunningham
@ 2005-07-06 10:07   ` Pekka Enberg
  2005-07-06 10:13     ` Nigel Cunningham
  2005-07-09 12:10   ` [PATCH] [48/48] " Pavel Machek
  2005-07-10 23:14   ` Christoph Hellwig
  2 siblings, 1 reply; 187+ messages in thread
From: Pekka Enberg @ 2005-07-06 10:07 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> diff -ruNp 625-crypto-api-work.patch-old/crypto/lzf.c 625-crypto-api-work.patch-new/crypto/lzf.c
> --- 625-crypto-api-work.patch-old/crypto/lzf.c  1970-01-01 10:00:00.000000000 +1000
> +++ 625-crypto-api-work.patch-new/crypto/lzf.c  2005-07-05 23:57:15.000000000 +1000
> +static int lzf_compress(void * context, const u8 *in_data, unsigned int in_len,
> +                           u8 *out_data, unsigned int *out_len)
> +{
> +  struct lzf_ctx * ctx = (struct lzf_ctx *) context;
> +  const u8 **htab = ctx->hbuf;
> +  const u8 **hslot;
> +  const u8 *ip = in_data;
> +        u8 *op = out_data;
> +  const u8 *in_end  = ip + in_len;
> +        u8 *out_end = op + *out_len - 3;
> +  const u8 *ref;
> +
> +  unsigned int hval = FRST (ip);
> +  unsigned long off;
> +           int lit = 0;
> +
> +       if (ctx->first_call) {
> +               ctx->first_call = 0;
> +       }
> +#if INIT_HTAB

[snip, snip]

scripts/Lindent, please.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [2/48] Suspend2 2.1.9.8 for 2.6.12: 300-reboot-handler-hook.patch
  2005-07-06  2:20 ` [PATCH] [2/48] Suspend2 2.1.9.8 for 2.6.12: 300-reboot-handler-hook.patch Nigel Cunningham
@ 2005-07-06 10:08   ` Pekka Enberg
  2005-07-06 10:18     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pekka Enberg @ 2005-07-06 10:08 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> 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
> --- 301-proc-acpi-sleep-activate-hook.patch-old/drivers/acpi/sleep/proc.c       2005-06-20 11:46:50.000000000 +1000
> +++ 301-proc-acpi-sleep-activate-hook.patch-new/drivers/acpi/sleep/proc.c       2005-07-04 23:14:18.000000000 +1000
> @@ -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.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [32/48] Suspend2 2.1.9.8 for 2.6.12: 609-driver-model.patch
  2005-07-06  2:20 ` [PATCH] [32/48] Suspend2 2.1.9.8 for 2.6.12: 609-driver-model.patch Nigel Cunningham
@ 2005-07-06 10:10   ` Pekka Enberg
  2005-07-06 12:05     ` Nigel Cunningham
  2005-07-06 12:14     ` Nigel Cunningham
  0 siblings, 2 replies; 187+ messages in thread
From: Pekka Enberg @ 2005-07-06 10:10 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> diff -ruNp 610-encryption.patch-old/kernel/power/suspend2_core/encryption.c 610-encryption.patch-new/kernel/power/suspend2_core/encryption.c
> --- 610-encryption.patch-old/kernel/power/suspend2_core/encryption.c    1970-01-01 10:00:00.000000000 +1000
> +++ 610-encryption.patch-new/kernel/power/suspend2_core/encryption.c    2005-07-05 23:54:31.000000000 +1000
> +static inline void free_local_buffer(void)
> +{
> +       if (page_buffer)
> +               free_pages((unsigned long) page_buffer, 0);

Use free_page(), please.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [48/48] Suspend2 2.1.9.8 for 2.6.12: 624-filewriter.patch
  2005-07-06 10:07   ` Pekka Enberg
@ 2005-07-06 10:13     ` Nigel Cunningham
  2005-07-06 10:17       ` Pekka J Enberg
  0 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06 10:13 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Nigel Cunningham, Linux Kernel Mailing List, Pekka Enberg

Hi.

Thanks very much for all your reading and commenting. I really
appreciate it. By the way, you do want replies sent to both addresses?

This one is contributed code. I haven't had or needed an update since it
was added though, so I guess I could reindent it. Will do.

Regards,

Nigel

On Wed, 2005-07-06 at 20:07, Pekka Enberg wrote:
> On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> > diff -ruNp 625-crypto-api-work.patch-old/crypto/lzf.c 625-crypto-api-work.patch-new/crypto/lzf.c
> > --- 625-crypto-api-work.patch-old/crypto/lzf.c  1970-01-01 10:00:00.000000000 +1000
> > +++ 625-crypto-api-work.patch-new/crypto/lzf.c  2005-07-05 23:57:15.000000000 +1000
> > +static int lzf_compress(void * context, const u8 *in_data, unsigned int in_len,
> > +                           u8 *out_data, unsigned int *out_len)
> > +{
> > +  struct lzf_ctx * ctx = (struct lzf_ctx *) context;
> > +  const u8 **htab = ctx->hbuf;
> > +  const u8 **hslot;
> > +  const u8 *ip = in_data;
> > +        u8 *op = out_data;
> > +  const u8 *in_end  = ip + in_len;
> > +        u8 *out_end = op + *out_len - 3;
> > +  const u8 *ref;
> > +
> > +  unsigned int hval = FRST (ip);
> > +  unsigned long off;
> > +           int lit = 0;
> > +
> > +       if (ctx->first_call) {
> > +               ctx->first_call = 0;
> > +       }
> > +#if INIT_HTAB
> 
> [snip, snip]
> 
> scripts/Lindent, please.
> 
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [34/48] Suspend2 2.1.9.8 for 2.6.12: 610-extent.patch
  2005-07-06  2:20 ` [PATCH] [34/48] Suspend2 2.1.9.8 for 2.6.12: 610-extent.patch Nigel Cunningham
@ 2005-07-06 10:14   ` Pekka Enberg
  0 siblings, 0 replies; 187+ messages in thread
From: Pekka Enberg @ 2005-07-06 10:14 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> diff -ruNp 611-io.patch-old/kernel/power/suspend2_core/io.c 611-io.patch-new/kernel/power/suspend2_core/io.c
> --- 611-io.patch-old/kernel/power/suspend2_core/io.c    1970-01-01 10:00:00.000000000 +1000
> +++ 611-io.patch-new/kernel/power/suspend2_core/io.c    2005-07-05 23:48:59.000000000 +1000
> @@ -0,0 +1,1006 @@
> +/*
> + * kernel/power/io.c
> + *
> + * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
> + * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
                                           ^

Whitespace damage (appears elsewhere too).

> + * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr>
> + * Copyright (C) 2002-2005 Nigel Cunningham <nigel@suspend2.net>
> + *

[snip]

> +       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)) {

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

> +                       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;

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

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: Suspend2 2.1.9.8 for 2.6.12: 624-filewriter.patch
  2005-07-06 10:13     ` Nigel Cunningham
@ 2005-07-06 10:17       ` Pekka J Enberg
  0 siblings, 0 replies; 187+ messages in thread
From: Pekka J Enberg @ 2005-07-06 10:17 UTC (permalink / raw)
  To: ncunningham; +Cc: Pekka Enberg, Nigel Cunningham, Linux Kernel Mailing List

Nigel Cunningham writes:
> Thanks very much for all your reading and commenting. I really
> appreciate it. By the way, you do want replies sent to both addresses?

I'm just browsing through it for now. Replies to cs.helsinki.fi is 
sufficient. I use my gmail address for replying to lkml posts only. 

                   Pekka 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [2/48] Suspend2 2.1.9.8 for 2.6.12: 300-reboot-handler-hook.patch
  2005-07-06 10:08   ` Pekka Enberg
@ 2005-07-06 10:18     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06 10:18 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Nigel Cunningham, Linux Kernel Mailing List, Pekka Enberg

Hi.

On Wed, 2005-07-06 at 20:08, Pekka Enberg wrote:
> On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> > 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
> > --- 301-proc-acpi-sleep-activate-hook.patch-old/drivers/acpi/sleep/proc.c       2005-06-20 11:46:50.000000000 +1000
> > +++ 301-proc-acpi-sleep-activate-hook.patch-new/drivers/acpi/sleep/proc.c       2005-07-04 23:14:18.000000000 +1000
> > @@ -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

-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [26/48] Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch
  2005-07-06  2:20 ` [PATCH] [26/48] Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch Nigel Cunningham
@ 2005-07-06 10:22   ` Pekka Enberg
  2005-07-06 11:41     ` Nigel Cunningham
  2005-07-06 11:58     ` [PATCH] [26/48] " Nigel Cunningham
  2005-07-09 11:53   ` Pavel Machek
  1 sibling, 2 replies; 187+ messages in thread
From: Pekka Enberg @ 2005-07-06 10:22 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> diff -ruNp 604-utility-header.patch-old/kernel/power/suspend2_core/utility.c 604-utility-header.patch-new/kernel/power/suspend2_core/utility.c
> --- 604-utility-header.patch-old/kernel/power/suspend2_core/utility.c   1970-01-01 10:00:00.000000000 +1000
> +++ 604-utility-header.patch-new/kernel/power/suspend2_core/utility.c   2005-07-05 23:48:59.000000000 +1000
> @@ -0,0 +1,46 @@
> +/*
> + * kernel/power/utility.c
> + *
> + * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
> + *
> + * 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
> --- 604-utility-header.patch-old/kernel/power/suspend2_core/utility.h   1970-01-01 10:00:00.000000000 +1000
> +++ 604-utility-header.patch-new/kernel/power/suspend2_core/utility.h   2005-07-05 23:48:59.000000000 +1000
> @@ -0,0 +1,12 @@
> +/*
> + * kernel/power/suspend2_core/utility.h
> + *
> + * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
> + *
> + * 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.

> +
> +extern int suspend_snprintf(char * buffer, int buffer_size, const char *fmt, ...);

What's wrong with regular snprintf?

                          Pekka

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [26/48] Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch
  2005-07-06 10:22   ` Pekka Enberg
@ 2005-07-06 11:41     ` Nigel Cunningham
  2005-07-06 11:52       ` Pekka J Enberg
  2005-07-06 11:58     ` [PATCH] [26/48] " Nigel Cunningham
  1 sibling, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06 11:41 UTC (permalink / raw)
  To: Linux Kernel Mailing List; +Cc: Pekka Enberg

Hi.

On Wed, 2005-07-06 at 20:22, Pekka Enberg wrote:
> > diff -ruNp 604-utility-header.patch-old/kernel/power/suspend2_core/utility.h 604-utility-header.patch-new/kernel/power/suspend2_core/utility.h
> > --- 604-utility-header.patch-old/kernel/power/suspend2_core/utility.h   1970-01-01 10:00:00.000000000 +1000
> > +++ 604-utility-header.patch-new/kernel/power/suspend2_core/utility.h   2005-07-05 23:48:59.000000000 +1000
> 
> Please do move these.

Okay.

> > +
> > +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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch
  2005-07-06 11:41     ` Nigel Cunningham
@ 2005-07-06 11:52       ` Pekka J Enberg
  0 siblings, 0 replies; 187+ messages in thread
From: Pekka J Enberg @ 2005-07-06 11:52 UTC (permalink / raw)
  To: ncunningham; +Cc: Linux Kernel Mailing List

On Wed, 2005-07-06 at 20:22, Pekka Enberg wrote:
> > > +
> > > +extern int suspend_snprintf(char * buffer, int buffer_size, const char *fmt, ...);
> > 
> > What's wrong with regular snprintf?

Nigel Cunningham writes:
> 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 

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [26/48] Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch
  2005-07-06 10:22   ` Pekka Enberg
  2005-07-06 11:41     ` Nigel Cunningham
@ 2005-07-06 11:58     ` Nigel Cunningham
  1 sibling, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06 11:58 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Linux Kernel Mailing List

Hi again.

On Wed, 2005-07-06 at 20:22, Pekka Enberg wrote:
> > + * 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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [37/48] Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch
  2005-07-06  2:20 ` [PATCH] [37/48] Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch Nigel Cunningham
@ 2005-07-06 12:01   ` Pekka Enberg
  2005-07-07  9:30     ` Nigel Cunningham
  2005-07-09 12:16   ` Pavel Machek
  1 sibling, 1 reply; 187+ messages in thread
From: Pekka Enberg @ 2005-07-06 12:01 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> diff -ruNp 614-plugins.patch-old/kernel/power/suspend2_core/plugins.c 614-plugins.patch-new/kernel/power/suspend2_core/plugins.c
> --- 614-plugins.patch-old/kernel/power/suspend2_core/plugins.c  1970-01-01 10:00:00.000000000 +1000
> +++ 614-plugins.patch-new/kernel/power/suspend2_core/plugins.c  2005-07-04 23:14:19.000000000 +1000
> @@ -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.

> +
> +#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.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [25/48] Suspend2 2.1.9.8 for 2.6.12: 602-smp.patch
  2005-07-06  2:20 ` [PATCH] [25/48] Suspend2 2.1.9.8 for 2.6.12: 602-smp.patch Nigel Cunningham
@ 2005-07-06 12:03   ` Pekka Enberg
  2005-07-06 13:21     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pekka Enberg @ 2005-07-06 12:03 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> 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
> --- 603-suspend2_common-headers.patch-old/kernel/power/suspend2_core/suspend2_common.h  1970-01-01 10:00:00.000000000 +1000
> +++ 603-suspend2_common-headers.patch-new/kernel/power/suspend2_core/suspend2_common.h  2005-07-04 23:14:19.000000000 +1000
> @@ -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))

Enums, please.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [32/48] Suspend2 2.1.9.8 for 2.6.12: 609-driver-model.patch
  2005-07-06 10:10   ` Pekka Enberg
@ 2005-07-06 12:05     ` Nigel Cunningham
  2005-07-06 12:14     ` Nigel Cunningham
  1 sibling, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06 12:05 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Linux Kernel Mailing List

Hi.

On Wed, 2005-07-06 at 20:10, Pekka Enberg wrote:
> On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> > diff -ruNp 610-encryption.patch-old/kernel/power/suspend2_core/encryption.c 610-encryption.patch-new/kernel/power/suspend2_core/encryption.c
> > --- 610-encryption.patch-old/kernel/power/suspend2_core/encryption.c    1970-01-01 10:00:00.000000000 +1000
> > +++ 610-encryption.patch-new/kernel/power/suspend2_core/encryption.c    2005-07-05 23:54:31.000000000 +1000
> > +static inline void free_local_buffer(void)
> > +{
> > +       if (page_buffer)
> > +               free_pages((unsigned long) page_buffer, 0);
> 
> Use free_page(), please.

Done. Thanks!

Nigel

-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [32/48] Suspend2 2.1.9.8 for 2.6.12: 609-driver-model.patch
  2005-07-06 10:10   ` Pekka Enberg
  2005-07-06 12:05     ` Nigel Cunningham
@ 2005-07-06 12:14     ` Nigel Cunningham
  1 sibling, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06 12:14 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Linux Kernel Mailing List

Hi again.

On Wed, 2005-07-06 at 20:10, Pekka Enberg wrote:
> On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> > diff -ruNp 610-encryption.patch-old/kernel/power/suspend2_core/encryption.c 610-encryption.patch-new/kernel/power/suspend2_core/encryption.c
> > --- 610-encryption.patch-old/kernel/power/suspend2_core/encryption.c    1970-01-01 10:00:00.000000000 +1000
> > +++ 610-encryption.patch-new/kernel/power/suspend2_core/encryption.c    2005-07-05 23:54:31.000000000 +1000
> > +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

-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [25/48] Suspend2 2.1.9.8 for 2.6.12: 602-smp.patch
  2005-07-06 12:03   ` Pekka Enberg
@ 2005-07-06 13:21     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-06 13:21 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Linux Kernel Mailing List

Hi.

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

[snip]

> > +#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))
> 
> Enums, please.

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

Nigel

-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch
  2005-07-06  3:43     ` Nigel Cunningham
@ 2005-07-06 13:27       ` Zwane Mwaikambo
  0 siblings, 0 replies; 187+ messages in thread
From: Zwane Mwaikambo @ 2005-07-06 13:27 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Nigel Cunningham, Linux Kernel Mailing List

On Wed, 6 Jul 2005, Nigel Cunningham wrote:

> On Wed, 2005-07-06 at 13:34, Zwane Mwaikambo wrote:
> > On Wed, 6 Jul 2005, Nigel Cunningham wrote:
> > 
> > > 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
> > > --- 353-disable-highmem-tlb-flush-for-copyback.patch-old/mm/highmem.c	2005-06-20 11:47:32.000000000 +1000
> > > +++ 353-disable-highmem-tlb-flush-for-copyback.patch-new/mm/highmem.c	2005-07-04 23:14:20.000000000 +1000
> > > @@ -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)
> > 
> > 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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [11/48] Suspend2 2.1.9.8 for 2.6.12: 401-e820-table-support.patch
  2005-07-06  3:44     ` Nigel Cunningham
  2005-07-06  8:04       ` Pavel Machek
@ 2005-07-06 13:29       ` Zwane Mwaikambo
  1 sibling, 0 replies; 187+ messages in thread
From: Zwane Mwaikambo @ 2005-07-06 13:29 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Nigel Cunningham, Linux Kernel Mailing List, shaohua.li

On Wed, 6 Jul 2005, Nigel Cunningham wrote:

> On Wed, 2005-07-06 at 13:35, Zwane Mwaikambo wrote:
> > 
> > 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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch
  2005-07-06  3:59     ` Nigel Cunningham
@ 2005-07-06 13:40       ` Zwane Mwaikambo
  0 siblings, 0 replies; 187+ messages in thread
From: Zwane Mwaikambo @ 2005-07-06 13:40 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux Kernel Mailing List

On Wed, 6 Jul 2005, Nigel Cunningham wrote:

> 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.

> 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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [4/48] Suspend2 2.1.9.8 for 2.6.12: 302-init-hooks.patch
  2005-07-06  8:38   ` Shaohua Li
  2005-07-06  8:35     ` Nigel Cunningham
@ 2005-07-06 15:38     ` Bernard Blackham
  1 sibling, 0 replies; 187+ messages in thread
From: Bernard Blackham @ 2005-07-06 15:38 UTC (permalink / raw)
  To: Shaohua Li; +Cc: Nigel Cunningham, linux-kernel

On Wed, Jul 06, 2005 at 04:38:45PM +0800, Shaohua Li wrote:
> On Wed, 2005-07-06 at 12:20 +1000, Nigel Cunningham wrote:
> > diff -ruNp 350-workthreads.patch-old/drivers/acpi/osl.c 350-workthreads.patch-new/drivers/acpi/osl.c
> > --- 350-workthreads.patch-old/drivers/acpi/osl.c	2005-06-20 11:46:50.000000000 +1000
> > +++ 350-workthreads.patch-new/drivers/acpi/osl.c	2005-07-04 23:14:18.000000000 +1000
> > @@ -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.

-- 
 Bernard Blackham <bernard at blackham dot com dot au>

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-06  8:22 ` Pavel Machek
  2005-07-06  8:33   ` Nigel Cunningham
@ 2005-07-07  0:27   ` Nigel Cunningham
  2005-07-07 12:04     ` Matthew Garrett
  2005-07-07 19:19     ` Pavel Machek
  1 sibling, 2 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-07  0:27 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Linux Kernel Mailing List

Hi again.

On Wed, 2005-07-06 at 18:22, Pavel Machek wrote:
> Is swsusp1 expected to be functional after these are applied? You
> removed *some* of its hooks, but not all, so I'm confused.

I've been thinking about this some more and wondering whether I should
just replace swsusp. I really don't want to step on your toes though.
What would you like to see happen?

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [37/48] Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch
  2005-07-06 12:01   ` Pekka Enberg
@ 2005-07-07  9:30     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-07  9:30 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Nigel Cunningham, Linux Kernel Mailing List, Pekka Enberg

Hi.

On Wed, 2005-07-06 at 22:01, Pekka Enberg wrote:
> On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> > diff -ruNp 614-plugins.patch-old/kernel/power/suspend2_core/plugins.c 614-plugins.patch-new/kernel/power/suspend2_core/plugins.c
> > --- 614-plugins.patch-old/kernel/power/suspend2_core/plugins.c  1970-01-01 10:00:00.000000000 +1000
> > +++ 614-plugins.patch-new/kernel/power/suspend2_core/plugins.c  2005-07-04 23:14:19.000000000 +1000
> > @@ -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.
> 
> > +
> > +#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

-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-07  0:27   ` Nigel Cunningham
@ 2005-07-07 12:04     ` Matthew Garrett
  2005-07-07 12:15       ` Nigel Cunningham
  2005-07-07 19:19     ` Pavel Machek
  1 sibling, 1 reply; 187+ messages in thread
From: Matthew Garrett @ 2005-07-07 12:04 UTC (permalink / raw)
  To: ncunningham; +Cc: linux-kernel

Nigel Cunningham <ncunningham@cyclades.com> wrote:

> I've been thinking about this some more and wondering whether I should
> just replace swsusp. I really don't want to step on your toes though.
> What would you like to see happen?

Do you implement the entire swsusp userspace interface? If not, removing
it probably isn't a reasonable plan without fair warning.

-- 
Matthew Garrett | mjg59-chiark.mail.linux-rutgers.kernel@srcf.ucam.org

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-07 12:04     ` Matthew Garrett
@ 2005-07-07 12:15       ` Nigel Cunningham
  2005-07-07 12:49         ` Matthew Garrett
  0 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-07 12:15 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Linux Kernel Mailing List

Hi.

On Thu, 2005-07-07 at 22:04, Matthew Garrett wrote:
> Nigel Cunningham <ncunningham@cyclades.com> wrote:
> 
> > I've been thinking about this some more and wondering whether I should
> > just replace swsusp. I really don't want to step on your toes though.
> > What would you like to see happen?
> 
> Do you implement the entire swsusp userspace interface? If not, removing
> it probably isn't a reasonable plan without fair warning.

I'm not suggesting removing the sysfs interface or replacing system to
ram - just the suspend to disk part.

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-06  6:40 ` [0/48] Suspend2 2.1.9.8 for 2.6.12 Pekka Enberg
@ 2005-07-07 12:19   ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-07 12:19 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Nigel Cunningham, Linux Kernel Mailing List, Pekka Enberg

Hi.

On Wed, 2005-07-06 at 16:40, Pekka Enberg wrote:
> Hi Nigel,
> 
> On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> > 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.
> 
> Please consider putting diffstat in the patches. They make navigating
> large patchsets easier.

Adjusted my patch generation script to do this.

Thanks.

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [46/48] Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch
  2005-07-06  6:33   ` Pekka Enberg
@ 2005-07-07 12:40     ` Nigel Cunningham
  2005-07-07 13:05       ` Pekka J Enberg
  0 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-07 12:40 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Nigel Cunningham, Linux Kernel Mailing List, Pekka Enberg

Hi.

On Wed, 2005-07-06 at 16:33, Pekka Enberg wrote:
> On 7/6/05, Nigel Cunningham <nigel@suspend2.net> wrote:
> > diff -ruNp 623-generic-block-io.patch-old/kernel/power/suspend_block_io.c 623-generic-block-io.patch-new/kernel/power/suspend_block_io.c
> > --- 623-generic-block-io.patch-old/kernel/power/suspend_block_io.c      1970-01-01 10:00:00.000000000 +1000
> > +++ 623-generic-block-io.patch-new/kernel/power/suspend_block_io.c      2005-07-05 23:48:59.000000000 +1000
> > @@ -0,0 +1,817 @@
> > +#include "suspend2_core/suspend.h"
> > +#include "suspend2_core/proc.h"
> > +#include "suspend2_core/plugins.h"
> > +#include "suspend2_core/utility.h"
> > +#include "suspend2_core/prepare_image.h"
> 
> You've got circular dependencies. kernel/power/suspend2_core depends
> on kernel/power and vice versa. Please just consider putting them all
> in kernel/power/

Done. They were separate just to keep things tidy.

> > +/* Bits in struct io_info->flags */
> > +#define IO_WRITING 1
> > +#define IO_RESTORE_PAGE_PROT 2
> > +#define IO_AWAITING_READ 3
> > +#define IO_AWAITING_WRITE 4
> > +#define IO_AWAITING_SUBMIT 5
> > +#define IO_AWAITING_CLEANUP 6
> > +#define IO_HANDLE_PAGE_PROT 7
> 
> Please use enums instead.

Done!

> > +
> > +#define MAX_OUTSTANDING_IO 1024
> > +
> > +/*
> > + * ---------------------------------------------------------------
> > + *
> > + *     IO in progress information storage and helpers
> > + *
> > + * ---------------------------------------------------------------
> > + */
> 
> Could we please drop the above banner. Hurts my eyes...

Sorry! :>

> > +
> > +struct io_info {
> > +       struct bio * sys_struct;
> > +       long block[PAGE_SIZE/512];
> 
> You're hardcoding sector size here, no?

As others do.

> > +       struct page * buffer_page;
> > +       struct page * data_page;
> > +       unsigned long flags;
> > +       struct block_device * dev;
> > +       struct list_head list;
> > +       int readahead_index;
> > +       struct work_struct work;
> > +};
> > +
> > +/* Locks separated to allow better SMP support.
> > + * An io_struct moves through the lists as follows.
> > + * free -> submit_batch -> busy -> ready_for_cleanup -> free
> > + */
> > +static LIST_HEAD(ioinfo_free);
> > +static spinlock_t ioinfo_free_lock = SPIN_LOCK_UNLOCKED;
> 
> Please use DEFINE_SPINLOCK instead. It is preferred as some automatic
> lock checkers need it.

Done.

> > +#define BITS_PER_UL (8 * sizeof(unsigned long))
> > +static volatile unsigned long suspend_readahead_flags[(MAX_READAHEAD + BITS_PER_UL - 1) / BITS_PER_UL];
> 
> <asm/types.h> has BITS_PER_LONG. Use it.

Thanks for educating the ignorant :>

> > +static int suspend_end_bio(struct bio * bio, unsigned int num, int err)
> > +{
> > +       struct io_info *io_info = (struct io_info *) bio->bi_private;
> 
> Redundant cast.

k.

> > +static unsigned long suspend_bio_memory_needed(void)
> > +{
> > +       /* We want to have at least enough memory so as to have 128 I/O
> > +        * transactions on the fly at once. If we can to more, fine. */
> > +       return (128 * (PAGE_SIZE + sizeof(struct request) +
> > +                               sizeof(struct bio) + sizeof(struct io_info)));
> 
> Where did the magic 128 come from?

My bad. Should be MAX_OUTSTANDING_IO.

Thanks, once again!

Nigel

-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-07 12:15       ` Nigel Cunningham
@ 2005-07-07 12:49         ` Matthew Garrett
  2005-07-07 12:56           ` Nigel Cunningham
                             ` (2 more replies)
  0 siblings, 3 replies; 187+ messages in thread
From: Matthew Garrett @ 2005-07-07 12:49 UTC (permalink / raw)
  To: ncunningham; +Cc: linux-kernel

Nigel Cunningham <ncunningham@cyclades.com> wrote:
> On Thu, 2005-07-07 at 22:04, Matthew Garrett wrote:
>> Do you implement the entire swsusp userspace interface? If not, removing
>> it probably isn't a reasonable plan without fair warning.
> 
> I'm not suggesting removing the sysfs interface or replacing system to
> ram - just the suspend to disk part.

Right, so you support the resume from disk trigger in sysfs and the
/proc/acpi/sleep interface? If suspend2 is a complete dropin replacement
then I'm much happier with the idea of dropping swsusp, but I don't want
to have to tie suspend/resume scripts to kernel versions.
-- 
Matthew Garrett | mjg59-chiark.mail.linux-rutgers.kernel@srcf.ucam.org

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-07 12:49         ` Matthew Garrett
@ 2005-07-07 12:56           ` Nigel Cunningham
  2005-07-07 18:54           ` Rafael J. Wysocki
  2005-07-08 13:30           ` Stefan Seyfried
  2 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-07 12:56 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Linux Kernel Mailing List

Hi.

On Thu, 2005-07-07 at 22:49, Matthew Garrett wrote:
> Nigel Cunningham <ncunningham@cyclades.com> wrote:
> > On Thu, 2005-07-07 at 22:04, Matthew Garrett wrote:
> >> Do you implement the entire swsusp userspace interface? If not, removing
> >> it probably isn't a reasonable plan without fair warning.
> > 
> > I'm not suggesting removing the sysfs interface or replacing system to
> > ram - just the suspend to disk part.
> 
> Right, so you support the resume from disk trigger in sysfs and the
> /proc/acpi/sleep interface? If suspend2 is a complete dropin replacement
> then I'm much happier with the idea of dropping swsusp, but I don't want
> to have to tie suspend/resume scripts to kernel versions.

Suspend2 currently has a proc entry to do the same, but I can easily
hook into the sysfs code. /proc/acpi/sleep is already taken care of, as
is the reboot handler. Suspend2 currently uses resume2= so as to not
conflict with swsusp, but that can be changed too. I always to my utmost
to ease the pain for other users. If something doesn't work the way you
want, just tell me and (assuming it's reasonable), I'll fix it.

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch
  2005-07-07 12:40     ` Nigel Cunningham
@ 2005-07-07 13:05       ` Pekka J Enberg
  2005-07-08 13:41         ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pekka J Enberg @ 2005-07-07 13:05 UTC (permalink / raw)
  To: ncunningham; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi Nigel, 

On Wed, 2005-07-06 at 16:33, Pekka Enberg wrote:
> > You're hardcoding sector size here, no?

Nigel Cunningham writes:
> As others do.

Even so, please use a constant. 

                  Pekka

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [46/48] Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch
  2005-07-06  2:20 ` [PATCH] [46/48] Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch Nigel Cunningham
  2005-07-06  6:33   ` Pekka Enberg
@ 2005-07-07 13:32   ` Pekka Enberg
  2005-07-07 21:16     ` Nigel Cunningham
  1 sibling, 1 reply; 187+ messages in thread
From: Pekka Enberg @ 2005-07-07 13:32 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel, Pekka Enberg

Hi Nigel,

> diff -ruNp 623-generic-block-io.patch-old/kernel/power/suspend_block_io.c 623-generic-block-io.patch-new/kernel/power/suspend_block_io.c
> --- 623-generic-block-io.patch-old/kernel/power/suspend_block_io.c      1970-01-01 10:00:00.000000000 +1000
> +++ 623-generic-block-io.patch-new/kernel/power/suspend_block_io.c      2005-07-05 23:48:59.000000000 +1000
> @@ -0,0 +1,817 @@
> +struct io_info {
> +       struct bio * sys_struct;
> +       long block[PAGE_SIZE/512];

Aah, but for this you should use block_size(io_info->dev) instead. No
need to mess with sector sizes. Why is this long by the way?
PAGE_SIZE/512 is block size in bytes.

> +       struct page * buffer_page;
> +       struct page * data_page;
> +       unsigned long flags;
> +       struct block_device * dev;
> +       struct list_head list;
> +       int readahead_index;
> +       struct work_struct work;
> +};

                                    Pekka

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-07 12:49         ` Matthew Garrett
  2005-07-07 12:56           ` Nigel Cunningham
@ 2005-07-07 18:54           ` Rafael J. Wysocki
  2005-07-07 21:21             ` Nigel Cunningham
  2005-07-08 13:30           ` Stefan Seyfried
  2 siblings, 1 reply; 187+ messages in thread
From: Rafael J. Wysocki @ 2005-07-07 18:54 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: ncunningham, linux-kernel

Hi,

On Thursday, 7 of July 2005 14:49, Matthew Garrett wrote:
> Nigel Cunningham <ncunningham@cyclades.com> wrote:
> > On Thu, 2005-07-07 at 22:04, Matthew Garrett wrote:
> >> Do you implement the entire swsusp userspace interface? If not, removing
> >> it probably isn't a reasonable plan without fair warning.
> > 
> > I'm not suggesting removing the sysfs interface or replacing system to
> > ram - just the suspend to disk part.
> 
> Right, so you support the resume from disk trigger in sysfs and the
> /proc/acpi/sleep interface? If suspend2 is a complete dropin replacement
> then I'm much happier with the idea of dropping swsusp, but I don't want
> to have to tie suspend/resume scripts to kernel versions.

I don't think that swsusp can be replaced with suspend2 right now.  First,
swsusp works on x86-64, and the support in suspend2 is preliminary,
AFAIK.  Second, the IA64 support for swsusp is in the works, and it is not supported
by suspend2.

Please don't plan to drop swsusp until you are able to replace it _completely_.

Greets,
Rafael


-- 
- Would you tell me, please, which way I ought to go from here?
- That depends a good deal on where you want to get to.
		-- Lewis Carroll "Alice's Adventures in Wonderland"

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-07  0:27   ` Nigel Cunningham
  2005-07-07 12:04     ` Matthew Garrett
@ 2005-07-07 19:19     ` Pavel Machek
  1 sibling, 0 replies; 187+ messages in thread
From: Pavel Machek @ 2005-07-07 19:19 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux Kernel Mailing List

Hi!

> > Is swsusp1 expected to be functional after these are applied? You
> > removed *some* of its hooks, but not all, so I'm confused.
> 
> I've been thinking about this some more and wondering whether I should
> just replace swsusp. I really don't want to step on your toes though.
> What would you like to see happen?

When/if suspend2 is merged and working, there's no reason to keep
swsusp around. So patches for removing swsusp1 are quite okay at the
end of series. OTOH it is one more patch for you to maintain, so... do
whatever you want.
								Pavel
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [46/48] Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch
  2005-07-07 13:32   ` [PATCH] [46/48] " Pekka Enberg
@ 2005-07-07 21:16     ` Nigel Cunningham
  2005-07-07 21:26       ` nickpiggin
                         ` (2 more replies)
  0 siblings, 3 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-07 21:16 UTC (permalink / raw)
  To: Pekka Enberg; +Cc: Linux Kernel Mailing List

Hi.

On Thu, 2005-07-07 at 23:32, Pekka Enberg wrote:
> Hi Nigel,
> 
> > diff -ruNp 623-generic-block-io.patch-old/kernel/power/suspend_block_io.c 623-generic-block-io.patch-new/kernel/power/suspend_block_io.c
> > --- 623-generic-block-io.patch-old/kernel/power/suspend_block_io.c      1970-01-01 10:00:00.000000000 +1000
> > +++ 623-generic-block-io.patch-new/kernel/power/suspend_block_io.c      2005-07-05 23:48:59.000000000 +1000
> > @@ -0,0 +1,817 @@
> > +struct io_info {
> > +       struct bio * sys_struct;
> > +       long block[PAGE_SIZE/512];
> 
> Aah, but for this you should use block_size(io_info->dev) instead. No
> need to mess with sector sizes. Why is this long by the way?
> PAGE_SIZE/512 is block size in bytes.

No...  it's the maximum number of blocks per page. Depending upon how
the user has set the blocksize when they created the filesystem (in the
case of filesystems), the number of blocks we use per page might be 1,
2, 4 or 8.

It's long because a sector number is stored in it.

Regards,

Nigel

> > +       struct page * buffer_page;
> > +       struct page * data_page;
> > +       unsigned long flags;
> > +       struct block_device * dev;
> > +       struct list_head list;
> > +       int readahead_index;
> > +       struct work_struct work;
> > +};
> 
>                                     Pekka
> 
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-07 18:54           ` Rafael J. Wysocki
@ 2005-07-07 21:21             ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-07 21:21 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Matthew Garrett, Linux Kernel Mailing List

Hi.

On Fri, 2005-07-08 at 04:54, Rafael J. Wysocki wrote:
> Hi,
> 
> On Thursday, 7 of July 2005 14:49, Matthew Garrett wrote:
> > Nigel Cunningham <ncunningham@cyclades.com> wrote:
> > > On Thu, 2005-07-07 at 22:04, Matthew Garrett wrote:
> > >> Do you implement the entire swsusp userspace interface? If not, removing
> > >> it probably isn't a reasonable plan without fair warning.
> > > 
> > > I'm not suggesting removing the sysfs interface or replacing system to
> > > ram - just the suspend to disk part.
> > 
> > Right, so you support the resume from disk trigger in sysfs and the
> > /proc/acpi/sleep interface? If suspend2 is a complete dropin replacement
> > then I'm much happier with the idea of dropping swsusp, but I don't want
> > to have to tie suspend/resume scripts to kernel versions.
> 
> I don't think that swsusp can be replaced with suspend2 right now.  First,
> swsusp works on x86-64, and the support in suspend2 is preliminary,
> AFAIK.  Second, the IA64 support for swsusp is in the works, and it is not supported
> by suspend2.
> 
> Please don't plan to drop swsusp until you are able to replace it _completely_.

Fair enough. I didn't realise Pavel had IA64 support too :>

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [46/48] Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch
  2005-07-07 21:16     ` Nigel Cunningham
@ 2005-07-07 21:26       ` nickpiggin
  2005-07-08 13:42         ` Nigel Cunningham
  2005-07-08  5:49       ` Pekka J Enberg
  2005-07-08  5:53       ` Pekka J Enberg
  2 siblings, 1 reply; 187+ messages in thread
From: nickpiggin @ 2005-07-07 21:26 UTC (permalink / raw)
  To: linux-kernel, ncunningham; +Cc: Pekka Enberg

On Fri, 8 Jul 2005 07:16 am, Nigel Cunningham wrote:

Hi,

> > > +struct io_info {
> > > +       struct bio * sys_struct;
> > > +       long block[PAGE_SIZE/512];
> >
> > Aah, but for this you should use block_size(io_info->dev) instead. No
> > need to mess with sector sizes. Why is this long by the way?
> > PAGE_SIZE/512 is block size in bytes.
>
> No...  it's the maximum number of blocks per page. Depending upon how
> the user has set the blocksize when they created the filesystem (in the
> case of filesystems), the number of blocks we use per page might be 1,
> 2, 4 or 8.
>

MAX_BUF_PER_PAGE

> It's long because a sector number is stored in it.
>

sector_t?

Nick

Send instant messages to your online friends http://au.messenger.yahoo.com 

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch
  2005-07-07 21:16     ` Nigel Cunningham
  2005-07-07 21:26       ` nickpiggin
@ 2005-07-08  5:49       ` Pekka J Enberg
  2005-07-08  5:53       ` Pekka J Enberg
  2 siblings, 0 replies; 187+ messages in thread
From: Pekka J Enberg @ 2005-07-08  5:49 UTC (permalink / raw)
  To: ncunningham; +Cc: Linux Kernel Mailing List

Nigel Cunningham writes:
> No...  it's the maximum number of blocks per page. Depending upon how
> the user has set the blocksize when they created the filesystem (in the
> case of filesystems), the number of blocks we use per page might be 1,
> 2, 4 or 8.

Yes. Sorry about that. I don't know what I was smoking. (But it must have 
been the good stuff (-:.) 

       Pekka 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch
  2005-07-07 21:16     ` Nigel Cunningham
  2005-07-07 21:26       ` nickpiggin
  2005-07-08  5:49       ` Pekka J Enberg
@ 2005-07-08  5:53       ` Pekka J Enberg
  2 siblings, 0 replies; 187+ messages in thread
From: Pekka J Enberg @ 2005-07-08  5:53 UTC (permalink / raw)
  To: ncunningham; +Cc: Linux Kernel Mailing List

On Thu, 2005-07-07 at 23:32, Pekka Enberg wrote:
> > > @@ -0,0 +1,817 @@
> > > +struct io_info {
> > > +       struct bio * sys_struct;
> > > +       long block[PAGE_SIZE/512];

Nigel Cunningham writes:
> No...  it's the maximum number of blocks per page. Depending upon how
> the user has set the blocksize when they created the filesystem (in the
> case of filesystems), the number of blocks we use per page might be 1,
> 2, 4 or 8. 
> 
> It's long because a sector number is stored in it.

The field block wants a better name. block_sectors, perhaps? 

                Pekka 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-07 12:49         ` Matthew Garrett
  2005-07-07 12:56           ` Nigel Cunningham
  2005-07-07 18:54           ` Rafael J. Wysocki
@ 2005-07-08 13:30           ` Stefan Seyfried
  2005-07-08 22:27             ` Nigel Cunningham
  2 siblings, 1 reply; 187+ messages in thread
From: Stefan Seyfried @ 2005-07-08 13:30 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: linux-kernel, ncunningham

Matthew Garrett wrote:

> Right, so you support the resume from disk trigger in sysfs and the
> /proc/acpi/sleep interface? If suspend2 is a complete dropin replacement
> then I'm much happier with the idea of dropping swsusp, but I don't want
> to have to tie suspend/resume scripts to kernel versions.

JFTR: i second this. There is already enough hackery involved if one
wants to provide a smooth user experience ;-)
-- 
Stefan Seyfried                  \ "I didn't want to write for pay. I
QA / R&D Team Mobile Devices      \ wanted to be paid for what I write."
SUSE LINUX Products GmbH, Nürnberg \                    -- Leonard Cohen


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch
  2005-07-07 13:05       ` Pekka J Enberg
@ 2005-07-08 13:41         ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-08 13:41 UTC (permalink / raw)
  To: Pekka J Enberg; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Thu, 2005-07-07 at 23:05, Pekka J Enberg wrote:
> Hi Nigel, 
> 
> On Wed, 2005-07-06 at 16:33, Pekka Enberg wrote:
> > > You're hardcoding sector size here, no?
> 
> Nigel Cunningham writes:
> > As others do.
> 
> Even so, please use a constant. 

Done
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [46/48] Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch
  2005-07-07 21:26       ` nickpiggin
@ 2005-07-08 13:42         ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-08 13:42 UTC (permalink / raw)
  To: nickpiggin; +Cc: Linux Kernel Mailing List, Pekka Enberg

Hi.

On Fri, 2005-07-08 at 07:26, nickpiggin@yahoo.com.au wrote:
> On Fri, 8 Jul 2005 07:16 am, Nigel Cunningham wrote:
> 
> Hi,
> 
> > > > +struct io_info {
> > > > +       struct bio * sys_struct;
> > > > +       long block[PAGE_SIZE/512];
> > >
> > > Aah, but for this you should use block_size(io_info->dev) instead. No
> > > need to mess with sector sizes. Why is this long by the way?
> > > PAGE_SIZE/512 is block size in bytes.
> >
> > No...  it's the maximum number of blocks per page. Depending upon how
> > the user has set the blocksize when they created the filesystem (in the
> > case of filesystems), the number of blocks we use per page might be 1,
> > 2, 4 or 8.
> >
> 
> MAX_BUF_PER_PAGE
> 
> > It's long because a sector number is stored in it.
> >
> 
> sector_t?

Fixed. Ta.

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-08 13:30           ` Stefan Seyfried
@ 2005-07-08 22:27             ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-08 22:27 UTC (permalink / raw)
  To: Stefan Seyfried; +Cc: Matthew Garrett, Linux Kernel Mailing List

Hi.

On Fri, 2005-07-08 at 23:30, Stefan Seyfried wrote:
> Matthew Garrett wrote:
> 
> > Right, so you support the resume from disk trigger in sysfs and the
> > /proc/acpi/sleep interface? If suspend2 is a complete dropin replacement
> > then I'm much happier with the idea of dropping swsusp, but I don't want
> > to have to tie suspend/resume scripts to kernel versions.
> 
> JFTR: i second this. There is already enough hackery involved if one
> wants to provide a smooth user experience ;-)

Consider it promised, and feel free to poke me if I forget! (That said,
I won't now!).

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [9/48] Suspend2 2.1.9.8 for 2.6.12: 354-disable-mce-checking-during-suspend-avoid-smp-deadlock.patch
  2005-07-06  2:20 ` [PATCH] [9/48] Suspend2 2.1.9.8 for 2.6.12: 354-disable-mce-checking-during-suspend-avoid-smp-deadlock.patch Nigel Cunningham
@ 2005-07-09 11:49   ` Pavel Machek
  2005-07-09 12:02     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-09 11:49 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> 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
> --- 360-reset-kswapd-max-order-after-resume.patch-old/mm/vmscan.c	2005-07-06 11:18:05.000000000 +1000
> +++ 360-reset-kswapd-max-order-after-resume.patch-new/mm/vmscan.c	2005-07-04 23:14:20.000000000 +1000
> @@ -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

-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [18/48] Suspend2 2.1.9.8 for 2.6.12: 501-tlb-flushing-functions.patch
  2005-07-06  2:20 ` [PATCH] [18/48] Suspend2 2.1.9.8 for 2.6.12: 501-tlb-flushing-functions.patch Nigel Cunningham
@ 2005-07-09 11:52   ` Pavel Machek
  0 siblings, 0 replies; 187+ messages in thread
From: Pavel Machek @ 2005-07-09 11:52 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!


> 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
> --- 510-version-specific-mac.patch-old/arch/ppc/platforms/pmac_feature.c	2005-06-20 11:46:45.000000000 +1000
> +++ 510-version-specific-mac.patch-new/arch/ppc/platforms/pmac_feature.c	2005-07-04 23:14:19.000000000 +1000
> @@ -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?



> 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
> --- 510-version-specific-mac.patch-old/arch/ppc/syslib/of_device.c	2004-11-03 21:55:03.000000000 +1100
> +++ 510-version-specific-mac.patch-new/arch/ppc/syslib/of_device.c	2005-07-04 23:14:19.000000000 +1000
> @@ -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?

> diff -ruNp 510-version-specific-mac.patch-old/drivers/macintosh/via-pmu.c 510-version-specific-mac.patch-new/drivers/macintosh/via-pmu.c
> --- 510-version-specific-mac.patch-old/drivers/macintosh/via-pmu.c	2005-07-06 11:25:14.000000000 +1000
> +++ 510-version-specific-mac.patch-new/drivers/macintosh/via-pmu.c	2005-07-04 23:14:19.000000000 +1000
> @@ -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:

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

									Pavel

-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [26/48] Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch
  2005-07-06  2:20 ` [PATCH] [26/48] Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch Nigel Cunningham
  2005-07-06 10:22   ` Pekka Enberg
@ 2005-07-09 11:53   ` Pavel Machek
  1 sibling, 0 replies; 187+ messages in thread
From: Pavel Machek @ 2005-07-09 11:53 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> diff -ruNp 604-utility-header.patch-old/kernel/power/suspend2_core/utility.c 604-utility-header.patch-new/kernel/power/suspend2_core/utility.c
> --- 604-utility-header.patch-old/kernel/power/suspend2_core/utility.c	1970-01-01 10:00:00.000000000 +1000
> +++ 604-utility-header.patch-new/kernel/power/suspend2_core/utility.c	2005-07-05 23:48:59.000000000 +1000
> @@ -0,0 +1,46 @@
> +/*
> + * kernel/power/utility.c
> + *
> + * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
> + * 
> + * 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;
> +}

Eh, this needs to be either generic function or not there at all.
										Pavel
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [31/48] Suspend2 2.1.9.8 for 2.6.12: 608-compression.patch
  2005-07-06  2:20 ` [PATCH] [31/48] Suspend2 2.1.9.8 for 2.6.12: 608-compression.patch Nigel Cunningham
@ 2005-07-09 11:55   ` Pavel Machek
  2005-07-09 12:15     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-09 11:55 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> 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
> --- 609-driver-model.patch-old/kernel/power/suspend2_core/driver_model.c	1970-01-01 10:00:00.000000000 +1000
> +++ 609-driver-model.patch-new/kernel/power/suspend2_core/driver_model.c	2005-07-04 23:14:19.000000000 +1000
> @@ -0,0 +1,95 @@
> +/*
> + * kernel/power/suspend2_core/driver_model.c
> + *
> + * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
> + *
> + * 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;
> +}

That seems like quite an ugly hack.

> +/* 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;
> +}

Can't you just inline these?

-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [9/48] Suspend2 2.1.9.8 for 2.6.12: 354-disable-mce-checking-during-suspend-avoid-smp-deadlock.patch
  2005-07-09 11:49   ` Pavel Machek
@ 2005-07-09 12:02     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-09 12:02 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Sat, 2005-07-09 at 21:49, Pavel Machek wrote:
> Hi!
> 
> > 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
> > --- 360-reset-kswapd-max-order-after-resume.patch-old/mm/vmscan.c	2005-07-06 11:18:05.000000000 +1000
> > +++ 360-reset-kswapd-max-order-after-resume.patch-new/mm/vmscan.c	2005-07-04 23:14:20.000000000 +1000
> > @@ -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;
> 
> ?

I have no idea. Fixed. Thanks!

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [48/48] Suspend2 2.1.9.8 for 2.6.12: 624-filewriter.patch
  2005-07-06  2:20 ` [PATCH] [48/48] Suspend2 2.1.9.8 for 2.6.12: 624-filewriter.patch Nigel Cunningham
  2005-07-06 10:07   ` Pekka Enberg
@ 2005-07-09 12:10   ` Pavel Machek
  2005-07-09 12:18     ` Nigel Cunningham
  2005-07-10 23:14   ` Christoph Hellwig
  2 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-09 12:10 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> +/*
> + * sacrifice some compression quality in favour of compression speed.
> + * (roughly 1-2% worse compression for large blocks and
> + * 9-10% for small, redundant, blocks and >>20% better speed in both cases)
> + * In short: enable this for binary data, disable this for text data.
> + */
> +#define ULTRA_FAST 1
> +
> +#define STRICT_ALIGN 0
> +#define USE_MEMCPY 1
> +#define INIT_HTAB 0

Ugly, ugly, ugly. Pick one set of options and use them.

> +/*
> + * don't play with this unless you benchmark!
> + * decompression is not dependent on the hash function
> + * the hashing function might seem strange, just believe me
> + * it works ;)
> + */
> +#define FRST(p) (((p[0]) << 8) + p[1])
> +#define NEXT(v,p) (((v) << 8) + p[2])

Dnt wrt mcr nms lk ths!

> +	if (ctx->first_call) {
> +		ctx->first_call = 0;
> +	}
> +#if INIT_HTAB
> +# if USE_MEMCPY
> +    memset (htab, 0, sizeof (htab));
> +# else
> +    for (hslot = htab; hslot < htab + HSIZE; hslot++)
> +      *hslot++ = ip;
> +# endif
> +#endif


Eh? Use_memcpy and then it memsets?

BTW if it is "contributed code", you may want original contributor to
push it, so that you don't have to do all the lindenting/cleaning/etc
yourself.

								Pavel
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [31/48] Suspend2 2.1.9.8 for 2.6.12: 608-compression.patch
  2005-07-09 11:55   ` Pavel Machek
@ 2005-07-09 12:15     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-09 12:15 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Howdy.

On Sat, 2005-07-09 at 21:55, Pavel Machek wrote:
> Hi!
> 
> > 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
> > --- 609-driver-model.patch-old/kernel/power/suspend2_core/driver_model.c	1970-01-01 10:00:00.000000000 +1000
> > +++ 609-driver-model.patch-new/kernel/power/suspend2_core/driver_model.c	2005-07-04 23:14:19.000000000 +1000
> > @@ -0,0 +1,95 @@
> > +/*
> > + * kernel/power/suspend2_core/driver_model.c
> > + *
> > + * Copyright (C) 2004-2005 Nigel Cunningham <nigel@suspend2.net>
> > + *
> > + * 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;
> > +}
> 
> 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.

> > +/* 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;
> > +}
> 
> Can't you just inline these?

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

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [37/48] Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch
  2005-07-06  2:20 ` [PATCH] [37/48] Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch Nigel Cunningham
  2005-07-06 12:01   ` Pekka Enberg
@ 2005-07-09 12:16   ` Pavel Machek
  2005-07-09 12:32     ` Nigel Cunningham
  1 sibling, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-09 12:16 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

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.

> +/*
> + * 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;
> +}

Why the cast and why long in the first place?

> +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
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [48/48] Suspend2 2.1.9.8 for 2.6.12: 624-filewriter.patch
  2005-07-09 12:10   ` [PATCH] [48/48] " Pavel Machek
@ 2005-07-09 12:18     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-09 12:18 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Howdy.

On Sat, 2005-07-09 at 22:10, Pavel Machek wrote:
> BTW if it is "contributed code", you may want original contributor to
> push it, so that you don't have to do all the lindenting/cleaning/etc
> yourself.

It is, and he's gone to ground. As requested by Pekka, I've Lindented
it. Apart from that, I didn't really want to touch it for fear of
breaking it :> Then again, I felt like that with suspend code at one
stage!

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [37/48] Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch
  2005-07-09 12:16   ` Pavel Machek
@ 2005-07-09 12:32     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-09 12:32 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Sat, 2005-07-09 at 22:16, Pavel Machek wrote:
> 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.
> 
> > +/*
> > + * 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;
> > +}
> 
> 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.

> > +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?

There would only be half a dozen tops.

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [28/48] Suspend2 2.1.9.8 for 2.6.12: 605-kernel_power_suspend.patch
  2005-07-06  2:20 ` [PATCH] [28/48] Suspend2 2.1.9.8 for 2.6.12: 605-kernel_power_suspend.patch Nigel Cunningham
@ 2005-07-10 17:58   ` Pavel Machek
  2005-07-12  8:39     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-10 17:58 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> 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
> --- 606-all-settings.patch-old/kernel/power/suspend2_core/all_settings.c	1970-01-01 10:00:00.000000000 +1000
> +++ 606-all-settings.patch-new/kernel/power/suspend2_core/all_settings.c	2005-07-04 23:14:19.000000000 +1000
> @@ -0,0 +1,325 @@
> +/*
> + * /kernel/power/suspend2_core/all_settings.c
> + *
> + * Suspend2 is released under the GPLv2.
> + * 
> + * Copyright (C) 2002-2005 Nigel Cunningham <nigel@suspend2.net>
> + *
> + * 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.
> + */

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

-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [30/48] Suspend2 2.1.9.8 for 2.6.12: 607-atomic-copy.patch
  2005-07-06  2:20 ` [PATCH] [30/48] Suspend2 2.1.9.8 for 2.6.12: 607-atomic-copy.patch Nigel Cunningham
@ 2005-07-10 18:01   ` Pavel Machek
  2005-07-11  8:58     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-10 18:01 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> --- 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
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [29/48] Suspend2 2.1.9.8 for 2.6.12: 606-all-settings.patch
  2005-07-06  2:20 ` [PATCH] [29/48] Suspend2 2.1.9.8 for 2.6.12: 606-all-settings.patch Nigel Cunningham
@ 2005-07-10 18:03   ` Pavel Machek
  2005-07-11  9:38     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-10 18:03 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> +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
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [38/48] Suspend2 2.1.9.8 for 2.6.12: 614-plugins.patch
  2005-07-06  2:20 ` [PATCH] [38/48] Suspend2 2.1.9.8 for 2.6.12: 614-plugins.patch Nigel Cunningham
@ 2005-07-10 18:08   ` Pavel Machek
  2005-07-11 10:05     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-10 18:08 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

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

Constants.....

> +	if (suspend2_powerdown_method == 3 ||
> +	    suspend2_powerdown_method == 4)

Constants...

> +	if (suspend2_powerdown_method == 3 ||
> +	    suspend2_powerdown_method == 4)

Constants...

> +		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
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [35/48] Suspend2 2.1.9.8 for 2.6.12: 611-io.patch
  2005-07-06  2:20 ` [PATCH] [35/48] Suspend2 2.1.9.8 for 2.6.12: 611-io.patch Nigel Cunningham
@ 2005-07-10 18:12   ` Pavel Machek
  2005-07-12  8:38     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-10 18:12 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> +	//p->pageset_size = pageset_size;

Please don't leave commented code in.

> +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);
> +}

Can you just replace it in callers?

> +#define pageset1_size (pagedir1.pageset_size)
> +#define pageset2_size (pagedir2.pageset_size)

This only makes reading code harder...

							Pavel
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [40/48] Suspend2 2.1.9.8 for 2.6.12: 616-prepare_image.patch
  2005-07-06  2:20 ` [PATCH] [40/48] Suspend2 2.1.9.8 for 2.6.12: 616-prepare_image.patch Nigel Cunningham
@ 2005-07-10 18:13   ` Pavel Machek
  2005-07-12  8:34     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-10 18:13 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> diff -ruNp 617-proc.patch-old/kernel/power/suspend2_core/proc.c 617-proc.patch-new/kernel/power/suspend2_core/proc.c
> --- 617-proc.patch-old/kernel/power/suspend2_core/proc.c	1970-01-01 10:00:00.000000000 +1000
> +++ 617-proc.patch-new/kernel/power/suspend2_core/proc.c	2005-07-04 23:14:19.000000000 +1000
> @@ -0,0 +1,336 @@
> +/*
> + * /kernel/power/proc.c
> + *
> + * Copyright (C) 2002-2005 Nigel Cunningham <nigel@suspend2.net>
> + *
> + * 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.

Pretty please, can we support just one version?
										Pavel
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [33/48] Suspend2 2.1.9.8 for 2.6.12: 610-encryption.patch
  2005-07-06  2:20 ` [PATCH] [33/48] Suspend2 2.1.9.8 for 2.6.12: 610-encryption.patch Nigel Cunningham
@ 2005-07-10 18:15   ` Pavel Machek
  2005-07-12  8:34     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-10 18:15 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> +/*
> + * put_extent_chain.
> + *
> + * Frees a whole chain of extents.
> + */
> +void put_extent_chain(struct extentchain * chain)

This probably should be extent_chain.

> +#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
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [39/48] Suspend2 2.1.9.8 for 2.6.12: 615-poweroff.patch
  2005-07-06  2:20 ` [PATCH] [39/48] Suspend2 2.1.9.8 for 2.6.12: 615-poweroff.patch Nigel Cunningham
@ 2005-07-10 18:18   ` Pavel Machek
  2005-07-12  8:31     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-10 18:18 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> @@ -0,0 +1,585 @@
> +/*
> + * kernel/power/prepare_image.c
> + *
> + * Copyright (C) 2003-2005 Nigel Cunningham <nigel@suspend.net>
> + *
> + * 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)
> + */

Can you just fix/use shrink_all_memory().

> +#define EATEN_ENOUGH_MEMORY() (amount_needed(1) < 1)

Hmm...

> +static int arefrozen = 0, numnosave = 0;

Missing _s.

> +/* 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

Is this kind of debugging neccessary any more?

> +#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))
> +
> +#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
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [42/48] Suspend2 2.1.9.8 for 2.6.12: 618-core.patch
  2005-07-06  2:20 ` [PATCH] [42/48] Suspend2 2.1.9.8 for 2.6.12: 618-core.patch Nigel Cunningham
@ 2005-07-10 18:21   ` Pavel Machek
  2005-07-12  6:59     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-10 18:21 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

Have you seen Christoph's recent fixes to refrigerator? You probably
have same problems..... And he wanted to move refrigerator to sched/
and make it more generic for page migration, too... what about using
it, too? ;-).
								Pavel
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [44/48] Suspend2 2.1.9.8 for 2.6.12: 620-userui.patch
  2005-07-06  2:20 ` [PATCH] [44/48] Suspend2 2.1.9.8 for 2.6.12: 620-userui.patch Nigel Cunningham
@ 2005-07-10 18:22   ` Pavel Machek
  2005-07-12  6:58     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-10 18:22 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

On St 06-07-05 12:20:44, Nigel Cunningham wrote:
> diff -ruNp 621-swsusp-tidy.patch-old/kernel/power/swsusp.c 621-swsusp-tidy.patch-new/kernel/power/swsusp.c
> --- 621-swsusp-tidy.patch-old/kernel/power/swsusp.c	2005-06-20 11:47:31.000000000 +1000
> +++ 621-swsusp-tidy.patch-new/kernel/power/swsusp.c	2005-07-04 23:14:19.000000000 +1000
> @@ -36,6 +36,8 @@
>   * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt
>   */
>  
> +#define KERNEL_POWER_SWSUSP_C

Headers that change depending on #define's are considered evil......

								Pavel

-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [47/48] Suspend2 2.1.9.8 for 2.6.12: 623-generic-block-io.patch
  2005-07-06  2:20 ` [PATCH] [47/48] Suspend2 2.1.9.8 for 2.6.12: 623-generic-block-io.patch Nigel Cunningham
@ 2005-07-10 18:24   ` Pavel Machek
  0 siblings, 0 replies; 187+ messages in thread
From: Pavel Machek @ 2005-07-10 18:24 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> +static int target_type = -1;
> +
> +/*
> +static char * description[7] = {
> +	"Socket",
> +	"Link",
> +	"Regular file",
> +	"Block device",
> +	"Directory",
> +	"Character device",
> +	"Fifo",
> +};
> +*/
> +
...
> +/*
> + *		Helpers.
> + */
> +
> +/* 
> + * Return the type of target we have, an index into the descriptions
> + * above.
> + */
> +static int get_target_type(struct inode * inode)
> +{
> +	switch (inode->i_mode & S_IFMT) {
> +		case S_IFSOCK:
> +			target_type = 0;
> +			break;
> +		case S_IFLNK:
> +			target_type = 1;
> +			break;
> +		case S_IFREG:
> +			target_type = 2;
> +			break;
> +		case S_IFBLK:
> +			target_type = 3;
> +			break;
> +		case S_IFDIR:
> +			target_type = 4;
> +			break;
> +		case S_IFCHR:
> +			target_type = 5;
> +			break;
> +		case S_IFIFO:
> +			target_type = 6;
> +			break;
> +	}
> +	return target_type;
> +}
> +	
> +#define target_is_usable (!(target_type == 1 || target_type == 4))
> +#define target_num_sectors (target_inode->i_size >> target_blkbits)

Why do you need this?
								Pavel

-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [13/48] Suspend2 2.1.9.8 for 2.6.12: 403-debug-pagealloc-support.patch
  2005-07-06  2:20 ` [PATCH] [13/48] Suspend2 2.1.9.8 for 2.6.12: 403-debug-pagealloc-support.patch Nigel Cunningham
@ 2005-07-10 23:02   ` Christoph Hellwig
  2005-07-12  6:48     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Christoph Hellwig @ 2005-07-10 23:02 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

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.


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch
  2005-07-06  2:20 ` [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch Nigel Cunningham
@ 2005-07-10 23:03   ` Christoph Hellwig
  2005-07-12  6:45     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Christoph Hellwig @ 2005-07-10 23:03 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

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.


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch
  2005-07-06  2:20 ` [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch Nigel Cunningham
@ 2005-07-10 23:04   ` Christoph Hellwig
  2005-07-12  6:40     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Christoph Hellwig @ 2005-07-10 23:04 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Again, why do you think you need this?


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
                   ` (50 preceding siblings ...)
  2005-07-06  8:22 ` Pavel Machek
@ 2005-07-10 23:06 ` Christoph Hellwig
  2005-07-12  6:36   ` Nigel Cunningham
  51 siblings, 1 reply; 187+ messages in thread
From: Christoph Hellwig @ 2005-07-10 23:06 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

This submissions is completely useless.  48 patches without description
and a subbject lines that hides the little information even more.

Please start again, and only with useful patches that on their own,
against -mm and with detailed explanations of each patch.


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [12/48] Suspend2 2.1.9.8 for 2.6.12: 402-mtrr-remove-sysdev.patch
  2005-07-06  2:20 ` [PATCH] [12/48] Suspend2 2.1.9.8 for 2.6.12: 402-mtrr-remove-sysdev.patch Nigel Cunningham
@ 2005-07-10 23:07   ` Christoph Hellwig
  2005-07-12  6:33     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Christoph Hellwig @ 2005-07-10 23:07 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch
  2005-07-06  2:20 ` [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch Nigel Cunningham
                     ` (2 preceding siblings ...)
  2005-07-06  9:52   ` Russell King
@ 2005-07-10 23:07   ` Christoph Hellwig
  3 siblings, 0 replies; 187+ messages in thread
From: Christoph Hellwig @ 2005-07-10 23:07 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

no explanation and even the subject doesn't match patch contents..


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [10/48] Suspend2 2.1.9.8 for 2.6.12: 360-reset-kswapd-max-order-after-resume.patch
  2005-07-06  2:20 ` [PATCH] [10/48] Suspend2 2.1.9.8 for 2.6.12: 360-reset-kswapd-max-order-after-resume.patch Nigel Cunningham
@ 2005-07-10 23:09   ` Christoph Hellwig
  2005-07-12  9:05     ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Christoph Hellwig @ 2005-07-10 23:09 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

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


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [48/48] Suspend2 2.1.9.8 for 2.6.12: 624-filewriter.patch
  2005-07-06  2:20 ` [PATCH] [48/48] Suspend2 2.1.9.8 for 2.6.12: 624-filewriter.patch Nigel Cunningham
  2005-07-06 10:07   ` Pekka Enberg
  2005-07-09 12:10   ` [PATCH] [48/48] " Pavel Machek
@ 2005-07-10 23:14   ` Christoph Hellwig
  2005-07-12  6:30     ` Nigel Cunningham
  2 siblings, 1 reply; 187+ messages in thread
From: Christoph Hellwig @ 2005-07-10 23:14 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Please send new crytptoapi algorithms to the cryptoapi maintainers for review.
It's something that's completely independent of any software suspend stuff.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [43/48] Suspend2 2.1.9.8 for 2.6.12: 619-userspace-nofreeze.patch
  2005-07-06  2:20 ` [PATCH] [43/48] Suspend2 2.1.9.8 for 2.6.12: 619-userspace-nofreeze.patch Nigel Cunningham
  2005-07-06  6:18   ` Pekka Enberg
@ 2005-07-10 23:15   ` Christoph Hellwig
  2005-07-12  6:29     ` Nigel Cunningham
  1 sibling, 1 reply; 187+ messages in thread
From: Christoph Hellwig @ 2005-07-10 23:15 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

UI support is nothing that belongs here.  People won't die by having a text console for
a while.


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [30/48] Suspend2 2.1.9.8 for 2.6.12: 607-atomic-copy.patch
  2005-07-10 18:01   ` Pavel Machek
@ 2005-07-11  8:58     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-11  8:58 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 04:01, Pavel Machek wrote:
> Hi!
> 
> > --- 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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [29/48] Suspend2 2.1.9.8 for 2.6.12: 606-all-settings.patch
  2005-07-10 18:03   ` Pavel Machek
@ 2005-07-11  9:38     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-11  9:38 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 04:03, Pavel Machek wrote:
> Hi!
> 
> > +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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [38/48] Suspend2 2.1.9.8 for 2.6.12: 614-plugins.patch
  2005-07-10 18:08   ` Pavel Machek
@ 2005-07-11 10:05     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-11 10:05 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 04:08, Pavel Machek wrote:
> Hi!
> 
> > +unsigned long suspend2_powerdown_method = 5; /* S5 = off */
> 
> Constants.....
> 
> > +	if (suspend2_powerdown_method == 3 ||
> > +	    suspend2_powerdown_method == 4)
> 
> Constants...
> 
> > +	if (suspend2_powerdown_method == 3 ||
> > +	    suspend2_powerdown_method == 4)
> 
> Constants...

Once per file is enough :>

> > +		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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [43/48] Suspend2 2.1.9.8 for 2.6.12: 619-userspace-nofreeze.patch
  2005-07-10 23:15   ` Christoph Hellwig
@ 2005-07-12  6:29     ` Nigel Cunningham
  2005-07-12 14:21       ` Christoph Hellwig
  0 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  6:29 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 09:15, Christoph Hellwig wrote:
> UI support is nothing that belongs here.  People won't die by having a text console for
> a while.

UI support belongs here for the following reasons:

- While driver support is imperfect, there is the potential for hangs.
People need to be able to recognise when this happens. They therefore
need some feedback to know that the process is not hung, and to be able
to say where it hung when it does.
- Particularly for the desktop, we want the system to look professional,
not half baked.
- Some support is needed for the user to be able to cancel a suspend.
You might not want to. Others might not want to, but this doesn't mean
that others shouldn't have the option of changing their minds.

I have already moved much of the code out to userspace in an effort to
ease your concerns. I'm not going so far as to remove the functionality,
though.

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [48/48] Suspend2 2.1.9.8 for 2.6.12: 624-filewriter.patch
  2005-07-10 23:14   ` Christoph Hellwig
@ 2005-07-12  6:30     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  6:30 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 09:14, Christoph Hellwig wrote:
> Please send new crytptoapi algorithms to the cryptoapi maintainers for review.
> It's something that's completely independent of any software suspend stuff.

Thanks.

Did this about a week prior to sending the patches. Sorry - including
this in the patches posted was an oversight.

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [12/48] Suspend2 2.1.9.8 for 2.6.12: 402-mtrr-remove-sysdev.patch
  2005-07-10 23:07   ` Christoph Hellwig
@ 2005-07-12  6:33     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  6:33 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 09:07, Christoph Hellwig wrote:
> 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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-10 23:06 ` Christoph Hellwig
@ 2005-07-12  6:36   ` Nigel Cunningham
  2005-07-12  6:41     ` Andrew Morton
  0 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  6:36 UTC (permalink / raw)
  To: Christoph Hellwig, Andrew Morton; +Cc: Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 09:06, Christoph Hellwig wrote:
> This submissions is completely useless.  48 patches without description
> and a subbject lines that hides the little information even more.

Yes. My mistake with the subject lines. Sorry. I'll also add better
descriptions when I repost.

> Please start again, and only with useful patches that on their own,
> against -mm and with detailed explanations of each patch.

First I'll act on feedback from this round. Regarding diffing against
-mm, I though Andrew wanted patches against Linus' tree. I'm happy to do
both. Andrew?

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch
  2005-07-10 23:04   ` Christoph Hellwig
@ 2005-07-12  6:40     ` Nigel Cunningham
  2005-07-12 10:57       ` Pavel Machek
  0 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  6:40 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 09:04, Christoph Hellwig wrote:
> 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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-12  6:36   ` Nigel Cunningham
@ 2005-07-12  6:41     ` Andrew Morton
  2005-07-12  6:57       ` Nigel Cunningham
  2005-07-12 10:25       ` Nigel Cunningham
  0 siblings, 2 replies; 187+ messages in thread
From: Andrew Morton @ 2005-07-12  6:41 UTC (permalink / raw)
  To: ncunningham; +Cc: hch, linux-kernel

Nigel Cunningham <ncunningham@cyclades.com> wrote:
>
> First I'll act on feedback from this round. Regarding diffing against
>  -mm, I though Andrew wanted patches against Linus' tree. I'm happy to do
>  both. Andrew?

Is it anywhere near being ready?

Am still futzing with the ongoing pm_message_t saga here.  I hope there's
no overlap with that.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch
  2005-07-10 23:03   ` Christoph Hellwig
@ 2005-07-12  6:45     ` Nigel Cunningham
       [not found]       ` <E1DsHMp-00062f-00@chiark.greenend.org.uk>
  0 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  6:45 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 09:03, Christoph Hellwig wrote:
> 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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [13/48] Suspend2 2.1.9.8 for 2.6.12: 403-debug-pagealloc-support.patch
  2005-07-10 23:02   ` Christoph Hellwig
@ 2005-07-12  6:48     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  6:48 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 09:02, Christoph Hellwig wrote:
> 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 
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-12  6:41     ` Andrew Morton
@ 2005-07-12  6:57       ` Nigel Cunningham
  2005-07-12 10:25       ` Nigel Cunningham
  1 sibling, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  6:57 UTC (permalink / raw)
  To: Andrew Morton; +Cc: hch, Linux Kernel Mailing List

Hi.

On Tue, 2005-07-12 at 16:41, Andrew Morton wrote:
> Nigel Cunningham <ncunningham@cyclades.com> wrote:
> >
> > First I'll act on feedback from this round. Regarding diffing against
> >  -mm, I though Andrew wanted patches against Linus' tree. I'm happy to do
> >  both. Andrew?
> 
> Is it anywhere near being ready?

Yes. Development has almost stopped. I'm just addressing the responses
from last week's email and then will send again, so yes. Here's my todo
list (some done already):

Todo list as at 12 July 2005.

FIX.
- Check for redundant variables & functions and remove.
- Ensure driver model calls are right (Bug 45).
- NFS issue (Bug 52)

COMPLETE.
- Opteron support (Bug 1).
- Documentation cleanups.

IMPLEMENT.
- 64GB support.
- IA64 support.
- Implement remembering compression ratio acheived using another method
apart
  from LZF plugin.

HCH/Pavel Replies.
- Setting NoSave pages early.
- Amount needed parameter.
- Add underscores to variable names.
- Inline functions for image preparation (storage needed etc).
- Debugging code from extents.
- extenchain -> extent_chain

- Patch descriptions/rationales.
- Against mm.
- Remove #define XXX_C

> Am still futzing with the ongoing pm_message_t saga here.  I hope there's
> no overlap with that.

We've been using pm_message_t in Suspend2 since February, so we should
already be where you're heading.

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [44/48] Suspend2 2.1.9.8 for 2.6.12: 620-userui.patch
  2005-07-10 18:22   ` Pavel Machek
@ 2005-07-12  6:58     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  6:58 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi

On Mon, 2005-07-11 at 04:22, Pavel Machek wrote:
> On St 06-07-05 12:20:44, Nigel Cunningham wrote:
> > diff -ruNp 621-swsusp-tidy.patch-old/kernel/power/swsusp.c 621-swsusp-tidy.patch-new/kernel/power/swsusp.c
> > --- 621-swsusp-tidy.patch-old/kernel/power/swsusp.c	2005-06-20 11:47:31.000000000 +1000
> > +++ 621-swsusp-tidy.patch-new/kernel/power/swsusp.c	2005-07-04 23:14:19.000000000 +1000
> > @@ -36,6 +36,8 @@
> >   * For TODOs,FIXMEs also look in Documentation/power/swsusp.txt
> >   */
> >  
> > +#define KERNEL_POWER_SWSUSP_C
> 
> Headers that change depending on #define's are considered evil......

Fixed. Thanks!

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [42/48] Suspend2 2.1.9.8 for 2.6.12: 618-core.patch
  2005-07-10 18:21   ` Pavel Machek
@ 2005-07-12  6:59     ` Nigel Cunningham
  2005-07-12  7:56       ` Pavel Machek
  0 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  6:59 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 04:21, Pavel Machek wrote:
> Hi!
> 
> Have you seen Christoph's recent fixes to refrigerator? You probably
> have same problems..... And he wanted to move refrigerator to sched/
> and make it more generic for page migration, too... what about using
> it, too? ;-).

Yeah. I'm using them already. I must say though that I don't think
sched.h is necessarily the best place for the refrigerator defines. Any
change to those functions and you have to recompile most of the kernel.
Is a refrigerator.h an idea?

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [42/48] Suspend2 2.1.9.8 for 2.6.12: 618-core.patch
  2005-07-12  6:59     ` Nigel Cunningham
@ 2005-07-12  7:56       ` Pavel Machek
  0 siblings, 0 replies; 187+ messages in thread
From: Pavel Machek @ 2005-07-12  7:56 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux Kernel Mailing List

Hi!

> > Have you seen Christoph's recent fixes to refrigerator? You probably
> > have same problems..... And he wanted to move refrigerator to sched/
> > and make it more generic for page migration, too... what about using
> > it, too? ;-).
> 
> Yeah. I'm using them already. I must say though that I don't think
> sched.h is necessarily the best place for the refrigerator defines. Any
> change to those functions and you have to recompile most of the kernel.
> Is a refrigerator.h an idea?

I do not think those recompiles pose a big problem; we don't want
million separate headers. I'd trust Christoph with this.
								Pavel
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [39/48] Suspend2 2.1.9.8 for 2.6.12: 615-poweroff.patch
  2005-07-10 18:18   ` Pavel Machek
@ 2005-07-12  8:31     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  8:31 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 04:18, Pavel Machek wrote:
> Hi!
> 
> > @@ -0,0 +1,585 @@
> > +/*
> > + * kernel/power/prepare_image.c
> > + *
> > + * Copyright (C) 2003-2005 Nigel Cunningham <nigel@suspend.net>
> > + *
> > + * 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)
> > + */
> 
> 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).

> > +#define EATEN_ENOUGH_MEMORY() (amount_needed(1) < 1)
> 
> Hmm...
> 
> > +static int arefrozen = 0, numnosave = 0;
> 
> Missing _s.

Fixed. Thanks.

> > +/* 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
> 
> Is this kind of debugging neccessary any more?

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

> > +#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))
> > +
> > +#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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [33/48] Suspend2 2.1.9.8 for 2.6.12: 610-encryption.patch
  2005-07-10 18:15   ` Pavel Machek
@ 2005-07-12  8:34     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  8:34 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux Kernel Mailing List

'ello!

On Mon, 2005-07-11 at 04:15, Pavel Machek wrote:
> Hi!
> 
> > +/*
> > + * put_extent_chain.
> > + *
> > + * Frees a whole chain of extents.
> > + */
> > +void put_extent_chain(struct extentchain * chain)
> 
> This probably should be extent_chain.
> 
> > +#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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [40/48] Suspend2 2.1.9.8 for 2.6.12: 616-prepare_image.patch
  2005-07-10 18:13   ` Pavel Machek
@ 2005-07-12  8:34     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  8:34 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 04:13, Pavel Machek wrote:
> Hi!
> 
> > diff -ruNp 617-proc.patch-old/kernel/power/suspend2_core/proc.c 617-proc.patch-new/kernel/power/suspend2_core/proc.c
> > --- 617-proc.patch-old/kernel/power/suspend2_core/proc.c	1970-01-01 10:00:00.000000000 +1000
> > +++ 617-proc.patch-new/kernel/power/suspend2_core/proc.c	2005-07-04 23:14:19.000000000 +1000
> > @@ -0,0 +1,336 @@
> > +/*
> > + * /kernel/power/proc.c
> > + *
> > + * Copyright (C) 2002-2005 Nigel Cunningham <nigel@suspend2.net>
> > + *
> > + * 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.
> 
> 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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [35/48] Suspend2 2.1.9.8 for 2.6.12: 611-io.patch
  2005-07-10 18:12   ` Pavel Machek
@ 2005-07-12  8:38     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  8:38 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 04:12, Pavel Machek wrote:
> Hi!
> 
> > +	//p->pageset_size = pageset_size;
> 
> Please don't leave commented code in.

Fixed.

> > +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);
> > +}
> 
> Can you just replace it in callers?

Done.

> > +#define pageset1_size (pagedir1.pageset_size)
> > +#define pageset2_size (pagedir2.pageset_size)
> 
> This only makes reading code harder...

Removed.

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [28/48] Suspend2 2.1.9.8 for 2.6.12: 605-kernel_power_suspend.patch
  2005-07-10 17:58   ` Pavel Machek
@ 2005-07-12  8:39     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  8:39 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Mon, 2005-07-11 at 03:58, Pavel Machek wrote:
> Hi!
> 
> > 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
> > --- 606-all-settings.patch-old/kernel/power/suspend2_core/all_settings.c	1970-01-01 10:00:00.000000000 +1000
> > +++ 606-all-settings.patch-new/kernel/power/suspend2_core/all_settings.c	2005-07-04 23:14:19.000000000 +1000

[...]

> > + * 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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [10/48] Suspend2 2.1.9.8 for 2.6.12: 360-reset-kswapd-max-order-after-resume.patch
  2005-07-10 23:09   ` Christoph Hellwig
@ 2005-07-12  9:05     ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12  9:05 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Linux Kernel Mailing List

On Mon, 2005-07-11 at 09:09, Christoph Hellwig wrote:
> 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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch
       [not found]       ` <E1DsHMp-00062f-00@chiark.greenend.org.uk>
@ 2005-07-12 10:07         ` Nigel Cunningham
  2005-07-12 10:22           ` Matthew Garrett
  0 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12 10:07 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Christoph Hellwig, Linux Kernel Mailing List

Hi.

On Tue, 2005-07-12 at 19:47, Matthew Garrett wrote:
> Nigel Cunningham <ncunningham@cyclades.com> wrote:
> 
> > 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.

> > 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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch
  2005-07-12 10:07         ` Nigel Cunningham
@ 2005-07-12 10:22           ` Matthew Garrett
  2005-07-12 10:34             ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Matthew Garrett @ 2005-07-12 10:22 UTC (permalink / raw)
  To: ncunningham; +Cc: Christoph Hellwig, Linux Kernel Mailing List

Nigel Cunningham <ncunningham@cyclades.com> wrote:
> On Tue, 2005-07-12 at 19:47, Matthew Garrett wrote:
>> 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.
 
> 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.
-- 
Matthew Garrett | mjg59-chiark.mail.linux-rutgers.kernel@srcf.ucam.org

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [0/48] Suspend2 2.1.9.8 for 2.6.12
  2005-07-12  6:41     ` Andrew Morton
  2005-07-12  6:57       ` Nigel Cunningham
@ 2005-07-12 10:25       ` Nigel Cunningham
  1 sibling, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12 10:25 UTC (permalink / raw)
  To: Andrew Morton; +Cc: hch, Linux Kernel Mailing List

Hi.

On Tue, 2005-07-12 at 16:41, Andrew Morton wrote:
> Am still futzing with the ongoing pm_message_t saga here.  I hope there's
> no overlap with that.

Perhaps I can help there. I've been preparing a patchset against the
latest mm. Here's a patch with additional changes I know about.

Hope it's helpful.

Regards,

Nigel

 arch/ppc/platforms/pmac_pic.c                 |    2 +-
 arch/ppc/syslib/open_pic.c                    |    2 +-
 drivers/base/power/resume.c                   |    8 ++++----
 drivers/base/power/runtime.c                  |    8 ++++----
 drivers/base/power/suspend.c                  |   14 +++++++-------
 drivers/base/power/sysfs.c                    |    9 +++++----
 drivers/ide/ide.c                             |    2 +-
 drivers/ide/pci/sc1200.c                      |    8 ++++----
 drivers/ide/ppc/pmac.c                        |   16 ++++++++--------
 drivers/macintosh/mediabay.c                  |    6 +++---
 drivers/macintosh/via-pmu.c                   |    2 +-
 drivers/media/dvb/cinergyT2/cinergyT2.c       |    2 +-
 drivers/media/video/bttv-driver.c             |    2 +-
 drivers/net/irda/vlsi_ir.c                    |   18 ++++++++++--------
 drivers/net/wireless/airo.c                   |    3 ++-
 drivers/net/wireless/orinoco_pci.c            |    2 +-
 drivers/net/wireless/prism54/islpci_hotplug.c |    2 +-
 drivers/pci/pci.c                             |   11 +++++++----
 drivers/scsi/lpfc/lpfc_init.c                 |    2 +-
 drivers/serial/pmac_zilog.c                   |    6 +++---
 drivers/usb/core/hub.c                        |   18 +++++++++---------
 drivers/usb/core/usb.c                        |    2 +-
 drivers/usb/host/ehci-dbg.c                   |    2 +-
 drivers/usb/host/ohci-dbg.c                   |    2 +-
 drivers/usb/host/sl811-hcd.c                  |    6 +++---
 drivers/video/aty/aty128fb.c                  |   12 ++++++------
 drivers/video/aty/atyfb_base.c                |   10 +++++-----
 drivers/video/aty/radeon_pm.c                 |   12 ++++++------
 drivers/video/i810/i810_main.c                |   22 ++++++++--------------
 drivers/video/savage/savagefb_driver.c        |    2 +-
 include/linux/pm.h                            |   18 ++++++++++++++----
 sound/pci/atiixp.c                            |    4 ++--
 32 files changed, 123 insertions(+), 112 deletions(-)
diff -ruNp 220-combined-pm_message_t.patch-old/arch/ppc/platforms/pmac_pic.c 220-combined-pm_message_t.patch-new/arch/ppc/platforms/pmac_pic.c
--- 220-combined-pm_message_t.patch-old/arch/ppc/platforms/pmac_pic.c	2005-02-03 22:33:18.000000000 +1100
+++ 220-combined-pm_message_t.patch-new/arch/ppc/platforms/pmac_pic.c	2005-07-12 20:10:30.000000000 +1000
@@ -619,7 +619,7 @@ not_found:
 	return viaint;
 }
 
-static int pmacpic_suspend(struct sys_device *sysdev, u32 state)
+static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state)
 {
 	int viaint = pmacpic_find_viaint();
 
diff -ruNp 220-combined-pm_message_t.patch-old/arch/ppc/syslib/open_pic.c 220-combined-pm_message_t.patch-new/arch/ppc/syslib/open_pic.c
--- 220-combined-pm_message_t.patch-old/arch/ppc/syslib/open_pic.c	2005-07-12 19:30:05.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/arch/ppc/syslib/open_pic.c	2005-07-12 20:10:30.000000000 +1000
@@ -948,7 +948,7 @@ static void openpic_cached_disable_irq(u
  * we need something better to deal with that... Maybe switch to S1 for
  * cpufreq changes
  */
-int openpic_suspend(struct sys_device *sysdev, u32 state)
+int openpic_suspend(struct sys_device *sysdev, pm_message_t state)
 {
 	int	i;
 	unsigned long flags;
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/base/power/resume.c 220-combined-pm_message_t.patch-new/drivers/base/power/resume.c
--- 220-combined-pm_message_t.patch-old/drivers/base/power/resume.c	2005-07-12 19:30:07.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/base/power/resume.c	2005-07-12 20:10:30.000000000 +1000
@@ -26,11 +26,11 @@ int resume_device(struct device * dev)
 
 	down(&dev->sem);
 	if (dev->power.pm_parent
-			&& dev->power.pm_parent->power.power_state) {
+			&& dev->power.pm_parent->power.power_state.event) {
 		dev_err(dev, "PM: resume from %d, parent %s still %d\n",
-			dev->power.power_state,
+			dev->power.power_state.event,
 			dev->power.pm_parent->bus_id,
-			dev->power.pm_parent->power.power_state);
+			dev->power.pm_parent->power.power_state.event);
 	}
 	if (dev->bus && dev->bus->resume) {
 		dev_dbg(dev,"resuming\n");
@@ -54,7 +54,7 @@ void dpm_resume(void)
 		list_add_tail(entry, &dpm_active);
 
 		up(&dpm_list_sem);
-		if (!dev->power.prev_state)
+		if (!dev->power.prev_state.event)
 			resume_device(dev);
 		down(&dpm_list_sem);
 		put_device(dev);
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/base/power/runtime.c 220-combined-pm_message_t.patch-new/drivers/base/power/runtime.c
--- 220-combined-pm_message_t.patch-old/drivers/base/power/runtime.c	2005-02-03 22:33:23.000000000 +1100
+++ 220-combined-pm_message_t.patch-new/drivers/base/power/runtime.c	2005-07-12 20:10:30.000000000 +1000
@@ -13,10 +13,10 @@
 static void runtime_resume(struct device * dev)
 {
 	dev_dbg(dev, "resuming\n");
-	if (!dev->power.power_state)
+	if (!dev->power.power_state.event)
 		return;
 	if (!resume_device(dev))
-		dev->power.power_state = 0;
+		dev->power.power_state = PMSG_ON;
 }
 
 
@@ -49,10 +49,10 @@ int dpm_runtime_suspend(struct device * 
 	int error = 0;
 
 	down(&dpm_sem);
-	if (dev->power.power_state == state)
+	if (dev->power.power_state.event == state.event)
 		goto Done;
 
-	if (dev->power.power_state)
+	if (dev->power.power_state.event)
 		runtime_resume(dev);
 
 	if (!(error = suspend_device(dev, state)))
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/base/power/suspend.c 220-combined-pm_message_t.patch-new/drivers/base/power/suspend.c
--- 220-combined-pm_message_t.patch-old/drivers/base/power/suspend.c	2005-07-12 19:30:07.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/base/power/suspend.c	2005-07-12 20:10:30.000000000 +1000
@@ -40,22 +40,22 @@ int suspend_device(struct device * dev, 
 	int error = 0;
 
 	down(&dev->sem);
-	if (dev->power.power_state) {
+	if (dev->power.power_state.event) {
 		dev_dbg(dev, "PM: suspend %d-->%d\n",
-			dev->power.power_state, state);
+			dev->power.power_state.event, state.event);
 	}
 	if (dev->power.pm_parent
-			&& dev->power.pm_parent->power.power_state) {
+			&& dev->power.pm_parent->power.power_state.event) {
 		dev_err(dev,
 			"PM: suspend %d->%d, parent %s already %d\n",
-			dev->power.power_state, state,
+			dev->power.power_state.event, state.event,
 			dev->power.pm_parent->bus_id,
-			dev->power.pm_parent->power.power_state);
+			dev->power.pm_parent->power.power_state.event);
 	}
 
-	dev->power.prev_state = dev->power.power_state;
+	dev->power.prev_state.event = dev->power.power_state.event;
 
-	if (dev->bus && dev->bus->suspend && !dev->power.power_state) {
+	if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
 		dev_dbg(dev, "suspending\n");
 		error = dev->bus->suspend(dev, state);
 	}
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/base/power/sysfs.c 220-combined-pm_message_t.patch-new/drivers/base/power/sysfs.c
--- 220-combined-pm_message_t.patch-old/drivers/base/power/sysfs.c	2005-07-12 19:30:07.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/base/power/sysfs.c	2005-07-12 20:10:30.000000000 +1000
@@ -26,19 +26,20 @@
 
 static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf)
 {
-	return sprintf(buf, "%u\n", dev->power.power_state);
+	return sprintf(buf, "%u\n", dev->power.power_state.event);
 }
 
 static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n)
 {
-	u32 state;
+	pm_message_t state;
 	char * rest;
 	int error = 0;
 
-	state = simple_strtoul(buf, &rest, 10);
+	state.event = simple_strtoul(buf, &rest, 10);
+	state.flags = PFL_RUNTIME;
 	if (*rest)
 		return -EINVAL;
-	if (state)
+	if (state.event)
 		error = dpm_runtime_suspend(dev, state);
 	else
 		dpm_runtime_resume(dev);
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/ide/ide.c 220-combined-pm_message_t.patch-new/drivers/ide/ide.c
--- 220-combined-pm_message_t.patch-old/drivers/ide/ide.c	2005-07-12 20:22:02.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/ide/ide.c	2005-07-12 20:10:31.000000000 +1000
@@ -1229,7 +1229,7 @@ static int generic_ide_suspend(struct de
 	rq.special = &args;
 	rq.pm = &rqpm;
 	rqpm.pm_step = ide_pm_state_start_suspend;
-	rqpm.pm_state = state;
+	rqpm.pm_state = state.event;
 
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/ide/pci/sc1200.c 220-combined-pm_message_t.patch-new/drivers/ide/pci/sc1200.c
--- 220-combined-pm_message_t.patch-old/drivers/ide/pci/sc1200.c	2005-07-12 19:30:10.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/ide/pci/sc1200.c	2005-07-12 20:10:31.000000000 +1000
@@ -350,9 +350,9 @@ static int sc1200_suspend (struct pci_de
 {
 	ide_hwif_t		*hwif = NULL;
 
-	printk("SC1200: suspend(%u)\n", state);
+	printk("SC1200: suspend(%u)\n", state.event);
 
-	if (state == 0) {
+	if (state.event == EVENT_ON) {
 		// we only save state when going from full power to less
 
 		//
@@ -386,8 +386,8 @@ static int sc1200_suspend (struct pci_de
 	/* You don't need to iterate over disks -- sysfs should have done that for you already */ 
 
 	pci_disable_device(dev);
-	pci_set_power_state(dev,state);
-	dev->current_state = state;
+	pci_set_power_state(dev, pci_choose_state(dev, state));
+	dev->current_state = state.event;
 	return 0;
 }
 
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/ide/ppc/pmac.c 220-combined-pm_message_t.patch-new/drivers/ide/ppc/pmac.c
--- 220-combined-pm_message_t.patch-old/drivers/ide/ppc/pmac.c	2005-07-12 19:31:56.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/ide/ppc/pmac.c	2005-07-12 20:10:31.000000000 +1000
@@ -1504,12 +1504,12 @@ pmac_ide_macio_attach(struct macio_dev *
 }
 
 static int
-pmac_ide_macio_suspend(struct macio_dev *mdev, u32 state)
+pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t state)
 {
 	ide_hwif_t	*hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
 	int		rc = 0;
 
-	if (state != mdev->ofdev.dev.power.power_state && state >= 2) {
+	if (state.event != mdev->ofdev.dev.power.power_state.event && state.event >= EVENT_SUSPEND) {
 		rc = pmac_ide_do_suspend(hwif);
 		if (rc == 0)
 			mdev->ofdev.dev.power.power_state = state;
@@ -1524,10 +1524,10 @@ pmac_ide_macio_resume(struct macio_dev *
 	ide_hwif_t	*hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
 	int		rc = 0;
 	
-	if (mdev->ofdev.dev.power.power_state != 0) {
+	if (mdev->ofdev.dev.power.power_state.event != EVENT_ON) {
 		rc = pmac_ide_do_resume(hwif);
 		if (rc == 0)
-			mdev->ofdev.dev.power.power_state = 0;
+			mdev->ofdev.dev.power.power_state = PMSG_ON;
 	}
 
 	return rc;
@@ -1608,12 +1608,12 @@ pmac_ide_pci_attach(struct pci_dev *pdev
 }
 
 static int
-pmac_ide_pci_suspend(struct pci_dev *pdev, u32 state)
+pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	ide_hwif_t	*hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
 	int		rc = 0;
 	
-	if (state != pdev->dev.power.power_state && state >= 2) {
+	if (state.event != pdev->dev.power.power_state.event && state.event >= 2) {
 		rc = pmac_ide_do_suspend(hwif);
 		if (rc == 0)
 			pdev->dev.power.power_state = state;
@@ -1628,10 +1628,10 @@ pmac_ide_pci_resume(struct pci_dev *pdev
 	ide_hwif_t	*hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
 	int		rc = 0;
 	
-	if (pdev->dev.power.power_state != 0) {
+	if (pdev->dev.power.power_state.event != EVENT_ON) {
 		rc = pmac_ide_do_resume(hwif);
 		if (rc == 0)
-			pdev->dev.power.power_state = 0;
+			pdev->dev.power.power_state = PMSG_ON;
 	}
 
 	return rc;
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/macintosh/mediabay.c 220-combined-pm_message_t.patch-new/drivers/macintosh/mediabay.c
--- 220-combined-pm_message_t.patch-old/drivers/macintosh/mediabay.c	2005-07-12 19:31:59.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/macintosh/mediabay.c	2005-07-12 20:10:31.000000000 +1000
@@ -708,7 +708,7 @@ static int __pmac media_bay_suspend(stru
 {
 	struct media_bay_info	*bay = macio_get_drvdata(mdev);
 
-	if (state != mdev->ofdev.dev.power.power_state && state == PM_SUSPEND_MEM) {
+	if (state.event != mdev->ofdev.dev.power.power_state.event && state.event == EVENT_SUSPEND) {
 		down(&bay->lock);
 		bay->sleeping = 1;
 		set_mb_power(bay, 0);
@@ -723,8 +723,8 @@ static int __pmac media_bay_resume(struc
 {
 	struct media_bay_info	*bay = macio_get_drvdata(mdev);
 
-	if (mdev->ofdev.dev.power.power_state != 0) {
-		mdev->ofdev.dev.power.power_state = 0;
+	if (mdev->ofdev.dev.power.power_state.event != EVENT_ON) {
+		mdev->ofdev.dev.power.power_state = PMSG_ON;
 
 	       	/* We re-enable the bay using it's previous content
 	       	   only if it did not change. Note those bozo timings,
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/macintosh/via-pmu.c 220-combined-pm_message_t.patch-new/drivers/macintosh/via-pmu.c
--- 220-combined-pm_message_t.patch-old/drivers/macintosh/via-pmu.c	2005-07-12 19:30:11.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/macintosh/via-pmu.c	2005-07-12 20:10:31.000000000 +1000
@@ -3065,7 +3065,7 @@ static int pmu_sys_suspended = 0;
 
 static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state)
 {
-	if (state != PM_SUSPEND_DISK || pmu_sys_suspended)
+	if (state.event != EVENT_SUSPEND || pmu_sys_suspended)
 		return 0;
 
 	/* Suspend PMU event interrupts */
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/media/dvb/cinergyT2/cinergyT2.c 220-combined-pm_message_t.patch-new/drivers/media/dvb/cinergyT2/cinergyT2.c
--- 220-combined-pm_message_t.patch-old/drivers/media/dvb/cinergyT2/cinergyT2.c	2005-07-12 19:31:59.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/media/dvb/cinergyT2/cinergyT2.c	2005-07-12 20:10:31.000000000 +1000
@@ -888,7 +888,7 @@ static int cinergyt2_suspend (struct usb
 	if (down_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
-	if (state > 0) {	/* state 0 seems to mean DEVICE_PM_ON */
+	if (state.event > 0) {	/* state 0 seems to mean DEVICE_PM_ON */
 		struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
 #ifdef ENABLE_RC
 		cancel_delayed_work(&cinergyt2->rc_query_work);
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/media/video/bttv-driver.c 220-combined-pm_message_t.patch-new/drivers/media/video/bttv-driver.c
--- 220-combined-pm_message_t.patch-old/drivers/media/video/bttv-driver.c	2005-07-12 19:30:11.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/media/video/bttv-driver.c	2005-07-12 20:10:31.000000000 +1000
@@ -4043,7 +4043,7 @@ static int bttv_suspend(struct pci_dev *
 	struct bttv_buffer_set idle;
 	unsigned long flags;
 
-	dprintk("bttv%d: suspend %d\n", btv->c.nr, state);
+	dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);
 
 	/* stop dma + irqs */
 	spin_lock_irqsave(&btv->s_lock,flags);
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/net/irda/vlsi_ir.c 220-combined-pm_message_t.patch-new/drivers/net/irda/vlsi_ir.c
--- 220-combined-pm_message_t.patch-old/drivers/net/irda/vlsi_ir.c	2005-06-20 11:47:00.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/net/irda/vlsi_ir.c	2005-07-12 20:10:31.000000000 +1000
@@ -1748,10 +1748,11 @@ static int vlsi_irda_suspend(struct pci_
 {
 	struct net_device *ndev = pci_get_drvdata(pdev);
 	vlsi_irda_dev_t *idev;
+	pci_power_t new_state;
 
-	if (state < 1 || state > 3 ) {
+	if (state.event < EVENT_FREEZE || state.event > EVENT_SUSPEND ) {
 		IRDA_ERROR("%s - %s: invalid pm state request: %u\n",
-			   __FUNCTION__, PCIDEV_NAME(pdev), state);
+			   __FUNCTION__, PCIDEV_NAME(pdev), state.event);
 		return 0;
 	}
 	if (!ndev) {
@@ -1760,14 +1761,15 @@ static int vlsi_irda_suspend(struct pci_
 		return 0;
 	}
 	idev = ndev->priv;	
+	new_state = pci_choose_state(pdev, state);
 	down(&idev->sem);
 	if (pdev->current_state != 0) {			/* already suspended */
-		if (state > pdev->current_state) {	/* simply go deeper */
-			pci_set_power_state(pdev,state);
-			pdev->current_state = state;
+		if (new_state > pdev->current_state) {	/* simply go deeper */
+			pci_set_power_state(pdev, new_state);
+			pdev->current_state = new_state;
 		}
 		else
-			IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, PCIDEV_NAME(pdev), pdev->current_state, state);
+			IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, PCIDEV_NAME(pdev), pdev->current_state, state.event);
 		up(&idev->sem);
 		return 0;
 	}
@@ -1781,8 +1783,8 @@ static int vlsi_irda_suspend(struct pci_
 			idev->new_baud = idev->baud;
 	}
 
-	pci_set_power_state(pdev,state);
-	pdev->current_state = state;
+	pci_set_power_state(pdev,new_state);
+	pdev->current_state = new_state;
 	idev->resume_ok = 1;
 	up(&idev->sem);
 	return 0;
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/net/wireless/airo.c 220-combined-pm_message_t.patch-new/drivers/net/wireless/airo.c
--- 220-combined-pm_message_t.patch-old/drivers/net/wireless/airo.c	2005-07-12 19:32:02.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/net/wireless/airo.c	2005-07-12 20:10:32.000000000 +1000
@@ -5487,6 +5487,7 @@ static int airo_pci_suspend(struct pci_d
 	struct airo_info *ai = dev->priv;
 	Cmd cmd;
 	Resp rsp;
+	int new_state = pci_choose_state(pdev, state);
 
 	if ((ai->APList == NULL) &&
 		(ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL)) == NULL)
@@ -5502,7 +5503,7 @@ static int airo_pci_suspend(struct pci_d
 		return -EAGAIN;
 	disable_MAC(ai, 0);
 	netif_device_detach(dev);
-	ai->power = state;
+	ai->power = state.event;
 	cmd.cmd=HOSTSLEEP;
 	issuecommand(ai, &cmd, &rsp);
 
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/net/wireless/orinoco_pci.c 220-combined-pm_message_t.patch-new/drivers/net/wireless/orinoco_pci.c
--- 220-combined-pm_message_t.patch-old/drivers/net/wireless/orinoco_pci.c	2005-06-20 11:47:02.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/net/wireless/orinoco_pci.c	2005-07-12 20:10:32.000000000 +1000
@@ -302,7 +302,7 @@ static int orinoco_pci_suspend(struct pc
 	int err;
 	
 	printk(KERN_DEBUG "%s: Orinoco-PCI entering sleep mode (state=%d)\n",
-	       dev->name, state);
+	       dev->name, state.event);
 
 	err = orinoco_lock(priv, &flags);
 	if (err) {
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/net/wireless/prism54/islpci_hotplug.c 220-combined-pm_message_t.patch-new/drivers/net/wireless/prism54/islpci_hotplug.c
--- 220-combined-pm_message_t.patch-old/drivers/net/wireless/prism54/islpci_hotplug.c	2005-06-20 11:47:02.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/net/wireless/prism54/islpci_hotplug.c	2005-07-12 20:10:32.000000000 +1000
@@ -268,7 +268,7 @@ prism54_suspend(struct pci_dev *pdev, pm
 	BUG_ON(!priv);
 
 	printk(KERN_NOTICE "%s: got suspend request (state %d)\n",
-	       ndev->name, state);
+	       ndev->name, state.event);
 
 	pci_save_state(pdev);
 
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/pci/pci.c 220-combined-pm_message_t.patch-new/drivers/pci/pci.c
--- 220-combined-pm_message_t.patch-old/drivers/pci/pci.c	2005-07-12 19:32:03.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/pci/pci.c	2005-07-12 20:16:21.000000000 +1000
@@ -333,11 +333,14 @@ pci_power_t pci_choose_state(struct pci_
 		if (ret >= 0)
 			state = ret;
 	}
-	switch (state) {
-	case 0: return PCI_D0;
-	case 3: return PCI_D3hot;
+	switch (state.event) {
+	case EVENT_ON:
+	case EVENT_FREEZE:
+		return PCI_D0;
+	case EVENT_SUSPEND:
+		return PCI_D3hot;
 	default:
-		printk("They asked me for state %d\n", state);
+		printk("They asked me for state %d\n", state.event);
 		BUG();
 	}
 	return PCI_D0;
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/scsi/lpfc/lpfc_init.c 220-combined-pm_message_t.patch-new/drivers/scsi/lpfc/lpfc_init.c
--- 220-combined-pm_message_t.patch-old/drivers/scsi/lpfc/lpfc_init.c	2005-07-12 19:32:05.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/scsi/lpfc/lpfc_init.c	2005-07-12 20:10:32.000000000 +1000
@@ -1475,7 +1475,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev,
 	phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4));
 
 	/* Startup the kernel thread for this host adapter. */
-	phba->worker_thread = kthread_run(lpfc_do_work, phba,
+	phba->worker_thread = kthread_run(lpfc_do_work, phba, PF_NOFREEZE,
 				       "lpfc_worker_%d", phba->brd_no);
 	if (IS_ERR(phba->worker_thread)) {
 		error = PTR_ERR(phba->worker_thread);
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/serial/pmac_zilog.c 220-combined-pm_message_t.patch-new/drivers/serial/pmac_zilog.c
--- 220-combined-pm_message_t.patch-old/drivers/serial/pmac_zilog.c	2005-07-12 19:32:05.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/serial/pmac_zilog.c	2005-07-12 20:10:32.000000000 +1000
@@ -1601,7 +1601,7 @@ static int pmz_suspend(struct macio_dev 
 		return 0;
 	}
 
-	if (pm_state == mdev->ofdev.dev.power.power_state || pm_state < 2)
+	if (pm_state.event == mdev->ofdev.dev.power.power_state.event || pm_state.event < EVENT_SUSPEND)
 		return 0;
 
 	pmz_debug("suspend, switching to state %d\n", pm_state);
@@ -1661,7 +1661,7 @@ static int pmz_resume(struct macio_dev *
 	if (uap == NULL)
 		return 0;
 
-	if (mdev->ofdev.dev.power.power_state == 0)
+	if (mdev->ofdev.dev.power.power_state.event == EVENT_ON)
 		return 0;
 	
 	pmz_debug("resume, switching to state 0\n");
@@ -1714,7 +1714,7 @@ static int pmz_resume(struct macio_dev *
 
 	pmz_debug("resume, switching complete\n");
 
-	mdev->ofdev.dev.power.power_state = 0;
+	mdev->ofdev.dev.power.power_state = PMSG_ON;
 
 	return 0;
 }
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/usb/core/hub.c 220-combined-pm_message_t.patch-new/drivers/usb/core/hub.c
--- 220-combined-pm_message_t.patch-old/drivers/usb/core/hub.c	2005-07-12 19:32:05.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/usb/core/hub.c	2005-07-12 20:10:32.000000000 +1000
@@ -1570,7 +1570,7 @@ static int __usb_suspend_device (struct 
 			struct usb_driver	*driver;
 
 			intf = udev->actconfig->interface[i];
-			if (state <= intf->dev.power.power_state)
+			if (state.event <= intf->dev.power.power_state.event)
 				continue;
 			if (!intf->dev.driver)
 				continue;
@@ -1578,11 +1578,11 @@ static int __usb_suspend_device (struct 
 
 			if (driver->suspend) {
 				status = driver->suspend(intf, state);
-				if (intf->dev.power.power_state != state
+				if (intf->dev.power.power_state.event != state.event
 						|| status)
 					dev_err(&intf->dev,
 						"suspend %d fail, code %d\n",
-						state, status);
+						state.event, status);
 			}
 
 			/* only drivers with suspend() can ever resume();
@@ -1595,7 +1595,7 @@ static int __usb_suspend_device (struct 
 			 * since we know every driver's probe/disconnect works
 			 * even for drivers that can't suspend.
 			 */
-			if (!driver->suspend || state > PM_SUSPEND_MEM) {
+			if (!driver->suspend || state.event > EVENT_SUSPEND) {
 #if 1
 				dev_warn(&intf->dev, "resume is unsafe!\n");
 #else
@@ -1616,7 +1616,7 @@ static int __usb_suspend_device (struct 
 	 * policies (when HNP doesn't apply) once we have mechanisms to
 	 * turn power back on!  (Likely not before 2.7...)
 	 */
-	if (state > PM_SUSPEND_MEM) {
+	if (state.event > EVENT_SUSPEND) {
 		dev_warn(&udev->dev, "no poweroff yet, suspending instead\n");
 	}
 
@@ -1733,7 +1733,7 @@ static int finish_port_resume(struct usb
 			struct usb_driver	*driver;
 
 			intf = udev->actconfig->interface[i];
-			if (intf->dev.power.power_state == PMSG_ON)
+			if (intf->dev.power.power_state.event == EVENT_SUSPEND)
 				continue;
 			if (!intf->dev.driver) {
 				/* FIXME maybe force to alt 0 */
@@ -1747,11 +1747,11 @@ static int finish_port_resume(struct usb
 
 			/* can we do better than just logging errors? */
 			status = driver->resume(intf);
-			if (intf->dev.power.power_state != PMSG_ON
+			if (intf->dev.power.power_state.event != EVENT_ON
 					|| status)
 				dev_dbg(&intf->dev,
 					"resume fail, state %d code %d\n",
-					intf->dev.power.power_state, status);
+					intf->dev.power.power_state.event, status);
 		}
 		status = 0;
 
@@ -1934,7 +1934,7 @@ static int hub_resume(struct usb_interfa
 	unsigned		port1;
 	int			status;
 
-	if (intf->dev.power.power_state == PM_SUSPEND_ON)
+	if (intf->dev.power.power_state.event == EVENT_ON)
 		return 0;
 
 	for (port1 = 1; port1 <= hdev->maxchild; port1++) {
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/usb/core/usb.c 220-combined-pm_message_t.patch-new/drivers/usb/core/usb.c
--- 220-combined-pm_message_t.patch-old/drivers/usb/core/usb.c	2005-07-12 19:32:06.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/usb/core/usb.c	2005-07-12 20:10:32.000000000 +1000
@@ -1400,7 +1400,7 @@ static int usb_generic_suspend(struct de
 	driver = to_usb_driver(dev->driver);
 
 	/* there's only one USB suspend state */
-	if (intf->dev.power.power_state)
+	if (intf->dev.power.power_state.event)
 		return 0;
 
 	if (driver->suspend)
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/usb/host/ehci-dbg.c 220-combined-pm_message_t.patch-new/drivers/usb/host/ehci-dbg.c
--- 220-combined-pm_message_t.patch-old/drivers/usb/host/ehci-dbg.c	2005-07-12 19:32:06.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/usb/host/ehci-dbg.c	2005-07-12 20:10:32.000000000 +1000
@@ -643,7 +643,7 @@ show_registers (struct class_device *cla
 
 	spin_lock_irqsave (&ehci->lock, flags);
 
-	if (bus->controller->power.power_state) {
+	if (bus->controller->power.power_state.event) {
 		size = scnprintf (next, size,
 			"bus %s, device %s (driver " DRIVER_VERSION ")\n"
 			"%s\n"
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/usb/host/ohci-dbg.c 220-combined-pm_message_t.patch-new/drivers/usb/host/ohci-dbg.c
--- 220-combined-pm_message_t.patch-old/drivers/usb/host/ohci-dbg.c	2005-07-12 19:30:17.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/usb/host/ohci-dbg.c	2005-07-12 20:10:32.000000000 +1000
@@ -631,7 +631,7 @@ show_registers (struct class_device *cla
 		hcd->product_desc,
 		hcd_name);
 
-	if (bus->controller->power.power_state) {
+	if (bus->controller->power.power_state.event) {
 		size -= scnprintf (next, size,
 			"SUSPENDED (no register access)\n");
 		goto done;
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/usb/host/sl811-hcd.c 220-combined-pm_message_t.patch-new/drivers/usb/host/sl811-hcd.c
--- 220-combined-pm_message_t.patch-old/drivers/usb/host/sl811-hcd.c	2005-07-12 19:32:06.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/usb/host/sl811-hcd.c	2005-07-12 20:10:32.000000000 +1000
@@ -1781,9 +1781,9 @@ sl811h_suspend(struct device *dev, pm_me
 	if (phase != SUSPEND_POWER_DOWN)
 		return retval;
 
-	if (state <= PM_SUSPEND_MEM)
+	if (state.event == EVENT_FREEZE)
 		retval = sl811h_hub_suspend(hcd);
-	else
+	else if (state.event == EVENT_SUSPEND)
 		port_power(sl811, 0);
 	if (retval == 0)
 		dev->power.power_state = state;
@@ -1802,7 +1802,7 @@ sl811h_resume(struct device *dev, u32 ph
 	/* with no "check to see if VBUS is still powered" board hook,
 	 * let's assume it'd only be powered to enable remote wakeup.
 	 */
-	if (dev->power.power_state > PM_SUSPEND_MEM
+	if (dev->power.power_state.event > EVENT_FREEZE
 			|| !hcd->can_wakeup) {
 		sl811->port1 = 0;
 		port_power(sl811, 1);
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/video/aty/aty128fb.c 220-combined-pm_message_t.patch-new/drivers/video/aty/aty128fb.c
--- 220-combined-pm_message_t.patch-old/drivers/video/aty/aty128fb.c	2005-07-12 19:30:19.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/video/aty/aty128fb.c	2005-07-12 20:10:32.000000000 +1000
@@ -2329,11 +2329,11 @@ static int aty128_pci_suspend(struct pci
 	 * that. On laptops, the AGP slot is just unclocked, so D2 is
 	 * expected, while on desktops, the card is powered off
 	 */
-	if (state >= 3)
-		state = 2;
+	if (state.event >= 3)
+		state.event = 2;
 #endif /* CONFIG_PPC_PMAC */
 	 
-	if (state != 2 || state == pdev->dev.power.power_state)
+	if (state.event != 2 || state.event == pdev->dev.power.power_state.event)
 		return 0;
 
 	printk(KERN_DEBUG "aty128fb: suspending...\n");
@@ -2367,7 +2367,7 @@ static int aty128_pci_suspend(struct pci
 	 * used dummy fb ops, 2.5 need proper support for this at the
 	 * fbdev level
 	 */
-	if (state == 2)
+	if (state.event == 2)
 		aty128_set_suspend(par, 1);
 
 	release_console_sem();
@@ -2382,11 +2382,11 @@ static int aty128_do_resume(struct pci_d
 	struct fb_info *info = pci_get_drvdata(pdev);
 	struct aty128fb_par *par = info->par;
 
-	if (pdev->dev.power.power_state == 0)
+	if (!pdev->dev.power.power_state.event)
 		return 0;
 
 	/* Wakeup chip */
-	if (pdev->dev.power.power_state == 2)
+	if (pdev->dev.power.power_state.event == 2)
 		aty128_set_suspend(par, 0);
 	par->asleep = 0;
 
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/video/aty/atyfb_base.c 220-combined-pm_message_t.patch-new/drivers/video/aty/atyfb_base.c
--- 220-combined-pm_message_t.patch-old/drivers/video/aty/atyfb_base.c	2005-06-20 11:47:10.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/video/aty/atyfb_base.c	2005-07-12 20:10:32.000000000 +1000
@@ -2028,11 +2028,11 @@ static int atyfb_pci_suspend(struct pci_
 	 * that. On laptops, the AGP slot is just unclocked, so D2 is
 	 * expected, while on desktops, the card is powered off
 	 */
-	if (state >= 3)
-		state = 2;
+	if (state.event >= 3)
+		state.event = 2;
 #endif /* CONFIG_PPC_PMAC */
 
-	if (state != 2 || state == pdev->dev.power.power_state)
+	if (state.event != 2 || state.event == pdev->dev.power.power_state.event)
 		return 0;
 
 	acquire_console_sem();
@@ -2071,12 +2071,12 @@ static int atyfb_pci_resume(struct pci_d
 	struct fb_info *info = pci_get_drvdata(pdev);
 	struct atyfb_par *par = (struct atyfb_par *) info->par;
 
-	if (pdev->dev.power.power_state == 0)
+	if (pdev->dev.power.power_state.event == EVENT_ON)
 		return 0;
 
 	acquire_console_sem();
 
-	if (pdev->dev.power.power_state == 2)
+	if (pdev->dev.power.power_state.event == 2)
 		aty_power_mgmt(0, par);
 	par->asleep = 0;
 
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/video/aty/radeon_pm.c 220-combined-pm_message_t.patch-new/drivers/video/aty/radeon_pm.c
--- 220-combined-pm_message_t.patch-old/drivers/video/aty/radeon_pm.c	2005-06-20 11:47:10.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/video/aty/radeon_pm.c	2005-07-12 20:10:32.000000000 +1000
@@ -2526,18 +2526,18 @@ int radeonfb_pci_suspend(struct pci_dev 
         struct radeonfb_info *rinfo = info->par;
 	int i;
 
-	if (state == pdev->dev.power.power_state)
+	if (state.event == pdev->dev.power.power_state.event)
 		return 0;
 
 	printk(KERN_DEBUG "radeonfb (%s): suspending to state: %d...\n",
-	       pci_name(pdev), state);
+	       pci_name(pdev), state.event);
 
 	/* For suspend-to-disk, we cheat here. We don't suspend anything and
 	 * let fbcon continue drawing until we are all set. That shouldn't
 	 * really cause any problem at this point, provided that the wakeup
 	 * code knows that any state in memory may not match the HW
 	 */
-	if (state != PM_SUSPEND_MEM)
+	if (state.event != EVENT_SUSPEND)
 		goto done;
 
 	acquire_console_sem();
@@ -2616,7 +2616,7 @@ int radeonfb_pci_resume(struct pci_dev *
         struct radeonfb_info *rinfo = info->par;
 	int rc = 0;
 
-	if (pdev->dev.power.power_state == 0)
+	if (!pdev->dev.power.power_state.event)
 		return 0;
 
 	if (rinfo->no_schedule) {
@@ -2626,7 +2626,7 @@ int radeonfb_pci_resume(struct pci_dev *
 		acquire_console_sem();
 
 	printk(KERN_DEBUG "radeonfb (%s): resuming from state: %d...\n",
-	       pci_name(pdev), pdev->dev.power.power_state);
+	       pci_name(pdev), pdev->dev.power.power_state.event);
 
 
 	if (pci_enable_device(pdev)) {
@@ -2637,7 +2637,7 @@ int radeonfb_pci_resume(struct pci_dev *
 	}
 	pci_set_master(pdev);
 
-	if (pdev->dev.power.power_state == PM_SUSPEND_MEM) {
+	if (pdev->dev.power.power_state.event == EVENT_SUSPEND) {
 		/* Wakeup chip. Check from config space if we were powered off
 		 * (todo: additionally, check CLK_PIN_CNTL too)
 		 */
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/video/i810/i810_main.c 220-combined-pm_message_t.patch-new/drivers/video/i810/i810_main.c
--- 220-combined-pm_message_t.patch-old/drivers/video/i810/i810_main.c	2005-07-12 19:30:19.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/video/i810/i810_main.c	2005-07-12 20:10:32.000000000 +1000
@@ -1506,23 +1506,17 @@ static int i810fb_suspend(struct pci_dev
 	struct i810fb_par *par = (struct i810fb_par *) info->par;
 	int blank = 0, prev_state = par->cur_state;
 
-	if (state == prev_state)
+	if (state.event == prev_state)
 		return 0;
 
-	par->cur_state = state;
+	par->cur_state = state.event;
 
-	switch (state) {
-	case 1:
-		blank = VESA_VSYNC_SUSPEND;
-		break;
-	case 2:
-		blank = VESA_HSYNC_SUSPEND;
-		break;
-	case 3:
-		blank = VESA_POWERDOWN;
-		break;
-	default:
-		return -EINVAL;
+	switch (state.event) {
+		case EVENT_SUSPEND:
+			blank = VESA_POWERDOWN;
+			break;
+		default:
+			return -EINVAL;
 	}
 	info->fbops->fb_blank(blank, info);
 
diff -ruNp 220-combined-pm_message_t.patch-old/drivers/video/savage/savagefb_driver.c 220-combined-pm_message_t.patch-new/drivers/video/savage/savagefb_driver.c
--- 220-combined-pm_message_t.patch-old/drivers/video/savage/savagefb_driver.c	2005-07-12 19:32:08.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/drivers/video/savage/savagefb_driver.c	2005-07-12 20:19:56.000000000 +1000
@@ -2110,7 +2110,7 @@ static int savagefb_suspend (struct pci_
 	struct savagefb_par *par = (struct savagefb_par *)info->par;
 
 	DBG("savagefb_suspend");
-	printk(KERN_DEBUG "state: %u\n", state);
+	printk(KERN_DEBUG "state: %u\n", state.event);
 
 	acquire_console_sem();
 	fb_set_suspend(info, pci_choose_state(dev, state));
diff -ruNp 220-combined-pm_message_t.patch-old/include/linux/pm.h 220-combined-pm_message_t.patch-new/include/linux/pm.h
--- 220-combined-pm_message_t.patch-old/include/linux/pm.h	2005-07-12 19:32:12.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/include/linux/pm.h	2005-07-12 20:10:32.000000000 +1000
@@ -186,7 +186,10 @@ extern int pm_suspend(suspend_state_t st
 
 struct device;
 
-typedef u32 __bitwise pm_message_t;
+typedef struct pm_message {
+	int event;
+	int flags;
+} pm_message_t;
 
 /*
  * There are 4 important states driver can be in:
@@ -207,9 +210,16 @@ typedef u32 __bitwise pm_message_t;
  * or something similar soon.
  */
 
-#define PMSG_FREEZE	((__force pm_message_t) 3)
-#define PMSG_SUSPEND	((__force pm_message_t) 3)
-#define PMSG_ON		((__force pm_message_t) 0)
+#define EVENT_ON 0
+#define EVENT_FREEZE 1
+#define EVENT_SUSPEND 2
+
+#define PFL_RUNTIME 1
+
+#define PMSG_FREEZE	({struct pm_message m; m.event = EVENT_FREEZE; m.flags = 0; m; })
+#define PMSG_SUSPEND	({struct pm_message m; m.event = EVENT_SUSPEND; m.flags = 0; m; })
+#define PMSG_ON		({struct pm_message m; m.event = EVENT_ON; m.flags = 0; m; })
+
 
 struct dev_pm_info {
 	pm_message_t		power_state;
diff -ruNp 220-combined-pm_message_t.patch-old/sound/pci/atiixp.c 220-combined-pm_message_t.patch-new/sound/pci/atiixp.c
--- 220-combined-pm_message_t.patch-old/sound/pci/atiixp.c	2005-07-12 19:30:30.000000000 +1000
+++ 220-combined-pm_message_t.patch-new/sound/pci/atiixp.c	2005-07-12 20:10:32.000000000 +1000
@@ -1419,7 +1419,7 @@ static int snd_atiixp_suspend(snd_card_t
 	snd_atiixp_aclink_down(chip);
 	snd_atiixp_chip_stop(chip);
 
-	pci_set_power_state(chip->pci, 3);
+	pci_set_power_state(chip->pci, PCI_D3hot);
 	pci_disable_device(chip->pci);
 	return 0;
 }
@@ -1430,7 +1430,7 @@ static int snd_atiixp_resume(snd_card_t 
 	int i;
 
 	pci_enable_device(chip->pci);
-	pci_set_power_state(chip->pci, 0);
+	pci_set_power_state(chip->pci, PCI_D0);
 	pci_set_master(chip->pci);
 
 	snd_atiixp_aclink_reset(chip);


-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch
  2005-07-12 10:22           ` Matthew Garrett
@ 2005-07-12 10:34             ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12 10:34 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Christoph Hellwig, Linux Kernel Mailing List

Hi.

On Tue, 2005-07-12 at 20:22, Matthew Garrett wrote:
> Nigel Cunningham <ncunningham@cyclades.com> wrote:
> > On Tue, 2005-07-12 at 19:47, Matthew Garrett wrote:
> >> 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.

Both are true. If it only provided functionality, it wouldn't remount
filesystems read only on journal errors or the like.
 
> > 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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch
  2005-07-12  6:40     ` Nigel Cunningham
@ 2005-07-12 10:57       ` Pavel Machek
  2005-07-12 11:07         ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-12 10:57 UTC (permalink / raw)
  To: Nigel Cunningham
  Cc: Christoph Hellwig, Nigel Cunningham, Linux Kernel Mailing List

Hi!

> > 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
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch
  2005-07-12 10:57       ` Pavel Machek
@ 2005-07-12 11:07         ` Nigel Cunningham
  2005-07-12 11:15           ` Pavel Machek
  0 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12 11:07 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Christoph Hellwig, Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Tue, 2005-07-12 at 20:57, Pavel Machek wrote:
> Hi!
> 
> > > 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.

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
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch
  2005-07-12 11:07         ` Nigel Cunningham
@ 2005-07-12 11:15           ` Pavel Machek
  2005-07-12 11:25             ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-12 11:15 UTC (permalink / raw)
  To: Nigel Cunningham
  Cc: Christoph Hellwig, Nigel Cunningham, Linux Kernel Mailing List

Hi!

> > > > 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.
> 
> 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
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch
  2005-07-12 11:15           ` Pavel Machek
@ 2005-07-12 11:25             ` Nigel Cunningham
  2005-07-12 11:25               ` Pavel Machek
  0 siblings, 1 reply; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12 11:25 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Christoph Hellwig, Nigel Cunningham, Linux Kernel Mailing List

Hi.

On Tue, 2005-07-12 at 21:15, Pavel Machek wrote:
> Hi!
> 
> > > > > 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.
> > 
> > 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.

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

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch
  2005-07-12 11:25             ` Nigel Cunningham
@ 2005-07-12 11:25               ` Pavel Machek
  2005-07-12 11:45                 ` Nigel Cunningham
  0 siblings, 1 reply; 187+ messages in thread
From: Pavel Machek @ 2005-07-12 11:25 UTC (permalink / raw)
  To: Nigel Cunningham
  Cc: Christoph Hellwig, Nigel Cunningham, Linux Kernel Mailing List

Hi!

> > > > > > 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.
> > > 
> > > 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.
> 
> 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
-- 
teflon -- maybe it is a trademark, but it should not be.

^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch
  2005-07-12 11:25               ` Pavel Machek
@ 2005-07-12 11:45                 ` Nigel Cunningham
  0 siblings, 0 replies; 187+ messages in thread
From: Nigel Cunningham @ 2005-07-12 11:45 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Christoph Hellwig, Linux Kernel Mailing List

Hi.

On Tue, 2005-07-12 at 21:25, Pavel Machek wrote:
> > > 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.

It does for you :>

Regards,

Nigel
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 


^ permalink raw reply	[flat|nested] 187+ messages in thread

* Re: [PATCH] [43/48] Suspend2 2.1.9.8 for 2.6.12: 619-userspace-nofreeze.patch
  2005-07-12  6:29     ` Nigel Cunningham
@ 2005-07-12 14:21       ` Christoph Hellwig
  0 siblings, 0 replies; 187+ messages in thread
From: Christoph Hellwig @ 2005-07-12 14:21 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Christoph Hellwig, Linux Kernel Mailing List

On Tue, Jul 12, 2005 at 04:29:00PM +1000, Nigel Cunningham wrote:
> People need to be able to recognise when this happens. They therefore
> need some feedback to know that the process is not hung, and to be able
> to say where it hung when it does.

this is called printk.


^ permalink raw reply	[flat|nested] 187+ messages in thread

end of thread, other threads:[~2005-07-12 14:22 UTC | newest]

Thread overview: 187+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-07-06  2:20 [0/48] Suspend2 2.1.9.8 for 2.6.12 Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [1/48] Suspend2 2.1.9.8 for 2.6.12: submit_intro Nigel Cunningham
2005-07-06  6:37   ` Pekka Enberg
2005-07-06  8:12   ` Pavel Machek
2005-07-06  2:20 ` [PATCH] [4/48] Suspend2 2.1.9.8 for 2.6.12: 302-init-hooks.patch Nigel Cunningham
2005-07-06  8:38   ` Shaohua Li
2005-07-06  8:35     ` Nigel Cunningham
2005-07-06 15:38     ` Bernard Blackham
2005-07-06  2:20 ` [PATCH] [3/48] Suspend2 2.1.9.8 for 2.6.12: 301-proc-acpi-sleep-activate-hook.patch Nigel Cunningham
2005-07-10 23:03   ` Christoph Hellwig
2005-07-12  6:45     ` Nigel Cunningham
     [not found]       ` <E1DsHMp-00062f-00@chiark.greenend.org.uk>
2005-07-12 10:07         ` Nigel Cunningham
2005-07-12 10:22           ` Matthew Garrett
2005-07-12 10:34             ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [2/48] Suspend2 2.1.9.8 for 2.6.12: 300-reboot-handler-hook.patch Nigel Cunningham
2005-07-06 10:08   ` Pekka Enberg
2005-07-06 10:18     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [6/48] Suspend2 2.1.9.8 for 2.6.12: 351-syncthreads.patch Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [5/48] Suspend2 2.1.9.8 for 2.6.12: 350-workthreads.patch Nigel Cunningham
2005-07-10 23:04   ` Christoph Hellwig
2005-07-12  6:40     ` Nigel Cunningham
2005-07-12 10:57       ` Pavel Machek
2005-07-12 11:07         ` Nigel Cunningham
2005-07-12 11:15           ` Pavel Machek
2005-07-12 11:25             ` Nigel Cunningham
2005-07-12 11:25               ` Pavel Machek
2005-07-12 11:45                 ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [8/48] Suspend2 2.1.9.8 for 2.6.12: 353-disable-highmem-tlb-flush-for-copyback.patch Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [10/48] Suspend2 2.1.9.8 for 2.6.12: 360-reset-kswapd-max-order-after-resume.patch Nigel Cunningham
2005-07-10 23:09   ` Christoph Hellwig
2005-07-12  9:05     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [13/48] Suspend2 2.1.9.8 for 2.6.12: 403-debug-pagealloc-support.patch Nigel Cunningham
2005-07-10 23:02   ` Christoph Hellwig
2005-07-12  6:48     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [9/48] Suspend2 2.1.9.8 for 2.6.12: 354-disable-mce-checking-during-suspend-avoid-smp-deadlock.patch Nigel Cunningham
2005-07-09 11:49   ` Pavel Machek
2005-07-09 12:02     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [14/48] Suspend2 2.1.9.8 for 2.6.12: 404-check-mounts-support.patch Nigel Cunningham
2005-07-06  8:15   ` Pavel Machek
2005-07-06  8:30     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [11/48] Suspend2 2.1.9.8 for 2.6.12: 401-e820-table-support.patch Nigel Cunningham
2005-07-06  3:35   ` Zwane Mwaikambo
2005-07-06  3:44     ` Nigel Cunningham
2005-07-06  8:04       ` Pavel Machek
2005-07-06 13:29       ` Zwane Mwaikambo
2005-07-06  2:20 ` [PATCH] [12/48] Suspend2 2.1.9.8 for 2.6.12: 402-mtrr-remove-sysdev.patch Nigel Cunningham
2005-07-10 23:07   ` Christoph Hellwig
2005-07-12  6:33     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [7/48] Suspend2 2.1.9.8 for 2.6.12: 352-disable-pdflush-during-suspend.patch Nigel Cunningham
2005-07-06  3:34   ` Zwane Mwaikambo
2005-07-06  3:43     ` Nigel Cunningham
2005-07-06 13:27       ` Zwane Mwaikambo
2005-07-06  8:08   ` Pavel Machek
2005-07-06  9:52   ` Russell King
2005-07-10 23:07   ` Christoph Hellwig
2005-07-06  2:20 ` [PATCH] [17/48] Suspend2 2.1.9.8 for 2.6.12: 500-version-specific-i386.patch Nigel Cunningham
2005-07-06  3:43   ` YOSHIFUJI Hideaki / 吉藤英明
2005-07-06  2:20 ` [PATCH] [23/48] Suspend2 2.1.9.8 for 2.6.12: 600-suspend-header.patch Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [21/48] Suspend2 2.1.9.8 for 2.6.12: 550-documentation.patch Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [18/48] Suspend2 2.1.9.8 for 2.6.12: 501-tlb-flushing-functions.patch Nigel Cunningham
2005-07-09 11:52   ` Pavel Machek
2005-07-06  2:20 ` [PATCH] [16/48] Suspend2 2.1.9.8 for 2.6.12: 406-dynamic-pageflags.patch Nigel Cunningham
2005-07-06  7:46   ` Shaohua Li
2005-07-06  8:13     ` Nigel Cunningham
2005-07-06  8:30       ` Shaohua Li
2005-07-06  2:20 ` [PATCH] [22/48] Suspend2 2.1.9.8 for 2.6.12: 560-Kconfig-and-Makefile-for-suspend2.patch Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [19/48] Suspend2 2.1.9.8 for 2.6.12: 510-version-specific-mac.patch Nigel Cunningham
2005-07-06  3:49   ` Nigel Cunningham
2005-07-06  5:30     ` hugang
2005-07-06  6:03       ` Nigel Cunningham
2005-07-06  3:53   ` Zwane Mwaikambo
2005-07-06  3:59     ` Nigel Cunningham
2005-07-06 13:40       ` Zwane Mwaikambo
2005-07-06  5:58   ` Pekka Enberg
2005-07-06  6:21     ` Nigel Cunningham
2005-07-06 10:04     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [15/48] Suspend2 2.1.9.8 for 2.6.12: 405-clear-swapfile-bdev-in-swapoff.patch Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [20/48] Suspend2 2.1.9.8 for 2.6.12: 520-version-specific-x86_64.patch Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [31/48] Suspend2 2.1.9.8 for 2.6.12: 608-compression.patch Nigel Cunningham
2005-07-09 11:55   ` Pavel Machek
2005-07-09 12:15     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [25/48] Suspend2 2.1.9.8 for 2.6.12: 602-smp.patch Nigel Cunningham
2005-07-06 12:03   ` Pekka Enberg
2005-07-06 13:21     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [24/48] Suspend2 2.1.9.8 for 2.6.12: 601-kernel_power_power-header.patch Nigel Cunningham
2005-07-06  3:42   ` Zwane Mwaikambo
2005-07-06  3:45     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [32/48] Suspend2 2.1.9.8 for 2.6.12: 609-driver-model.patch Nigel Cunningham
2005-07-06 10:10   ` Pekka Enberg
2005-07-06 12:05     ` Nigel Cunningham
2005-07-06 12:14     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [26/48] Suspend2 2.1.9.8 for 2.6.12: 603-suspend2_common-headers.patch Nigel Cunningham
2005-07-06 10:22   ` Pekka Enberg
2005-07-06 11:41     ` Nigel Cunningham
2005-07-06 11:52       ` Pekka J Enberg
2005-07-06 11:58     ` [PATCH] [26/48] " Nigel Cunningham
2005-07-09 11:53   ` Pavel Machek
2005-07-06  2:20 ` [PATCH] [30/48] Suspend2 2.1.9.8 for 2.6.12: 607-atomic-copy.patch Nigel Cunningham
2005-07-10 18:01   ` Pavel Machek
2005-07-11  8:58     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [27/48] Suspend2 2.1.9.8 for 2.6.12: 604-utility.patch Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [29/48] Suspend2 2.1.9.8 for 2.6.12: 606-all-settings.patch Nigel Cunningham
2005-07-10 18:03   ` Pavel Machek
2005-07-11  9:38     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [28/48] Suspend2 2.1.9.8 for 2.6.12: 605-kernel_power_suspend.patch Nigel Cunningham
2005-07-10 17:58   ` Pavel Machek
2005-07-12  8:39     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [38/48] Suspend2 2.1.9.8 for 2.6.12: 614-plugins.patch Nigel Cunningham
2005-07-10 18:08   ` Pavel Machek
2005-07-11 10:05     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [35/48] Suspend2 2.1.9.8 for 2.6.12: 611-io.patch Nigel Cunningham
2005-07-10 18:12   ` Pavel Machek
2005-07-12  8:38     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [40/48] Suspend2 2.1.9.8 for 2.6.12: 616-prepare_image.patch Nigel Cunningham
2005-07-10 18:13   ` Pavel Machek
2005-07-12  8:34     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [36/48] Suspend2 2.1.9.8 for 2.6.12: 612-pagedir.patch Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [34/48] Suspend2 2.1.9.8 for 2.6.12: 610-extent.patch Nigel Cunningham
2005-07-06 10:14   ` Pekka Enberg
2005-07-06  2:20 ` [PATCH] [37/48] Suspend2 2.1.9.8 for 2.6.12: 613-pageflags.patch Nigel Cunningham
2005-07-06 12:01   ` Pekka Enberg
2005-07-07  9:30     ` Nigel Cunningham
2005-07-09 12:16   ` Pavel Machek
2005-07-09 12:32     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [41/48] Suspend2 2.1.9.8 for 2.6.12: 617-proc.patch Nigel Cunningham
2005-07-06 10:03   ` Pekka Enberg
2005-07-06  2:20 ` [PATCH] [33/48] Suspend2 2.1.9.8 for 2.6.12: 610-encryption.patch Nigel Cunningham
2005-07-10 18:15   ` Pavel Machek
2005-07-12  8:34     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [39/48] Suspend2 2.1.9.8 for 2.6.12: 615-poweroff.patch Nigel Cunningham
2005-07-10 18:18   ` Pavel Machek
2005-07-12  8:31     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [47/48] Suspend2 2.1.9.8 for 2.6.12: 623-generic-block-io.patch Nigel Cunningham
2005-07-10 18:24   ` Pavel Machek
2005-07-06  2:20 ` [PATCH] [48/48] Suspend2 2.1.9.8 for 2.6.12: 624-filewriter.patch Nigel Cunningham
2005-07-06 10:07   ` Pekka Enberg
2005-07-06 10:13     ` Nigel Cunningham
2005-07-06 10:17       ` Pekka J Enberg
2005-07-09 12:10   ` [PATCH] [48/48] " Pavel Machek
2005-07-09 12:18     ` Nigel Cunningham
2005-07-10 23:14   ` Christoph Hellwig
2005-07-12  6:30     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [46/48] Suspend2 2.1.9.8 for 2.6.12: 622-swapwriter.patch Nigel Cunningham
2005-07-06  6:33   ` Pekka Enberg
2005-07-07 12:40     ` Nigel Cunningham
2005-07-07 13:05       ` Pekka J Enberg
2005-07-08 13:41         ` Nigel Cunningham
2005-07-07 13:32   ` [PATCH] [46/48] " Pekka Enberg
2005-07-07 21:16     ` Nigel Cunningham
2005-07-07 21:26       ` nickpiggin
2005-07-08 13:42         ` Nigel Cunningham
2005-07-08  5:49       ` Pekka J Enberg
2005-07-08  5:53       ` Pekka J Enberg
2005-07-06  2:20 ` [PATCH] [42/48] Suspend2 2.1.9.8 for 2.6.12: 618-core.patch Nigel Cunningham
2005-07-10 18:21   ` Pavel Machek
2005-07-12  6:59     ` Nigel Cunningham
2005-07-12  7:56       ` Pavel Machek
2005-07-06  2:20 ` [PATCH] [44/48] Suspend2 2.1.9.8 for 2.6.12: 620-userui.patch Nigel Cunningham
2005-07-10 18:22   ` Pavel Machek
2005-07-12  6:58     ` Nigel Cunningham
2005-07-06  2:20 ` [PATCH] [43/48] Suspend2 2.1.9.8 for 2.6.12: 619-userspace-nofreeze.patch Nigel Cunningham
2005-07-06  6:18   ` Pekka Enberg
2005-07-10 23:15   ` Christoph Hellwig
2005-07-12  6:29     ` Nigel Cunningham
2005-07-12 14:21       ` Christoph Hellwig
2005-07-06  2:20 ` [PATCH] [45/48] Suspend2 2.1.9.8 for 2.6.12: 621-swsusp-tidy.patch Nigel Cunningham
2005-07-06  9:55   ` Pekka Enberg
2005-07-06  6:40 ` [0/48] Suspend2 2.1.9.8 for 2.6.12 Pekka Enberg
2005-07-07 12:19   ` Nigel Cunningham
2005-07-06  8:21 ` Pavel Machek
2005-07-06  8:22 ` Pavel Machek
2005-07-06  8:33   ` Nigel Cunningham
2005-07-07  0:27   ` Nigel Cunningham
2005-07-07 12:04     ` Matthew Garrett
2005-07-07 12:15       ` Nigel Cunningham
2005-07-07 12:49         ` Matthew Garrett
2005-07-07 12:56           ` Nigel Cunningham
2005-07-07 18:54           ` Rafael J. Wysocki
2005-07-07 21:21             ` Nigel Cunningham
2005-07-08 13:30           ` Stefan Seyfried
2005-07-08 22:27             ` Nigel Cunningham
2005-07-07 19:19     ` Pavel Machek
2005-07-10 23:06 ` Christoph Hellwig
2005-07-12  6:36   ` Nigel Cunningham
2005-07-12  6:41     ` Andrew Morton
2005-07-12  6:57       ` Nigel Cunningham
2005-07-12 10:25       ` Nigel Cunningham

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).