Hi,

Christoph Hellwig writes:

>  - I have done some more work on the split patches, especially added
>    lots of .dpatch commentary.  I'll re-merged that with your
>    changes tomorrow

>  - the changelog should be much more detailed, e.g. mentioning which
>    changes we've dropped that didn't go upstream.  I'll write
>    something up on that.

Very nice.  I was kind of wondering what to do about the identical
dpatch comments and default author addresses.

I enclose a new version of modular-swsusp.dpatch.  The header file
that Kenshi's system complained about was simply missing from the
patch.  Just adding it from 2.6.6 looks alright to me.

Regards, Jens.

#! /bin/sh -e 
## <PATCHNAME>.dpatch by <[EMAIL PROTECTED]>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Makefiles, configure scripts and other build stuff adapted for
## DP: debian package creation

. $(dirname $0)/DPATCH

 * Partially modularised software suspend

--- 1.3/arch/i386/power/Makefile        2003-09-09 22:52:20 +02:00
+++ edited/arch/i386/power/Makefile     2004-06-16 15:29:58 +02:00
@@ -1,3 +1,8 @@
+swsusp-arch-y                  += swsusp_syms.o swsusp.o
+
 obj-$(CONFIG_PM)               += cpu.o
 obj-$(CONFIG_PM_DISK)          += pmdisk.o
-obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o
+
+ifneq ($(CONFIG_SOFTWARE_SUSPEND),)
+obj-y                          += swsusp-arch.o
+endif
--- 1.14/arch/i386/power/pmdisk.S       2004-05-25 11:53:07 +02:00
+++ edited/arch/i386/power/pmdisk.S     2004-06-16 15:29:58 +02:00
@@ -25,8 +25,9 @@
        movl %ecx,%cr3
 
        movl    pm_pagedir_nosave,%ebx
-       xorl    %eax, %eax
-       xorl    %edx, %edx
+       movl    pmdisk_pages, %eax
+       leal    -1(%eax), %edx
+       sall    $4, %edx
        .p2align 4,,7
 .L1455:
        movl    4(%ebx,%edx),%edi
@@ -36,13 +37,11 @@
        rep
        movsl
 
-       movl    %cr3, %ecx;
-       movl    %ecx, %cr3;  # flush TLB 
+       movl    %cr3, %eax;
+       movl    %eax, %cr3;  # flush TLB 
 
-       incl    %eax
-       addl    $16, %edx
-       cmpl    pmdisk_pages,%eax
-       jb .L1455
+       subl    $16, %edx
+       jge     .L1455
        .p2align 4,,7
 .L1453:
        movl saved_context_esp, %esp
--- 1.14/arch/i386/power/swsusp.S       2004-05-25 11:53:07 +02:00
+++ edited/arch/i386/power/swsusp.S     2004-06-16 15:29:59 +02:00
@@ -40,8 +40,9 @@
        movl %ecx,%cr3
 
        call do_magic_resume_1
-       movl $0,loop
-       cmpl $0,nr_copy_pages
+       movl nr_copy_pages,%eax
+       movl %eax,loop
+       cmpl $0,%eax
        je .L1453
        .p2align 4,,7
 .L1455:
@@ -52,8 +53,8 @@
        movl loop,%eax
        movl loop2,%edx
        sall $4,%eax
-       movl 4(%ecx,%eax),%ebx
-       movl (%ecx,%eax),%eax
+       movl -12(%ecx,%eax),%ebx
+       movl -16(%ecx,%eax),%eax
        movb (%edx,%eax),%al
        movb %al,(%edx,%ebx)
        movl %cr3, %eax;              
@@ -66,11 +67,11 @@
        cmpl $4095,%eax
        jbe .L1459
        movl loop,%eax
-       leal 1(%eax),%edx
+       leal -1(%eax),%edx
        movl %edx,loop
        movl %edx,%eax
-       cmpl nr_copy_pages,%eax
-       jb .L1455
+       cmpl $0,%eax
+       jne .L1455
        .p2align 4,,7
 .L1453:
        movl $__USER_DS,%eax
--- 1.36/arch/x86_64/kernel/Makefile    2004-05-10 12:25:59 +02:00
+++ edited/arch/x86_64/kernel/Makefile  2004-06-16 15:29:59 +02:00
@@ -19,7 +19,9 @@
 obj-$(CONFIG_X86_LOCAL_APIC)   += apic.o  nmi.o
 obj-$(CONFIG_X86_IO_APIC)      += io_apic.o mpparse.o
 obj-$(CONFIG_PM)               += suspend.o
-obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend_asm.o
+ifneq ($(CONFIG_SOFTWARE_SUSPEND),)
+obj-y                          += swsusp-arch.o
+endif
 obj-$(CONFIG_CPU_FREQ)         += cpufreq/
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
 obj-$(CONFIG_GART_IOMMU)       += pci-gart.o aperture.o
@@ -36,3 +38,4 @@
 topology-y                     += ../../i386/mach-default/topology.o
 swiotlb-$(CONFIG_SWIOTLB)      += ../../ia64/lib/swiotlb.o
 microcode-$(subst m,y,$(CONFIG_MICROCODE))  += ../../i386/kernel/microcode.o
+swsusp-arch-y                  += swsusp_syms.o suspend_asm.o
--- 1.10/drivers/acpi/sleep/proc.c      2004-03-31 15:32:27 +02:00
+++ edited/drivers/acpi/sleep/proc.c    2004-06-16 15:30:00 +02:00
@@ -2,6 +2,7 @@
 #include <linux/seq_file.h>
 #include <linux/suspend.h>
 #include <linux/bcd.h>
+#include <linux/module.h>
 #include <asm/uaccess.h>
 
 #include <acpi/acpi_bus.h>
@@ -67,12 +68,17 @@
                goto Done;
        }
        state = simple_strtoul(str, NULL, 0);
-#ifdef CONFIG_SOFTWARE_SUSPEND
        if (state == 4) {
-               software_suspend();
-               goto Done;
+               down(&software_suspend_sem);
+               if (software_suspend_module &&
+                   try_module_get(software_suspend_module)) {
+                       up(&software_suspend_sem);
+                       software_suspend_hook();
+                       module_put(software_suspend_module);
+                       goto Done;
+               }
+               up(&software_suspend_sem);
        }
-#endif
        error = acpi_suspend(state);
  Done:
        return error ? error : count;
--- 1.248/fs/buffer.c   2004-05-22 23:56:23 +02:00
+++ edited/fs/buffer.c  2004-06-16 15:30:03 +02:00
@@ -379,6 +379,8 @@
        return 0;
 }
 
+EXPORT_SYMBOL(sys_sync);
+
 void emergency_sync(void)
 {
        pdflush_operation(do_sync, 0);
--- 1.29/include/linux/suspend.h        2004-04-12 19:55:24 +02:00
+++ edited/include/linux/suspend.h      2004-06-16 15:30:03 +02:00
@@ -4,6 +4,7 @@
 #ifdef CONFIG_X86
 #include <asm/suspend.h>
 #endif
+#include <asm/semaphore.h>
 #include <linux/swap.h>
 #include <linux/notifier.h>
 #include <linux/config.h>
@@ -42,23 +43,10 @@
 /* mm/page_alloc.c */
 extern void drain_local_pages(void);
 
-/* kernel/power/swsusp.c */
-extern int software_suspend(void);
-
 extern unsigned int nr_copy_pages __nosavedata;
 extern suspend_pagedir_t *pagedir_nosave __nosavedata;
 
-#else  /* CONFIG_SOFTWARE_SUSPEND */
-static inline int software_suspend(void)
-{
-       printk("Warning: fake suspend called\n");
-       return -EPERM;
-}
-#define software_resume()              do { } while(0)
-#endif /* CONFIG_SOFTWARE_SUSPEND */
-
 
-#ifdef CONFIG_PM
 extern void refrigerator(unsigned long);
 extern int freeze_processes(void);
 extern void thaw_processes(void);
@@ -86,5 +74,10 @@
 asmlinkage void do_magic_resume_2(void);
 asmlinkage void do_magic_suspend_1(void);
 asmlinkage void do_magic_suspend_2(void);
+
+struct module;
+extern struct module *software_suspend_module;
+extern int (*software_suspend_hook)(void);
+extern struct semaphore software_suspend_sem;
 
 #endif /* _LINUX_SWSUSP_H */
--- 1.87/kernel/sys.c   2004-06-01 17:16:26 +02:00
+++ edited/kernel/sys.c 2004-06-16 15:30:02 +02:00
@@ -27,6 +27,7 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/unistd.h>
+#include <asm/semaphore.h>
 
 #ifndef SET_UNALIGN_CTL
 # define SET_UNALIGN_CTL(a,b)  (-EINVAL)
@@ -427,6 +428,14 @@
 }
 
 
+struct module *software_suspend_module;
+int (*software_suspend_hook)(void);
+DECLARE_MUTEX(software_suspend_sem);
+
+EXPORT_SYMBOL(software_suspend_module);
+EXPORT_SYMBOL(software_suspend_hook);
+EXPORT_SYMBOL(software_suspend_sem);
+
 /*
  * Reboot system call: for obvious reasons only root may call it,
  * and even root needs to set up some magic numbers in the registers
@@ -503,14 +512,20 @@
                machine_restart(buffer);
                break;
 
-#ifdef CONFIG_SOFTWARE_SUSPEND
        case LINUX_REBOOT_CMD_SW_SUSPEND:
-               {
-                       int ret = software_suspend();
+               down(&software_suspend_sem);
+               if (software_suspend_module &&
+                   try_module_get(software_suspend_module)) {
+                       int ret;
+
+                       up(&software_suspend_sem);
+                       ret = software_suspend_hook();
+                       module_put(software_suspend_module);
                        unlock_kernel();
                        return ret;
                }
-#endif
+               up(&software_suspend_sem);
+               /* fall through */
 
        default:
                unlock_kernel();
--- 1.7/kernel/power/Kconfig    2004-04-12 19:55:34 +02:00
+++ edited/kernel/power/Kconfig 2004-06-16 15:30:00 +02:00
@@ -19,7 +19,7 @@
          sending the processor to sleep and saving power.
 
 config SOFTWARE_SUSPEND
-       bool "Software Suspend (EXPERIMENTAL)"
+       tristate "Software Suspend (EXPERIMENTAL)"
        depends on EXPERIMENTAL && PM && SWAP
        ---help---
          Enable the possibilty of suspendig machine. It doesn't need APM.
--- 1.9/kernel/power/Makefile   2003-09-09 22:52:20 +02:00
+++ edited/kernel/power/Makefile        2004-06-16 15:30:01 +02:00
@@ -3,3 +3,7 @@
 obj-$(CONFIG_PM_DISK)          += disk.o pmdisk.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)      += poweroff.o
+
+ifneq ($(CONFIG_SOFTWARE_SUSPEND),)
+obj-y                          += swsusp-core.o
+endif
--- 1.6/kernel/power/console.c  2004-02-04 06:28:11 +01:00
+++ edited/kernel/power/console.c       2004-06-16 15:30:01 +02:00
@@ -7,6 +7,7 @@
 #include <linux/vt_kern.h>
 #include <linux/kbd_kern.h>
 #include <linux/console.h>
+#include <linux/module.h>
 #include "power.h"
 
 static int new_loglevel = 10;
@@ -43,6 +44,8 @@
        return 0;
 }
 
+EXPORT_SYMBOL(pm_prepare_console);
+
 void pm_restore_console(void)
 {
        console_loglevel = orig_loglevel;
@@ -53,3 +56,5 @@
 #endif
        return;
 }
+
+EXPORT_SYMBOL(pm_restore_console);
--- 1.8/kernel/power/process.c  2004-05-22 10:24:05 +02:00
+++ edited/kernel/power/process.c       2004-06-16 15:30:01 +02:00
@@ -53,6 +53,8 @@
        current->state = save;
 }
 
+EXPORT_SYMBOL(refrigerator);
+
 /* 0 = success, else # of processes that we failed to stop */
 int freeze_processes(void)
 {
@@ -95,6 +97,8 @@
        return 0;
 }
 
+EXPORT_SYMBOL(freeze_processes);
+
 void thaw_processes(void)
 {
        struct task_struct *g, *p;
@@ -117,4 +121,4 @@
        printk( " done\n" );
 }
 
-EXPORT_SYMBOL(refrigerator);
+EXPORT_SYMBOL(thaw_processes);
--- 1.81/kernel/power/swsusp.c  2004-05-22 10:24:07 +02:00
+++ edited/kernel/power/swsusp.c        2004-06-16 15:30:01 +02:00
@@ -39,548 +39,38 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/suspend.h>
-#include <linux/smp_lock.h>
-#include <linux/file.h>
 #include <linux/utsname.h>
 #include <linux/version.h>
-#include <linux/delay.h>
-#include <linux/reboot.h>
-#include <linux/bitops.h>
-#include <linux/vt_kern.h>
-#include <linux/kbd_kern.h>
-#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>
-#include <linux/swapops.h>
-#include <linux/bootmem.h>
 #include <linux/syscalls.h>
 #include <linux/console.h>
-#include <linux/highmem.h>
-
-#include <asm/uaccess.h>
-#include <asm/mmu_context.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/kdev_t.h>
+#include <linux/blkdev.h>
+#include <linux/buffer_head.h>
+#include <linux/swapops.h>
+#include <linux/cpumask.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/pagemap.h>
 
 #include "power.h"
+#include "swsusp.h"
 
 unsigned char software_suspend_enabled = 0;
 
-#define NORESUME               1
-#define RESUME_SPECIFIED       2
-
-/* References to section boundaries */
-extern char __nosave_begin, __nosave_end;
-
-extern int is_head_of_free_region(struct page *);
-
-/* Locks */
-spinlock_t suspend_pagedir_lock __nosavedata = SPIN_LOCK_UNLOCKED;
-
-/* Variables to be preserved over suspend */
-static int pagedir_order_check;
-static int nr_copy_pages_check;
-
-static int resume_status;
-static char resume_file[256] = "";                     /* For resume= kernel 
option */
-static dev_t resume_device;
-/* Local variables that should not be affected by save */
-unsigned int nr_copy_pages __nosavedata = 0;
-
-/* Suspend pagedir is allocated before final copy, therefore it
-   must be freed after resume 
-
-   Warning: this is evil. There are actually two pagedirs at time of
-   resume. One is "pagedir_save", which is empty frame allocated at
-   time of suspend, that must be freed. Second is "pagedir_nosave", 
-   allocated at time of resume, that travels through memory not to
-   collide with anything.
-
-   Warning: this is even more evil than it seems. Pagedirs this file
-   talks about are completely different from page directories used by
-   MMU hardware.
- */
-suspend_pagedir_t *pagedir_nosave __nosavedata = NULL;
-static suspend_pagedir_t *pagedir_save;
-static int pagedir_order __nosavedata = 0;
-
-struct link {
-       char dummy[PAGE_SIZE - sizeof(swp_entry_t)];
-       swp_entry_t next;
-};
-
-union diskpage {
-       union swap_header swh;
-       struct link link;
-       struct suspend_header sh;
-};
-
-/*
- * XXX: We try to keep some more pages free so that I/O operations succeed
- * without paging. Might this be more?
- */
-#define PAGES_FOR_IO   512
-
-static const char name_suspend[] = "Suspend Machine: ";
-static const char name_resume[] = "Resume Machine: ";
-
-/*
- * Debug
- */
-#define        DEBUG_DEFAULT
-#undef DEBUG_PROCESS
-#undef DEBUG_SLOW
-#define TEST_SWSUSP 0          /* Set to 1 to reboot instead of halt machine 
after suspension */
-
-#ifdef DEBUG_DEFAULT
-# define PRINTK(f, a...)       printk(f, ## a)
-#else
-# define PRINTK(f, a...)               do { } while(0)
-#endif
-
-#ifdef DEBUG_SLOW
-#define MDELAY(a) mdelay(a)
-#else
-#define MDELAY(a) do { } while(0)
-#endif
+static int noresume __initdata;
+static char resume_file[256] __initdata;
 
 /*
  * Saving part...
  */
 
-static __inline__ int fill_suspend_header(struct suspend_header *sh)
-{
-       memset((char *)sh, 0, sizeof(*sh));
-
-       sh->version_code = LINUX_VERSION_CODE;
-       sh->num_physpages = num_physpages;
-       strncpy(sh->machine, system_utsname.machine, 8);
-       strncpy(sh->version, system_utsname.version, 20);
-       /* FIXME: Is this bogus? --RR */
-       sh->num_cpus = num_online_cpus();
-       sh->page_size = PAGE_SIZE;
-       sh->suspend_pagedir = pagedir_nosave;
-       BUG_ON (pagedir_save != pagedir_nosave);
-       sh->num_pbes = nr_copy_pages;
-       /* TODO: needed? mounted fs' last mounted date comparison
-        * [so they haven't been mounted since last suspend.
-        * Maybe it isn't.] [we'd need to do this for _all_ fs-es]
-        */
-       return 0;
-}
-
-/* We memorize in swapfile_used what swap devices are used for suspension */
-#define SWAPFILE_UNUSED    0
-#define SWAPFILE_SUSPEND   1   /* This is the suspending device */
-#define SWAPFILE_IGNORED   2   /* Those are other swap devices ignored for 
suspension */
-
-static unsigned short swapfile_used[MAX_SWAPFILES];
-static unsigned short root_swap;
-#define MARK_SWAP_SUSPEND 0
-#define MARK_SWAP_RESUME 2
-
-static void mark_swapfiles(swp_entry_t prev, int mode)
-{
-       swp_entry_t entry;
-       union diskpage *cur;
-       struct page *page;
-
-       if (root_swap == 0xFFFF)  /* ignored */
-               return;
-
-       page = alloc_page(GFP_ATOMIC);
-       if (!page)
-               panic("Out of memory in mark_swapfiles");
-       cur = page_address(page);
-       /* XXX: this is dirty hack to get first page of swap file */
-       entry = swp_entry(root_swap, 0);
-       rw_swap_page_sync(READ, entry, page);
-
-       if (mode == MARK_SWAP_RESUME) {
-               if (!memcmp("S1",cur->swh.magic.magic,2))
-                       memcpy(cur->swh.magic.magic,"SWAP-SPACE",10);
-               else if (!memcmp("S2",cur->swh.magic.magic,2))
-                       memcpy(cur->swh.magic.magic,"SWAPSPACE2",10);
-               else printk("%sUnable to find suspended-data signature (%.10s - 
misspelled?\n", 
-                       name_resume, cur->swh.magic.magic);
-       } else {
-               if ((!memcmp("SWAP-SPACE",cur->swh.magic.magic,10)))
-                       memcpy(cur->swh.magic.magic,"S1SUSP....",10);
-               else if ((!memcmp("SWAPSPACE2",cur->swh.magic.magic,10)))
-                       memcpy(cur->swh.magic.magic,"S2SUSP....",10);
-               else panic("\nSwapspace is not swapspace (%.10s)\n", 
cur->swh.magic.magic);
-               cur->link.next = prev; /* prev is the first/last swap page of 
the resume area */
-               /* link.next lies *no more* in last 4/8 bytes of magic */
-       }
-       rw_swap_page_sync(WRITE, entry, page);
-       __free_page(page);
-}
-
-
-/*
- * Check whether the swap device is the specified resume
- * device, irrespective of whether they are specified by
- * identical names.
- *
- * (Thus, device inode aliasing is allowed.  You can say /dev/hda4
- * instead of /dev/ide/host0/bus0/target0/lun0/part4 [if using devfs]
- * and they'll be considered the same device.  This is *necessary* for
- * devfs, since the resume code can only recognize the form /dev/hda4,
- * but the suspend code would see the long name.)
- */
-static int is_resume_device(const struct swap_info_struct *swap_info)
-{
-       struct file *file = swap_info->swap_file;
-       struct inode *inode = file->f_dentry->d_inode;
-
-       return S_ISBLK(inode->i_mode) &&
-               resume_device == MKDEV(imajor(inode), iminor(inode));
-}
-
-static void read_swapfiles(void) /* This is called before saving image */
-{
-       int i, len;
-       
-       len=strlen(resume_file);
-       root_swap = 0xFFFF;
-       
-       swap_list_lock();
-       for(i=0; i<MAX_SWAPFILES; i++) {
-               if (swap_info[i].flags == 0) {
-                       swapfile_used[i]=SWAPFILE_UNUSED;
-               } else {
-                       if(!len) {
-                               printk(KERN_WARNING "resume= option should be 
used to set suspend device" );
-                               if(root_swap == 0xFFFF) {
-                                       swapfile_used[i] = SWAPFILE_SUSPEND;
-                                       root_swap = i;
-                               } else
-                                       swapfile_used[i] = SWAPFILE_IGNORED;    
                          
-                       } else {
-                               /* we ignore all swap devices that are not the 
resume_file */
-                               if (is_resume_device(&swap_info[i])) {
-                                       swapfile_used[i] = SWAPFILE_SUSPEND;
-                                       root_swap = i;
-                               } else {
-                                       swapfile_used[i] = SWAPFILE_IGNORED;
-                               }
-                       }
-               }
-       }
-       swap_list_unlock();
-}
-
-static void lock_swapdevices(void) /* This is called after saving image so 
modification
-                                     will be lost after resume... and that's 
what we want. */
-{
-       int i;
-
-       swap_list_lock();
-       for(i = 0; i< MAX_SWAPFILES; i++)
-               if(swapfile_used[i] == SWAPFILE_IGNORED) {
-                       swap_info[i].flags ^= 0xFF; /* we make the device 
unusable. A new call to
-                                                      lock_swapdevices can 
unlock the devices. */
-               }
-       swap_list_unlock();
-}
-
-/**
- *    write_suspend_image - Write entire image to disk.
- *
- *    After writing suspend signature to the disk, suspend may no
- *    longer fail: we have ready-to-run image in swap, and rollback
- *    would happen on next reboot -- corrupting data.
- *
- *    Note: The buffer we allocate to use to write the suspend header is
- *    not freed; its not needed since the system is going down anyway
- *    (plus it causes an oops and I'm lazy^H^H^H^Htoo busy).
- */
-static int write_suspend_image(void)
-{
-       int i;
-       swp_entry_t entry, prev = { 0 };
-       int nr_pgdir_pages = SUSPEND_PD_PAGES(nr_copy_pages);
-       union diskpage *cur,  *buffer = (union diskpage 
*)get_zeroed_page(GFP_ATOMIC);
-       unsigned long address;
-       struct page *page;
-
-       if (!buffer)
-               return -ENOMEM;
-
-       printk( "Writing data to swap (%d pages): ", nr_copy_pages );
-       for (i=0; i<nr_copy_pages; i++) {
-               if (!(i%100))
-                       printk( "." );
-               if (!(entry = get_swap_page()).val)
-                       panic("\nNot enough swapspace when writing data" );
-               
-               if (swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
-                       panic("\nPage %d: not enough swapspace on suspend 
device", i );
-           
-               address = (pagedir_nosave+i)->address;
-               page = virt_to_page(address);
-               rw_swap_page_sync(WRITE, entry, page);
-               (pagedir_nosave+i)->swap_address = entry;
-       }
-       printk( "|\n" );
-       printk( "Writing pagedir (%d pages): ", nr_pgdir_pages);
-       for (i=0; i<nr_pgdir_pages; i++) {
-               cur = (union diskpage *)((char *) pagedir_nosave)+i;
-               BUG_ON ((char *) cur != (((char *) pagedir_nosave) + 
i*PAGE_SIZE));
-               printk( "." );
-               if (!(entry = get_swap_page()).val) {
-                       printk(KERN_CRIT "Not enough swapspace when writing 
pgdir\n" );
-                       panic("Don't know how to recover");
-                       free_page((unsigned long) buffer);
-                       return -ENOSPC;
-               }
-
-               if(swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
-                       panic("\nNot enough swapspace for pagedir on suspend 
device" );
-
-               BUG_ON (sizeof(swp_entry_t) != sizeof(long));
-               BUG_ON (PAGE_SIZE % sizeof(struct pbe));
-
-               cur->link.next = prev;                          
-               page = virt_to_page((unsigned long)cur);
-               rw_swap_page_sync(WRITE, entry, page);
-               prev = entry;
-       }
-       printk("H");
-       BUG_ON (sizeof(struct suspend_header) > PAGE_SIZE-sizeof(swp_entry_t));
-       BUG_ON (sizeof(union diskpage) != PAGE_SIZE);
-       BUG_ON (sizeof(struct link) != PAGE_SIZE);
-       if (!(entry = get_swap_page()).val)
-               panic( "\nNot enough swapspace when writing header" );
-       if (swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
-               panic("\nNot enough swapspace for header on suspend device" );
-
-       cur = (void *) buffer;
-       if (fill_suspend_header(&cur->sh))
-               BUG();          /* Not a BUG_ON(): we want fill_suspend_header 
to be called, always */
-               
-       cur->link.next = prev;
-
-       page = virt_to_page((unsigned long)cur);
-       rw_swap_page_sync(WRITE, entry, page);
-       prev = entry;
-
-       printk( "S" );
-       mark_swapfiles(prev, MARK_SWAP_SUSPEND);
-       printk( "|\n" );
-
-       MDELAY(1000);
-       return 0;
-}
-
-#ifdef CONFIG_HIGHMEM
-struct highmem_page {
-       char *data;
-       struct page *page;
-       struct highmem_page *next;
-};
-
-struct highmem_page *highmem_copy = NULL;
-
-static int save_highmem_zone(struct zone *zone)
-{
-       unsigned long zone_pfn;
-       for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
-               struct page *page;
-               struct highmem_page *save;
-               void *kaddr;
-               unsigned long pfn = zone_pfn + zone->zone_start_pfn;
-               int chunk_size;
-
-               if (!(pfn%1000))
-                       printk(".");
-               if (!pfn_valid(pfn))
-                       continue;
-               page = pfn_to_page(pfn);
-               /*
-                * This condition results from rvmalloc() sans vmalloc_32()
-                * and architectural memory reservations. This should be
-                * corrected eventually when the cases giving rise to this
-                * are better understood.
-                */
-               if (PageReserved(page)) {
-                       printk("highmem reserved page?!\n");
-                       continue;
-               }
-               if ((chunk_size = is_head_of_free_region(page))) {
-                       pfn += chunk_size - 1;
-                       zone_pfn += chunk_size - 1;
-                       continue;
-               }
-               save = kmalloc(sizeof(struct highmem_page), GFP_ATOMIC);
-               if (!save)
-                       return -ENOMEM;
-               save->next = highmem_copy;
-               save->page = page;
-               save->data = (void *) get_zeroed_page(GFP_ATOMIC);
-               if (!save->data) {
-                       kfree(save);
-                       return -ENOMEM;
-               }
-               kaddr = kmap_atomic(page, KM_USER0);
-               memcpy(save->data, kaddr, PAGE_SIZE);
-               kunmap_atomic(kaddr, KM_USER0);
-               highmem_copy = save;
-       }
-       return 0;
-}
-
-static int save_highmem(void)
-{
-       struct zone *zone;
-       int res = 0;
-       for_each_zone(zone) {
-               if (is_highmem(zone))
-                       res = save_highmem_zone(zone);
-               if (res)
-                       return res;
-       }
-       return 0;
-}
-
-static int restore_highmem(void)
-{
-       while (highmem_copy) {
-               struct highmem_page *save = highmem_copy;
-               void *kaddr;
-               highmem_copy = save->next;
-
-               kaddr = kmap_atomic(save->page, KM_USER0);
-               memcpy(kaddr, save->data, PAGE_SIZE);
-               kunmap_atomic(kaddr, KM_USER0);
-               free_page((long) save->data);
-               kfree(save);
-       }
-       return 0;
-}
-#endif
-
-static int pfn_is_nosave(unsigned long pfn)
-{
-       unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
-       unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> 
PAGE_SHIFT;
-       return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
-}
-
-/* if *pagedir_p != NULL it also copies the counted pages */
-static int count_and_copy_zone(struct zone *zone, struct pbe **pagedir_p)
-{
-       unsigned long zone_pfn, chunk_size, nr_copy_pages = 0;
-       struct pbe *pbe = *pagedir_p;
-       for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
-               struct page *page;
-               unsigned long pfn = zone_pfn + zone->zone_start_pfn;
-
-               if (!(pfn%1000))
-                       printk(".");
-               if (!pfn_valid(pfn))
-                       continue;
-               page = pfn_to_page(pfn);
-               BUG_ON(PageReserved(page) && PageNosave(page));
-               if (PageNosave(page))
-                       continue;
-               if (PageReserved(page) && pfn_is_nosave(pfn)) {
-                       PRINTK("[nosave pfn 0x%lx]", pfn);
-                       continue;
-               }
-               if ((chunk_size = is_head_of_free_region(page))) {
-                       pfn += chunk_size - 1;
-                       zone_pfn += chunk_size - 1;
-                       continue;
-               }
-               nr_copy_pages++;
-               if (!pbe)
-                       continue;
-               pbe->orig_address = (long) page_address(page);
-               copy_page((void *)pbe->address, (void *)pbe->orig_address);
-               pbe++;
-       }
-       *pagedir_p = pbe;
-       return nr_copy_pages;
-}
-
-static int count_and_copy_data_pages(struct pbe *pagedir_p)
-{
-       int nr_copy_pages = 0;
-       struct zone *zone;
-       for_each_zone(zone) {
-               if (!is_highmem(zone))
-                       nr_copy_pages += count_and_copy_zone(zone, &pagedir_p);
-       }
-       return nr_copy_pages;
-}
-
-static void free_suspend_pagedir_zone(struct zone *zone, unsigned long pagedir)
-{
-       unsigned long zone_pfn, pagedir_end, pagedir_pfn, pagedir_end_pfn;
-       pagedir_end = pagedir + (PAGE_SIZE << pagedir_order);
-       pagedir_pfn = __pa(pagedir) >> PAGE_SHIFT;
-       pagedir_end_pfn = __pa(pagedir_end) >> PAGE_SHIFT;
-       for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
-               struct page *page;
-               unsigned long pfn = zone_pfn + zone->zone_start_pfn;
-               if (!pfn_valid(pfn))
-                       continue;
-               page = pfn_to_page(pfn);
-               if (!TestClearPageNosave(page))
-                       continue;
-               else if (pfn >= pagedir_pfn && pfn < pagedir_end_pfn)
-                       continue;
-               __free_page(page);
-       }
-}
-
-static void free_suspend_pagedir(unsigned long this_pagedir)
-{
-       struct zone *zone;
-       for_each_zone(zone) {
-               if (!is_highmem(zone))
-                       free_suspend_pagedir_zone(zone, this_pagedir);
-       }
-       free_pages(this_pagedir, pagedir_order);
-}
-
-static suspend_pagedir_t *create_suspend_pagedir(int nr_copy_pages)
-{
-       int i;
-       suspend_pagedir_t *pagedir;
-       struct pbe *p;
-       struct page *page;
-
-       pagedir_order = get_bitmask_order(SUSPEND_PD_PAGES(nr_copy_pages));
-
-       p = pagedir = (suspend_pagedir_t *)__get_free_pages(GFP_ATOMIC | 
__GFP_COLD, pagedir_order);
-       if (!pagedir)
-               return NULL;
-
-       page = virt_to_page(pagedir);
-       for(i=0; i < 1<<pagedir_order; i++)
-               SetPageNosave(page++);
-               
-       while(nr_copy_pages--) {
-               p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
-               if (!p->address) {
-                       free_suspend_pagedir((unsigned long) pagedir);
-                       return NULL;
-               }
-               SetPageNosave(virt_to_page(p->address));
-               p->orig_address = 0;
-               p++;
-       }
-       return pagedir;
-}
-
 static int prepare_suspend_processes(void)
 {
        sys_sync();     /* Syncing needs pdflushd, so do it before stopping 
processes */
@@ -605,216 +95,11 @@
        printk("|\n");
 }
 
-static int suspend_prepare_image(void)
-{
-       struct sysinfo i;
-       unsigned int nr_needed_pages = 0;
-
-       pagedir_nosave = NULL;
-       printk( "/critical section: ");
-#ifdef CONFIG_HIGHMEM
-       printk( "handling highmem" );
-       if (save_highmem()) {
-               printk(KERN_CRIT "%sNot enough free pages for highmem\n", 
name_suspend);
-               return -ENOMEM;
-       }
-       printk(", ");
-#endif
-
-       printk("counting pages to copy" );
-       drain_local_pages();
-       nr_copy_pages = count_and_copy_data_pages(NULL);
-       nr_needed_pages = nr_copy_pages + PAGES_FOR_IO;
-       
-       printk(" (pages needed: %d+%d=%d free: 
%d)\n",nr_copy_pages,PAGES_FOR_IO,nr_needed_pages,nr_free_pages());
-       if(nr_free_pages() < nr_needed_pages) {
-               printk(KERN_CRIT "%sCouldn't get enough free pages, on %d pages 
short\n",
-                      name_suspend, nr_needed_pages-nr_free_pages());
-               root_swap = 0xFFFF;
-               return -ENOMEM;
-       }
-       si_swapinfo(&i);        /* FIXME: si_swapinfo(&i) returns all swap 
devices information.
-                                  We should only consider resume_device. */
-       if (i.freeswap < nr_needed_pages)  {
-               printk(KERN_CRIT "%sThere's not enough swap space available, on 
%ld pages short\n",
-                      name_suspend, nr_needed_pages-i.freeswap);
-               return -ENOSPC;
-       }
-
-       PRINTK( "Alloc pagedir\n" ); 
-       pagedir_save = pagedir_nosave = create_suspend_pagedir(nr_copy_pages);
-       if (!pagedir_nosave) {
-               /* Pagedir is big, one-chunk allocation. It is easily possible 
for this allocation to fail */
-               printk(KERN_CRIT "%sCouldn't allocate continuous pagedir\n", 
name_suspend);
-               return -ENOMEM;
-       }
-       nr_copy_pages_check = nr_copy_pages;
-       pagedir_order_check = pagedir_order;
-
-       drain_local_pages();    /* During allocating of suspend pagedir, new 
cold pages may appear. Kill them */
-       if (nr_copy_pages != count_and_copy_data_pages(pagedir_nosave)) /* copy 
*/
-               BUG();
-
-       /*
-        * End of critical section. From now on, we can write to memory,
-        * but we should not touch disk. This specially means we must _not_
-        * touch swap space! Except we must write out our image of course.
-        */
-
-       printk( "critical section/: done (%d pages copied)\n", nr_copy_pages );
-       return 0;
-}
-
-static void suspend_save_image(void)
-{
-       device_resume();
-
-       lock_swapdevices();
-       write_suspend_image();
-       lock_swapdevices();     /* This will unlock ignored swap devices since 
writing is finished */
-
-       /* It is important _NOT_ to umount filesystems at this point. We want
-        * them synced (in case something goes wrong) but we DO not want to mark
-        * filesystem clean: it is not. (And it does not matter, if we resume
-        * correctly, we'll mark system clean, anyway.)
-        */
-}
-
-static void suspend_power_down(void)
-{
-       extern int C_A_D;
-       C_A_D = 0;
-       printk(KERN_EMERG "%s%s Trying to power down.\n", name_suspend, 
TEST_SWSUSP ? "Disable TEST_SWSUSP. NOT ": "");
-#ifdef CONFIG_VT
-       PRINTK(KERN_EMERG "shift_state: %04x\n", shift_state);
-       mdelay(1000);
-       if (TEST_SWSUSP ^ (!!(shift_state & (1 << KG_CTRL))))
-               machine_restart(NULL);
-       else
-#endif
-       {
-               device_shutdown();
-               machine_power_off();
-       }
-
-       printk(KERN_EMERG "%sProbably not capable for powerdown. System 
halted.\n", name_suspend);
-       machine_halt();
-       while (1);
-       /* NOTREACHED */
-}
-
-/*
- * Magic happens here
- */
-
-asmlinkage void do_magic_resume_1(void)
-{
-       barrier();
-       mb();
-       spin_lock_irq(&suspend_pagedir_lock);   /* Done to disable interrupts 
*/ 
-
-       device_power_down(4);
-       PRINTK( "Waiting for DMAs to settle down...\n");
-       mdelay(1000);   /* We do not want some readahead with DMA to corrupt 
our memory, right?
-                          Do it with disabled interrupts for best effect. That 
way, if some
-                          driver scheduled DMA, we have good chance for DMA to 
finish ;-). */
-}
-
-asmlinkage void do_magic_resume_2(void)
-{
-       BUG_ON (nr_copy_pages_check != nr_copy_pages);
-       BUG_ON (pagedir_order_check != pagedir_order);
-
-       __flush_tlb_global();           /* Even mappings of "global" things 
(vmalloc) need to be fixed */
-
-       PRINTK( "Freeing prev allocated pagedir\n" );
-       free_suspend_pagedir((unsigned long) pagedir_save);
-
-#ifdef CONFIG_HIGHMEM
-       printk( "Restoring highmem\n" );
-       restore_highmem();
-#endif
-       printk("done, devices\n");
-
-       device_power_up();
-       spin_unlock_irq(&suspend_pagedir_lock);
-       device_resume();
-
-       /* Fixme: this is too late; we should do this ASAP to avoid "infinite 
reboots" problem */
-       PRINTK( "Fixing swap signatures... " );
-       mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
-       PRINTK( "ok\n" );
-
-#ifdef SUSPEND_CONSOLE
-       acquire_console_sem();
-       update_screen(fg_console);
-       release_console_sem();
-#endif
-}
-
-/* do_magic() is implemented in arch/?/kernel/suspend_asm.S, and basically 
does:
-
-       if (!resume) {
-               do_magic_suspend_1();
-               save_processor_state();
-               SAVE_REGISTERS
-               do_magic_suspend_2();
-               return;
-       }
-       GO_TO_SWAPPER_PAGE_TABLES
-       do_magic_resume_1();
-       COPY_PAGES_BACK
-       RESTORE_REGISTERS
-       restore_processor_state();
-       do_magic_resume_2();
-
- */
-
-asmlinkage void do_magic_suspend_1(void)
-{
-       mb();
-       barrier();
-       BUG_ON(in_atomic());
-       spin_lock_irq(&suspend_pagedir_lock);
-}
-
-asmlinkage void do_magic_suspend_2(void)
-{
-       int is_problem;
-       read_swapfiles();
-       device_power_down(4);
-       is_problem = suspend_prepare_image();
-       device_power_up();
-       spin_unlock_irq(&suspend_pagedir_lock);
-       if (!is_problem) {
-               kernel_fpu_end();       /* save_processor_state() does 
kernel_fpu_begin, and we need to revert it in order to pass in_atomic() checks 
*/
-               BUG_ON(in_atomic());
-               suspend_save_image();
-               suspend_power_down();   /* FIXME: if suspend_power_down is 
commented out, console is lost after few suspends ?! */
-       }
-
-       printk(KERN_EMERG "%sSuspend failed, trying to recover...\n", 
name_suspend);
-       MDELAY(1000); /* So user can wait and report us messages if armageddon 
comes :-) */
-
-       barrier();
-       mb();
-       spin_lock_irq(&suspend_pagedir_lock);   /* Done to disable interrupts 
*/ 
-       mdelay(1000);
-
-       free_pages((unsigned long) pagedir_nosave, pagedir_order);
-       spin_unlock_irq(&suspend_pagedir_lock);
-
-       device_resume();
-       PRINTK( "Fixing swap signatures... " );
-       mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
-       PRINTK( "ok\n" );
-}
-
 /*
  * This is main interface to the outside world. It needs to be
  * called from process context.
  */
-int software_suspend(void)
+static int software_suspend(void)
 {
        int res;
        if (!software_suspend_enabled)
@@ -1023,8 +308,6 @@
        return 0;
 }
 
-extern dev_t __init name_to_dev_t(const char *line);
-
 static int __init __read_suspend_image(struct block_device *bdev, union 
diskpage *cur, int noresume)
 {
        swp_entry_t next;
@@ -1117,15 +400,31 @@
        unsigned long scratch_page = 0;
        int error;
        char b[BDEVNAME_SIZE];
+#ifdef MODULE
+       char *p;
+
+       swsusp_resume_device =
+               new_decode_dev(simple_strtoul(specialfile, &p, 16));
+       if (*p)
+               swsusp_resume_device = 0;
+#else
+       extern dev_t __init name_to_dev_t(const char *line);
 
-       resume_device = name_to_dev_t(specialfile);
+       swsusp_resume_device = name_to_dev_t(specialfile);
+#endif
+       if (!swsusp_resume_device) {
+               printk(KERN_ERR "%s%s: Invalid device\n", name_resume,
+                      specialfile);
+               error = -EINVAL;
+               goto out;
+       }
        scratch_page = get_zeroed_page(GFP_ATOMIC);
        cur = (void *) scratch_page;
        if (cur) {
                struct block_device *bdev;
                printk("Resuming from device %s\n",
-                               __bdevname(resume_device, b));
-               bdev = open_by_devnum(resume_device, FMODE_READ);
+                               __bdevname(swsusp_resume_device, b));
+               bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
                if (IS_ERR(bdev)) {
                        error = PTR_ERR(bdev);
                } else {
@@ -1155,6 +454,7 @@
                default:
                        printk( "%sError %d resuming\n", name_resume, error );
        }
+out:
        MDELAY(1000);
        return error;
 }
@@ -1178,11 +478,17 @@
        }
        /* We enable the possibility of machine suspend */
        software_suspend_enabled = 1;
-       if (!resume_status)
+
+       down(&software_suspend_sem);
+       software_suspend_module = THIS_MODULE;
+       software_suspend_hook = software_suspend;
+       up(&software_suspend_sem);
+
+       if (!noresume && !resume_file[0])
                return 0;
 
        printk( "%s", name_resume );
-       if (resume_status == NORESUME) {
+       if (noresume) {
                if(resume_file[0])
                        read_suspend_image(resume_file, 1);
                printk( "disabled\n" );
@@ -1193,11 +499,6 @@
        if (pm_prepare_console())
                printk("swsusp: Can't allocate a console... proceeding\n");
 
-       if (!resume_file[0] && resume_status == RESUME_SPECIFIED) {
-               printk( "suspension device unspecified\n" );
-               return -EINVAL;
-       }
-
        printk( "resuming from %s\n", resume_file);
        if (read_suspend_image(resume_file, 0))
                goto read_failure;
@@ -1210,27 +511,19 @@
        return 0;
 }
 
-late_initcall(software_resume);
-
-static int __init resume_setup(char *str)
+static void __exit software_resume_exit(void)
 {
-       if (resume_status == NORESUME)
-               return 1;
-
-       strncpy( resume_file, str, 255 );
-       resume_status = RESUME_SPECIFIED;
-
-       return 1;
+       down(&software_suspend_sem);
+       software_suspend_module = 0;
+       up(&software_suspend_sem);
 }
 
-static int __init noresume_setup(char *str)
-{
-       resume_status = NORESUME;
-       return 1;
-}
+late_initcall(software_resume);
+module_exit(software_resume_exit);
+
+module_param(noresume, bool, 0);
+module_param_string(resume, resume_file, sizeof(resume_file), 0);
 
-__setup("noresume", noresume_setup);
-__setup("resume=", resume_setup);
+MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(software_suspend);
 EXPORT_SYMBOL(software_suspend_enabled);
--- 1.37/mm/page_io.c   2004-04-12 19:55:21 +02:00
+++ edited/mm/page_io.c 2004-06-16 15:30:02 +02:00
@@ -127,7 +127,7 @@
        return ret;
 }
 
-#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_PM_DISK)
+#if defined(CONFIG_SOFTWARE_SUSPEND) || 
defined(CONFIG_SOFTWARE_SUSPEND_MODULE) || defined(CONFIG_PM_DISK)
 /*
  * A scruffy utility function to read or write an arbitrary swap page
  * and wait on the I/O.  The caller must have a ref on the page.
--- 1.219/mm/vmscan.c   2004-06-14 04:42:00 +02:00
+++ edited/mm/vmscan.c  2004-06-16 15:30:03 +02:00
@@ -1179,6 +1179,8 @@
        current->reclaim_state = NULL;
        return ret;
 }
+
+EXPORT_SYMBOL(shrink_all_memory);
 #endif
 
 #ifdef CONFIG_HOTPLUG_CPU
--- /dev/null   2004-05-30 14:45:31.000000000 +0200
+++ b/kernel/power/swsusp-core.c        2004-06-16 15:32:39.000000000 +0200
@@ -0,0 +1,738 @@
+/*
+ * linux/kernel/power/swsusp-core.c
+ *
+ * This file provides symbols required by swusup-arch.
+ *
+ * Copyright (C) 1998-2001 Gabor Kuti <[EMAIL PROTECTED]>
+ * Copyright (C) 1998,2001-2004 Pavel Machek <[EMAIL PROTECTED]>
+ * Copyright (C) 2004 Herbert Xu <[EMAIL PROTECTED]>
+ *
+ * This file is licensed under the GPLv2.
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/suspend.h>
+#include <linux/smp_lock.h>
+#include <linux/file.h>
+#include <linux/utsname.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/bitops.h>
+#include <linux/vt_kern.h>
+#include <linux/kbd_kern.h>
+#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>
+#include <linux/swapops.h>
+#include <linux/bootmem.h>
+#include <linux/console.h>
+#include <linux/highmem.h>
+#include <linux/init.h>
+#include <linux/cpumask.h>
+#include <linux/fs.h>
+
+#include <asm/uaccess.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+#include "power.h"
+#include "swsusp.h"
+
+/* References to section boundaries */
+extern char __nosave_begin, __nosave_end;
+
+extern int is_head_of_free_region(struct page *);
+
+/* Locks */
+spinlock_t suspend_pagedir_lock __nosavedata = SPIN_LOCK_UNLOCKED;
+
+/* Variables to be preserved over suspend */
+static int pagedir_order_check;
+static int nr_copy_pages_check;
+
+dev_t swsusp_resume_device;
+EXPORT_SYMBOL(swsusp_resume_device);
+
+/* Local variables that should not be affected by save */
+unsigned int nr_copy_pages __nosavedata = 0;
+EXPORT_SYMBOL(nr_copy_pages);
+
+/* Suspend pagedir is allocated before final copy, therefore it
+   must be freed after resume 
+
+   Warning: this is evil. There are actually two pagedirs at time of
+   resume. One is "pagedir_save", which is empty frame allocated at
+   time of suspend, that must be freed. Second is "pagedir_nosave", 
+   allocated at time of resume, that travels through memory not to
+   collide with anything.
+
+   Warning: this is even more evil than it seems. Pagedirs this file
+   talks about are completely different from page directories used by
+   MMU hardware.
+ */
+suspend_pagedir_t *pagedir_nosave __nosavedata = NULL;
+EXPORT_SYMBOL(pagedir_nosave);
+suspend_pagedir_t *pagedir_save;
+EXPORT_SYMBOL(pagedir_save);
+int pagedir_order __nosavedata = 0;
+EXPORT_SYMBOL(pagedir_order);
+
+/*
+ * XXX: We try to keep some more pages free so that I/O operations succeed
+ * without paging. Might this be more?
+ */
+#define PAGES_FOR_IO   512
+
+const char name_suspend[] = "Suspend Machine: ";
+EXPORT_SYMBOL(name_suspend);
+const char name_resume[] = "Resume Machine: ";
+EXPORT_SYMBOL(name_resume);
+
+/*
+ * Saving part...
+ */
+
+static __inline__ int fill_suspend_header(struct suspend_header *sh)
+{
+       memset((char *)sh, 0, sizeof(*sh));
+
+       sh->version_code = LINUX_VERSION_CODE;
+       sh->num_physpages = num_physpages;
+       strncpy(sh->machine, system_utsname.machine, 8);
+       strncpy(sh->version, system_utsname.version, 20);
+       /* FIXME: Is this bogus? --RR */
+       sh->num_cpus = num_online_cpus();
+       sh->page_size = PAGE_SIZE;
+       sh->suspend_pagedir = pagedir_nosave;
+       BUG_ON (pagedir_save != pagedir_nosave);
+       sh->num_pbes = nr_copy_pages;
+       /* TODO: needed? mounted fs' last mounted date comparison
+        * [so they haven't been mounted since last suspend.
+        * Maybe it isn't.] [we'd need to do this for _all_ fs-es]
+        */
+       return 0;
+}
+
+/* We memorize in swapfile_used what swap devices are used for suspension */
+#define SWAPFILE_UNUSED    0
+#define SWAPFILE_SUSPEND   1   /* This is the suspending device */
+#define SWAPFILE_IGNORED   2   /* Those are other swap devices ignored for 
suspension */
+
+static unsigned short swapfile_used[MAX_SWAPFILES];
+static unsigned short root_swap;
+#define MARK_SWAP_SUSPEND 0
+#define MARK_SWAP_RESUME 2
+
+static void mark_swapfiles(swp_entry_t prev, int mode)
+{
+       swp_entry_t entry;
+       union diskpage *cur;
+       struct page *page;
+
+       if (root_swap == 0xFFFF)  /* ignored */
+               return;
+
+       page = alloc_page(GFP_ATOMIC);
+       if (!page)
+               panic("Out of memory in mark_swapfiles");
+       cur = page_address(page);
+       /* XXX: this is dirty hack to get first page of swap file */
+       entry = swp_entry(root_swap, 0);
+       rw_swap_page_sync(READ, entry, page);
+
+       if (mode == MARK_SWAP_RESUME) {
+               if (!memcmp("S1",cur->swh.magic.magic,2))
+                       memcpy(cur->swh.magic.magic,"SWAP-SPACE",10);
+               else if (!memcmp("S2",cur->swh.magic.magic,2))
+                       memcpy(cur->swh.magic.magic,"SWAPSPACE2",10);
+               else printk("%sUnable to find suspended-data signature (%.10s - 
misspelled?\n", 
+                       name_resume, cur->swh.magic.magic);
+       } else {
+               if ((!memcmp("SWAP-SPACE",cur->swh.magic.magic,10)))
+                       memcpy(cur->swh.magic.magic,"S1SUSP....",10);
+               else if ((!memcmp("SWAPSPACE2",cur->swh.magic.magic,10)))
+                       memcpy(cur->swh.magic.magic,"S2SUSP....",10);
+               else panic("\nSwapspace is not swapspace (%.10s)\n", 
cur->swh.magic.magic);
+               cur->link.next = prev; /* prev is the first/last swap page of 
the resume area */
+               /* link.next lies *no more* in last 4/8 bytes of magic */
+       }
+       rw_swap_page_sync(WRITE, entry, page);
+       __free_page(page);
+}
+ 
+/*
+ * Check whether the swap device is the specified resume
+ * device, irrespective of whether they are specified by
+ * identical names.
+ *
+ * (Thus, device inode aliasing is allowed.  You can say /dev/hda4
+ * instead of /dev/ide/host0/bus0/target0/lun0/part4 [if using devfs]
+ * and they'll be considered the same device.  This is *necessary* for
+ * devfs, since the resume code can only recognize the form /dev/hda4,
+ * but the suspend code would see the long name.)
+ */
+static int is_resume_device(const struct swap_info_struct *swap_info)
+{
+       struct inode *inode = swap_info->swap_file->f_dentry->d_inode;
+
+       return S_ISBLK(inode->i_mode) && resume_device == inode->i_rdev;
+}
+
+static void read_swapfiles(void) /* This is called before saving image */
+{
+       int i;
+       
+       root_swap = 0xFFFF;
+       
+       swap_list_lock();
+       for(i=0; i<MAX_SWAPFILES; i++) {
+               if (swap_info[i].flags == 0) {
+                       swapfile_used[i]=SWAPFILE_UNUSED;
+               } else {
+                       if (!swsusp_resume_device) {
+                               printk(KERN_WARNING "resume= option should be 
used to set suspend device" );
+                               if(root_swap == 0xFFFF) {
+                                       swapfile_used[i] = SWAPFILE_SUSPEND;
+                                       root_swap = i;
+                               } else
+                                       swapfile_used[i] = SWAPFILE_IGNORED;    
                          
+                       } else {
+                               /* we ignore all swap devices that are not the 
resume_file */
+                               if (is_resume_device(&swap_info[i])) {
+                                       swapfile_used[i] = SWAPFILE_SUSPEND;
+                                       root_swap = i;
+                               } else {
+                                       swapfile_used[i] = SWAPFILE_IGNORED;
+                               }
+                       }
+               }
+       }
+       swap_list_unlock();
+}
+
+static void lock_swapdevices(void) /* This is called after saving image so 
modification
+                                     will be lost after resume... and that's 
what we want. */
+{
+       int i;
+
+       swap_list_lock();
+       for(i = 0; i< MAX_SWAPFILES; i++)
+               if(swapfile_used[i] == SWAPFILE_IGNORED) {
+                       swap_info[i].flags ^= 0xFF; /* we make the device 
unusable. A new call to
+                                                      lock_swapdevices can 
unlock the devices. */
+               }
+       swap_list_unlock();
+}
+
+/**
+ *    write_suspend_image - Write entire image to disk.
+ *
+ *    After writing suspend signature to the disk, suspend may no
+ *    longer fail: we have ready-to-run image in swap, and rollback
+ *    would happen on next reboot -- corrupting data.
+ *
+ *    Note: The buffer we allocate to use to write the suspend header is
+ *    not freed; its not needed since the system is going down anyway
+ *    (plus it causes an oops and I'm lazy^H^H^H^Htoo busy).
+ */
+static int write_suspend_image(void)
+{
+       int i;
+       swp_entry_t entry, prev = { 0 };
+       int nr_pgdir_pages = SUSPEND_PD_PAGES(nr_copy_pages);
+       union diskpage *cur,  *buffer = (union diskpage 
*)get_zeroed_page(GFP_ATOMIC);
+       unsigned long address;
+       struct page *page;
+
+       if (!buffer)
+               return -ENOMEM;
+
+       printk( "Writing data to swap (%d pages): ", nr_copy_pages );
+       for (i=0; i<nr_copy_pages; i++) {
+               if (!(i%100))
+                       printk( "." );
+               if (!(entry = get_swap_page()).val)
+                       panic("\nNot enough swapspace when writing data" );
+               
+               if (swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
+                       panic("\nPage %d: not enough swapspace on suspend 
device", i );
+           
+               address = (pagedir_nosave+i)->address;
+               page = virt_to_page(address);
+               rw_swap_page_sync(WRITE, entry, page);
+               (pagedir_nosave+i)->swap_address = entry;
+       }
+       printk( "|\n" );
+       printk( "Writing pagedir (%d pages): ", nr_pgdir_pages);
+       for (i=0; i<nr_pgdir_pages; i++) {
+               cur = (union diskpage *)((char *) pagedir_nosave)+i;
+               BUG_ON ((char *) cur != (((char *) pagedir_nosave) + 
i*PAGE_SIZE));
+               printk( "." );
+               if (!(entry = get_swap_page()).val) {
+                       printk(KERN_CRIT "Not enough swapspace when writing 
pgdir\n" );
+                       panic("Don't know how to recover");
+                       free_page((unsigned long) buffer);
+                       return -ENOSPC;
+               }
+
+               if(swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
+                       panic("\nNot enough swapspace for pagedir on suspend 
device" );
+
+               BUG_ON (sizeof(swp_entry_t) != sizeof(long));
+               BUG_ON (PAGE_SIZE % sizeof(struct pbe));
+
+               cur->link.next = prev;                          
+               page = virt_to_page((unsigned long)cur);
+               rw_swap_page_sync(WRITE, entry, page);
+               prev = entry;
+       }
+       printk("H");
+       BUG_ON (sizeof(struct suspend_header) > PAGE_SIZE-sizeof(swp_entry_t));
+       BUG_ON (sizeof(union diskpage) != PAGE_SIZE);
+       BUG_ON (sizeof(struct link) != PAGE_SIZE);
+       if (!(entry = get_swap_page()).val)
+               panic( "\nNot enough swapspace when writing header" );
+       if (swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
+               panic("\nNot enough swapspace for header on suspend device" );
+
+       cur = (void *) buffer;
+       if (fill_suspend_header(&cur->sh))
+               BUG();          /* Not a BUG_ON(): we want fill_suspend_header 
to be called, always */
+               
+       cur->link.next = prev;
+
+       page = virt_to_page((unsigned long)cur);
+       rw_swap_page_sync(WRITE, entry, page);
+       prev = entry;
+
+       printk( "S" );
+       mark_swapfiles(prev, MARK_SWAP_SUSPEND);
+       printk( "|\n" );
+
+       MDELAY(1000);
+       return 0;
+}
+
+#ifdef CONFIG_HIGHMEM
+struct highmem_page {
+       char *data;
+       struct page *page;
+       struct highmem_page *next;
+};
+
+struct highmem_page *highmem_copy = NULL;
+
+static int save_highmem_zone(struct zone *zone)
+{
+       unsigned long zone_pfn;
+       for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
+               struct page *page;
+               struct highmem_page *save;
+               void *kaddr;
+               unsigned long pfn = zone_pfn + zone->zone_start_pfn;
+               int chunk_size;
+
+               if (!(pfn%1000))
+                       printk(".");
+               if (!pfn_valid(pfn))
+                       continue;
+               page = pfn_to_page(pfn);
+               /*
+                * This condition results from rvmalloc() sans vmalloc_32()
+                * and architectural memory reservations. This should be
+                * corrected eventually when the cases giving rise to this
+                * are better understood.
+                */
+               if (PageReserved(page)) {
+                       printk("highmem reserved page?!\n");
+                       continue;
+               }
+               if ((chunk_size = is_head_of_free_region(page))) {
+                       pfn += chunk_size - 1;
+                       zone_pfn += chunk_size - 1;
+                       continue;
+               }
+               save = kmalloc(sizeof(struct highmem_page), GFP_ATOMIC);
+               if (!save)
+                       return -ENOMEM;
+               save->next = highmem_copy;
+               save->page = page;
+               save->data = (void *) get_zeroed_page(GFP_ATOMIC);
+               if (!save->data) {
+                       kfree(save);
+                       return -ENOMEM;
+               }
+               kaddr = kmap_atomic(page, KM_USER0);
+               memcpy(save->data, kaddr, PAGE_SIZE);
+               kunmap_atomic(kaddr, KM_USER0);
+               highmem_copy = save;
+       }
+       return 0;
+}
+
+static int save_highmem(void)
+{
+       struct zone *zone;
+       int res = 0;
+       for_each_zone(zone) {
+               if (is_highmem(zone))
+                       res = save_highmem_zone(zone);
+               if (res)
+                       return res;
+       }
+       return 0;
+}
+
+static int restore_highmem(void)
+{
+       while (highmem_copy) {
+               struct highmem_page *save = highmem_copy;
+               void *kaddr;
+               highmem_copy = save->next;
+
+               kaddr = kmap_atomic(save->page, KM_USER0);
+               memcpy(kaddr, save->data, PAGE_SIZE);
+               kunmap_atomic(kaddr, KM_USER0);
+               free_page((long) save->data);
+               kfree(save);
+       }
+       return 0;
+}
+#endif
+
+static int pfn_is_nosave(unsigned long pfn)
+{
+       unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
+       unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> 
PAGE_SHIFT;
+       return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
+}
+
+/* if *pagedir_p != NULL it also copies the counted pages */
+static int count_and_copy_zone(struct zone *zone, struct pbe **pagedir_p)
+{
+       unsigned long zone_pfn, chunk_size, nr_copy_pages = 0;
+       struct pbe *pbe = *pagedir_p;
+       for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
+               struct page *page;
+               unsigned long pfn = zone_pfn + zone->zone_start_pfn;
+
+               if (!(pfn%1000))
+                       printk(".");
+               if (!pfn_valid(pfn))
+                       continue;
+               page = pfn_to_page(pfn);
+               BUG_ON(PageReserved(page) && PageNosave(page));
+               if (PageNosave(page))
+                       continue;
+               if (PageReserved(page) && pfn_is_nosave(pfn)) {
+                       PRINTK("[nosave pfn 0x%lx]", pfn);
+                       continue;
+               }
+               if ((chunk_size = is_head_of_free_region(page))) {
+                       pfn += chunk_size - 1;
+                       zone_pfn += chunk_size - 1;
+                       continue;
+               }
+               nr_copy_pages++;
+               if (!pbe)
+                       continue;
+               pbe->orig_address = (long) page_address(page);
+               copy_page((void *)pbe->address, (void *)pbe->orig_address);
+               pbe++;
+       }
+       *pagedir_p = pbe;
+       return nr_copy_pages;
+}
+
+static int count_and_copy_data_pages(struct pbe *pagedir_p)
+{
+       int nr_copy_pages = 0;
+       struct zone *zone;
+       for_each_zone(zone) {
+               if (!is_highmem(zone))
+                       nr_copy_pages += count_and_copy_zone(zone, &pagedir_p);
+       }
+       return nr_copy_pages;
+}
+
+static void free_suspend_pagedir_zone(struct zone *zone, unsigned long pagedir)
+{
+       unsigned long zone_pfn, pagedir_end, pagedir_pfn, pagedir_end_pfn;
+       pagedir_end = pagedir + (PAGE_SIZE << pagedir_order);
+       pagedir_pfn = __pa(pagedir) >> PAGE_SHIFT;
+       pagedir_end_pfn = __pa(pagedir_end) >> PAGE_SHIFT;
+       for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
+               struct page *page;
+               unsigned long pfn = zone_pfn + zone->zone_start_pfn;
+               if (!pfn_valid(pfn))
+                       continue;
+               page = pfn_to_page(pfn);
+               if (!TestClearPageNosave(page))
+                       continue;
+               else if (pfn >= pagedir_pfn && pfn < pagedir_end_pfn)
+                       continue;
+               __free_page(page);
+       }
+}
+
+static void free_suspend_pagedir(unsigned long this_pagedir)
+{
+       struct zone *zone;
+       for_each_zone(zone) {
+               if (!is_highmem(zone))
+                       free_suspend_pagedir_zone(zone, this_pagedir);
+       }
+       free_pages(this_pagedir, pagedir_order);
+}
+
+static suspend_pagedir_t *create_suspend_pagedir(int nr_copy_pages)
+{
+       int i;
+       suspend_pagedir_t *pagedir;
+       struct pbe *p;
+       struct page *page;
+
+       pagedir_order = get_bitmask_order(SUSPEND_PD_PAGES(nr_copy_pages));
+
+       p = pagedir = (suspend_pagedir_t *)__get_free_pages(GFP_ATOMIC | 
__GFP_COLD, pagedir_order);
+       if (!pagedir)
+               return NULL;
+
+       page = virt_to_page(pagedir);
+       for(i=0; i < 1<<pagedir_order; i++)
+               SetPageNosave(page++);
+               
+       while(nr_copy_pages--) {
+               p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
+               if (!p->address) {
+                       free_suspend_pagedir((unsigned long) pagedir);
+                       return NULL;
+               }
+               SetPageNosave(virt_to_page(p->address));
+               p->orig_address = 0;
+               p++;
+       }
+       return pagedir;
+}
+
+static int suspend_prepare_image(void)
+{
+       struct sysinfo i;
+       unsigned int nr_needed_pages = 0;
+
+       pagedir_nosave = NULL;
+       printk( "/critical section: ");
+#ifdef CONFIG_HIGHMEM
+       printk( "handling highmem" );
+       if (save_highmem()) {
+               printk(KERN_CRIT "%sNot enough free pages for highmem\n", 
name_suspend);
+               return -ENOMEM;
+       }
+       printk(", ");
+#endif
+
+       printk("counting pages to copy" );
+       drain_local_pages();
+       nr_copy_pages = count_and_copy_data_pages(NULL);
+       nr_needed_pages = nr_copy_pages + PAGES_FOR_IO;
+       
+       printk(" (pages needed: %d+%d=%d free: 
%d)\n",nr_copy_pages,PAGES_FOR_IO,nr_needed_pages,nr_free_pages());
+       if(nr_free_pages() < nr_needed_pages) {
+               printk(KERN_CRIT "%sCouldn't get enough free pages, on %d pages 
short\n",
+                      name_suspend, nr_needed_pages-nr_free_pages());
+               root_swap = 0xFFFF;
+               return -ENOMEM;
+       }
+       si_swapinfo(&i);        /* FIXME: si_swapinfo(&i) returns all swap 
devices information.
+                                  We should only consider resume_file. */
+       if (i.freeswap < nr_needed_pages)  {
+               printk(KERN_CRIT "%sThere's not enough swap space available, on 
%ld pages short\n",
+                      name_suspend, nr_needed_pages-i.freeswap);
+               return -ENOMEM;
+       }
+
+       PRINTK( "Alloc pagedir\n" ); 
+       pagedir_save = pagedir_nosave = create_suspend_pagedir(nr_copy_pages);
+       if (!pagedir_nosave) {
+               /* Pagedir is big, one-chunk allocation. It is easily possible 
for this allocation to fail */
+               printk(KERN_CRIT "%sCouldn't allocate continuous pagedir\n", 
name_suspend);
+               return -ENOMEM;
+       }
+       nr_copy_pages_check = nr_copy_pages;
+       pagedir_order_check = pagedir_order;
+
+       drain_local_pages();    /* During allocating of suspend pagedir, new 
cold pages may appear. Kill them */
+       if (nr_copy_pages != count_and_copy_data_pages(pagedir_nosave)) /* copy 
*/
+               BUG();
+
+       /*
+        * End of critical section. From now on, we can write to memory,
+        * but we should not touch disk. This specially means we must _not_
+        * touch swap space! Except we must write out our image of course.
+        */
+
+       printk( "critical section/: done (%d pages copied)\n", nr_copy_pages );
+       return 0;
+}
+
+static void suspend_save_image(void)
+{
+       device_resume();
+
+       lock_swapdevices();
+       write_suspend_image();
+       lock_swapdevices();     /* This will unlock ignored swap devices since 
writing is finished */
+
+       /* It is important _NOT_ to umount filesystems at this point. We want
+        * them synced (in case something goes wrong) but we DO not want to mark
+        * filesystem clean: it is not. (And it does not matter, if we resume
+        * correctly, we'll mark system clean, anyway.)
+        */
+}
+
+static void suspend_power_down(void)
+{
+       extern int C_A_D;
+       C_A_D = 0;
+       printk(KERN_EMERG "%s%s Trying to power down.\n", name_suspend, 
TEST_SWSUSP ? "Disable TEST_SWSUSP. NOT ": "");
+#ifdef CONFIG_VT
+       PRINTK(KERN_EMERG "shift_state: %04x\n", shift_state);
+       mdelay(1000);
+       if (TEST_SWSUSP ^ (!!(shift_state & (1 << KG_CTRL))))
+               machine_restart(NULL);
+       else
+#endif
+       {
+               device_shutdown();
+               machine_power_off();
+       }
+
+       printk(KERN_EMERG "%sProbably not capable for powerdown. System 
halted.\n", name_suspend);
+       machine_halt();
+       while (1);
+       /* NOTREACHED */
+}
+
+/*
+ * Magic happens here
+ */
+
+asmlinkage void do_magic_resume_1(void)
+{
+       barrier();
+       mb();
+       spin_lock_irq(&suspend_pagedir_lock);   /* Done to disable interrupts 
*/ 
+
+       device_power_down(4);
+       PRINTK( "Waiting for DMAs to settle down...\n");
+       mdelay(1000);   /* We do not want some readahead with DMA to corrupt 
our memory, right?
+                          Do it with disabled interrupts for best effect. That 
way, if some
+                          driver scheduled DMA, we have good chance for DMA to 
finish ;-). */
+}
+
+EXPORT_SYMBOL(do_magic_resume_1);
+
+asmlinkage void do_magic_resume_2(void)
+{
+       BUG_ON (nr_copy_pages_check != nr_copy_pages);
+       BUG_ON (pagedir_order_check != pagedir_order);
+
+       __flush_tlb_global();           /* Even mappings of "global" things 
(vmalloc) need to be fixed */
+
+       PRINTK( "Freeing prev allocated pagedir\n" );
+       free_suspend_pagedir((unsigned long) pagedir_save);
+
+#ifdef CONFIG_HIGHMEM
+       printk( "Restoring highmem\n" );
+       restore_highmem();
+#endif
+       printk("done, devices\n");
+
+       device_power_up();
+       spin_unlock_irq(&suspend_pagedir_lock);
+       device_resume();
+
+       /* Fixme: this is too late; we should do this ASAP to avoid "infinite 
reboots" problem */
+       PRINTK( "Fixing swap signatures... " );
+       mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
+       PRINTK( "ok\n" );
+
+#ifdef SUSPEND_CONSOLE
+       acquire_console_sem();
+       update_screen(fg_console);
+       release_console_sem();
+#endif
+}
+
+EXPORT_SYMBOL(do_magic_resume_2);
+
+/* do_magic() is implemented in arch/?/kernel/suspend_asm.S, and basically 
does:
+
+       if (!resume) {
+               do_magic_suspend_1();
+               save_processor_state();
+               SAVE_REGISTERS
+               do_magic_suspend_2();
+               return;
+       }
+       GO_TO_SWAPPER_PAGE_TABLES
+       do_magic_resume_1();
+       COPY_PAGES_BACK
+       RESTORE_REGISTERS
+       restore_processor_state();
+       do_magic_resume_2();
+
+ */
+
+asmlinkage void do_magic_suspend_1(void)
+{
+       mb();
+       barrier();
+       BUG_ON(in_atomic());
+       spin_lock_irq(&suspend_pagedir_lock);
+}
+
+EXPORT_SYMBOL(do_magic_suspend_1);
+
+asmlinkage void do_magic_suspend_2(void)
+{
+       int is_problem;
+       read_swapfiles();
+       device_power_down(4);
+       is_problem = suspend_prepare_image();
+       device_power_up();
+       spin_unlock_irq(&suspend_pagedir_lock);
+       if (!is_problem) {
+               kernel_fpu_end();       /* save_processor_state() does 
kernel_fpu_begin, and we need to revert it in order to pass in_atomic() checks 
*/
+               BUG_ON(in_atomic());
+               suspend_save_image();
+               suspend_power_down();   /* FIXME: if suspend_power_down is 
commented out, console is lost after few suspends ?! */
+       }
+
+       printk(KERN_EMERG "%sSuspend failed, trying to recover...\n", 
name_suspend);
+       MDELAY(1000); /* So user can wait and report us messages if armageddon 
comes :-) */
+
+       barrier();
+       mb();
+       spin_lock_irq(&suspend_pagedir_lock);   /* Done to disable interrupts 
*/ 
+       mdelay(1000);
+
+       free_pages((unsigned long) pagedir_nosave, pagedir_order);
+       spin_unlock_irq(&suspend_pagedir_lock);
+
+       device_resume();
+       PRINTK( "Fixing swap signatures... " );
+       mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
+       PRINTK( "ok\n" );
+}
+
+EXPORT_SYMBOL(do_magic_suspend_2);
--- /dev/null   2004-06-19 10:21:50.000000000 +0200
+++ b/kernel/power/swsusp.h     2004-06-19 18:37:51.000000000 +0200
@@ -0,0 +1,50 @@
+/*
+ * linux/kernel/power/swsusp.h
+ *
+ * Copyright (c) 2004 Herbert Xu <[EMAIL PROTECTED]>
+ *
+ * This file is licensed under the GPLv2.
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/suspend.h>
+#include <linux/types.h>
+
+struct link {
+       char dummy[PAGE_SIZE - sizeof(swp_entry_t)];
+       swp_entry_t next;
+};
+
+union diskpage {
+       union swap_header swh;
+       struct link link;
+       struct suspend_header sh;
+};
+
+extern dev_t swsusp_resume_device;
+extern const char name_suspend[];
+extern const char name_resume[];
+
+extern suspend_pagedir_t *pagedir_save;
+extern int pagedir_order;
+
+/*
+ * Debug
+ */
+#define        DEBUG_DEFAULT
+#undef DEBUG_PROCESS
+#undef DEBUG_SLOW
+#define TEST_SWSUSP 0          /* Set to 1 to reboot instead of halt machine 
after suspension */
+
+#ifdef DEBUG_DEFAULT
+# define PRINTK(f, a...)       printk(f, ## a)
+#else
+# define PRINTK(f, a...)               do { } while(0)
+#endif
+
+#ifdef DEBUG_SLOW
+#define MDELAY(a) mdelay(a)
+#else
+#define MDELAY(a) do { } while(0)
+#endif


-- 
J'qbpbe, le m'en fquz pe j'qbpbe!
Le veux aimeb et mqubib panz je pézqbpbe je djuz tqtaj!


Reply via email to