On Mon, Jan 17, 2005 at 03:53:02PM +0100, Rafael J. Wysocki wrote:
> Hi,
> > 
> > Try Lukas's patch, it should provide equivalent speedups.
> 
> It does.  Still, I don't think it'll solve memory allocation problems on 
> resume,
> and the hugang's patch has such a potential.
> 
If your only wannt fix memory allocation problems Pavel Machek's
free_some_memory patch enought do it.

 * fix a bug in alloc_one_pagedir()

2005-1-18.core.diff        18-Jan-2005 09:37    22k  
        fix a bug
2005-1-16.i386.diff        18-Jan-2005 09:37     1k  
        no change from prev version.
2005-1-16.x86_64.diff      18-Jan-2005 09:37     2k  
        no change from prev version.
2005-1-18.core.eatmem.diff 18-Jan-2005 09:37     1k  
         Pavel Machek's patch, that's useful fix memory allocation problems.

http://soulinfo.com/~hugang/swsusp/2005-1-18/

Signed-off-by: Hu Gang <[EMAIL PROTECTED]>

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

2005-1-18.core.diff

--- 2.6.11-rc1-mm1/kernel/power/swsusp.c        2005-01-14 20:19:58.000000000 
+0800
+++ 2.6.11-rc1-mm1-swsusp/kernel/power/swsusp.c 2005-01-18 09:24:46.000000000 
+0800
@@ -76,7 +76,6 @@
 extern const void __nosave_begin, __nosave_end;
 
 /* Variables to be preserved over suspend */
-static int pagedir_order_check;
 static int nr_copy_pages_check;
 
 extern char resume_file[];
@@ -99,7 +98,6 @@ unsigned int nr_copy_pages __nosavedata 
  */
 suspend_pagedir_t *pagedir_nosave __nosavedata = NULL;
 static suspend_pagedir_t *pagedir_save;
-static int pagedir_order __nosavedata = 0;
 
 #define SWSUSP_SIG     "S1SUSPEND"
 
@@ -259,8 +257,420 @@ static int write_page(unsigned long addr
        return error;
 }
 
+static int mod_progress = 1;
+
+static void inline mod_printk_progress(int i)
+{
+       if (mod_progress == 0) mod_progress = 1;
+       if (!(i%100))
+               printk( "\b\b\b\b%3d%%", i / mod_progress );
+}
+
+#define PBE_PAGE_NUMS          (PAGE_SIZE/sizeof(struct pbe))
+#define PBE_IS_PAGE_END(x) \
+       ( PAGE_SIZE - sizeof(struct pbe) == ((x) - ((~(PAGE_SIZE - 1)) & (x))) )
+
+/**
+ * pgdir_for_each - iterate over a pagedir list
+ * @pos:       the &suspend_pagedir_t to use as a loop conter.
+ * @n:         another &suspend_pagedir_t to use as tempory storage.
+ * @head:      the head for your list.
+ */
+#define pgdir_for_each(pos, n, head) \
+       for(pos = head, n = pos ? (suspend_pagedir_t*)pos->dummy.val : NULL; \
+                       pos != NULL; \
+                       pos = n, n = pos ? (suspend_pagedir_t *)pos->dummy.val 
: NULL)
+
+/**
+ * pbe_for_each - iterate over a page backup entry list
+ * @pos:       the &struct pbe to use as a loop conter.
+ * @n          another &struct pbe to use as tempory storage.
+ * @index:     show current index 
+ * @max:       max index in this list
+ * @head:      the head for your list.
+ */
+#define pbe_for_each(pos, n, index, max, head) \
+       for(pos = head, index = 0,\
+                       n = pos ? (struct pbe *)pos->dummy.val : NULL; \
+               (pos != NULL) && (index < max); \
+               pos = (PBE_IS_PAGE_END((unsigned long)pos)) ? n : \
+                       ((struct pbe *)((unsigned long)pos + sizeof(struct 
pbe))), \
+                       index ++, \
+                       n = pos ? (struct pbe*)pos->dummy.val : NULL)
+
+/**
+ * find_pbe_by_index - find a pbe by index
+ * @head:      the head for your list.
+ *
+ * @return:    NULL is failed.
+ */
+static inline struct pbe *find_pbe_by_index(struct pbe *head, int index)
+{
+       unsigned long p = 0;
+       struct pbe *pbe, *next;
+
+       pgdir_for_each(pbe, next, head) {
+               if (p == index / PBE_PAGE_NUMS) {
+                       pbe = (struct pbe *)((unsigned long)pbe + 
+                                       (index % PBE_PAGE_NUMS) * sizeof(struct 
pbe));
+                       pr_debug("find_pbe_by_index: %p, 0x%03x, %p", head, 
index, pbe); 
+                       return pbe;
+               }
+               p ++;
+       }
+       return (NULL);
+}
+
+/**
+ * pagedir_free - free the pagedir list storage 
+ * @head:      the head for your list.
+ */
+static inline void pagedir_free(suspend_pagedir_t *head)
+{
+       suspend_pagedir_t *next, *cur;
+       pgdir_for_each(cur, next, head) 
+               free_page((unsigned long)cur);
+}
+
+static int bio_read_page(pgoff_t page_off, void * page);
+/**
+ *  write_one_pbe -     write a page backup entry to swap device
+ *  @p:                the page backup entry pointer
+ *  @data:     the data page pointer
+ *  @cur:      current index 
+ *
+ *  @return: 0 is ok.
+ */
+static int inline write_one_pbe(struct pbe *p, void *data, int cur)
+{
+       int error = 0;
+
+       mod_printk_progress(cur);
+
+       pr_debug("write_one_pbe: %p, o{%p} c{%p} %d ",
+                       p, (void *)p->orig_address, (void *)p->address, cur);
+       error = write_page((unsigned long)data, &p->swap_address);
+       if (error) return error;
+       pr_debug("%lu\n", swp_offset(p->swap_address));
+       return 0;
+}
+static int inline read_one_pbe(struct pbe *p, void *data, int cur)
+{
+       int error = 0;
+
+       mod_printk_progress(cur);
+
+       pr_debug("read_one_pbe: %p, o{%p} c{%p} %lu\n",
+                       p, (void *)p->orig_address, data, 
+                       swp_offset(p->swap_address));
+
+       error = bio_read_page(swp_offset(p->swap_address), data);
+       if (error) return error;
+       return 0;
+}
+
+/*
+ * Returns true if given address/order collides with any orig_address 
+ */
+static int inline does_collide_order(unsigned long addr, int order) 
+{
+       int i;
+
+       for (i=0; i < (1<<order); i++)
+               if(!PageNosaveFree(virt_to_page(addr + i * PAGE_SIZE)))
+                       return 1;
+       return 0;
+}
+
+
+static void **eaten_memory = NULL;
+
+/**
+ * swsusp_get_safe_free_page - a get_free_pages wrapper.
+ * 
+ * in resume we must make sure the page not collide with old pages, first call 
+ * get_free_page, if that's collide, adding it in a easy list, then try next, 
+ * until get un colliede page.
+ *
+ * @collide:   if true enable collide check.
+ * 
+ */
+static void *swsusp_get_safe_free_page(int collide)
+{
+       void *addr = NULL;
+       void **c = eaten_memory;
+
+       do {
+               if (addr) {
+                       eaten_memory = (void**)addr;
+                       *eaten_memory = c;
+                       c = eaten_memory;
+                       printk(".");
+               }
+               addr = (void*)__get_free_pages(GFP_ATOMIC | __GFP_COLD, 0);
+               if (!addr) {
+                       printk("out of memory\n");
+                       return NULL;
+               }
+       } while (collide && does_collide_order((unsigned long)addr, 0));
+
+       if (collide)
+               ClearPageNosaveFree(virt_to_page(addr)); 
+
+       return addr;
+}
 
 /**
+ * alloc_one_pagedir - allocate a new pagedir 
+ * @prev:      last pagedir pointer
+ * @collide:
+ * 
+ */
+static suspend_pagedir_t * alloc_one_pagedir(suspend_pagedir_t *prev, 
+               int collide)
+{
+       suspend_pagedir_t *pgdir = NULL;
+       int i;
+
+       pgdir = (suspend_pagedir_t *)swsusp_get_safe_free_page(collide);
+
+       if (!pgdir) 
+               return NULL;
+
+       /*pr_debug("pgdir: %p, %p, %d\n", 
+         pgdir, prev, sizeof(suspend_pagedir_t)); */
+       for (i = 0; i < PBE_PAGE_NUMS; i++) {
+               pgdir[i].dummy.val = 0;
+               pgdir[i].address = 0;
+               pgdir[i].orig_address = 0;
+               if (prev)
+                       prev[i].dummy.val= (unsigned long)pgdir;
+       }
+
+       return (pgdir);
+}
+
+/* calc_nums - Determine the nums of allocation needed for pagedir_save. */
+static int calc_nums(int nr_copy)
+{
+       int diff = 0, ret = 0;
+       do {
+               diff = (nr_copy / PBE_PAGE_NUMS) - ret + 1;
+               if (diff) {
+                       ret += diff;
+                       nr_copy += diff;
+               }
+       } while (diff);
+       return nr_copy;
+}
+
+/**
+ * alloc_pagedir - Allocate the page directory.
+ * @pbe:
+ * @pbe_nums:  needs how many page backup entry.
+ * @collide:   true is need do collide check.
+ * @page_nums: if we knows need how many pages for pagedir set it, 
+ *                         only using resume stage, 0 is known.
+ *
+ * @return:    < 0 is failed.
+ */
+static int alloc_pagedir(struct pbe **pbe, 
+               int pbe_nums, int collide, int page_nums)
+{
+       unsigned int nums = 0;
+       unsigned int after_alloc = pbe_nums;
+       suspend_pagedir_t *prev = NULL, *cur = NULL;
+
+       if (page_nums)
+               after_alloc = PBE_PAGE_NUMS * page_nums;
+       else
+               after_alloc = calc_nums(after_alloc);
+       pr_debug("alloc_pagedir: %d, %d\n", pbe_nums, after_alloc);
+       for (nums = 0 ; nums < after_alloc ; nums += PBE_PAGE_NUMS) {
+               cur = alloc_one_pagedir(prev, collide);
+               pr_debug("alloc_one_pagedir: %p\n", cur);
+               if (!cur) { /* get page failed */
+                       goto no_mem;
+               }
+               if (nums == 0) { /* setup the head */
+                       *pbe = cur;
+               }
+               prev = cur;
+       }
+       return after_alloc - pbe_nums;
+
+no_mem:
+       pagedir_free(*pbe);
+       *pbe = NULL;
+
+       return (-ENOMEM);
+}
+
+static int __init check_one_pbe(struct pbe *p, int cur)
+{
+       unsigned long addr = 0;
+
+       pr_debug("check_one_pbe: %p %lu o{%p} ", 
+                       p, p->swap_address.val, (void*)p->orig_address);
+       addr = (unsigned long)swsusp_get_safe_free_page(1);
+       if(!addr)
+               return -ENOMEM;
+       pr_debug("c{%p} done\n", (void*)addr);
+       p->address = addr;
+
+       return 0;
+}
+
+static void __init swsusp_copy_pagedir(suspend_pagedir_t *d_pgdir, 
+               suspend_pagedir_t *s_pgdir)
+{
+       int i = 0;
+
+       while (s_pgdir != NULL) {
+               suspend_pagedir_t *s_next = (suspend_pagedir_t 
*)s_pgdir->dummy.val;
+               suspend_pagedir_t *d_next = (suspend_pagedir_t 
*)d_pgdir->dummy.val;
+               for (i = 0; i < PBE_PAGE_NUMS; i++) {
+                       d_pgdir->address = s_pgdir->address;
+                       d_pgdir->orig_address = s_pgdir->orig_address;
+                       d_pgdir->swap_address = s_pgdir->swap_address;
+                       s_pgdir ++; d_pgdir ++;
+               }
+               d_pgdir = d_next;
+               s_pgdir = s_next;
+       };
+}
+
+/**
+ * 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
+ */
+static int __init check_pagedir(void)
+{
+       void **c, *f;
+       struct pbe *next, *pos;
+       int error, index;
+       suspend_pagedir_t *addr = NULL;
+       struct zone *zone;
+       unsigned long zone_pfn;
+
+       printk("Relocating pagedir ... ");
+       /* Set page flags */
+       for_each_zone(zone) {
+               for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
+                       SetPageNosaveFree(pfn_to_page(zone_pfn + 
zone->zone_start_pfn));
+       }
+
+       /* Clear orig address */
+       pbe_for_each(pos, next, index, nr_copy_pages, pagedir_nosave) {
+               pr_debug("clear <%p>, <%p>, %d\n", 
+                               pos, (void*)pos->orig_address, index);
+               ClearPageNosaveFree(virt_to_page(pos->orig_address));
+       }
+       
+       error = alloc_pagedir(&addr, nr_copy_pages, 1, 
swsusp_info.pagedir_pages);
+       if (error < 0) {
+               return error;
+       }
+       swsusp_copy_pagedir(addr, pagedir_nosave);
+       pagedir_free(pagedir_nosave);
+
+       /* check copy address */
+       pbe_for_each(pos, next, index, nr_copy_pages, addr) {
+               error = check_one_pbe(pos, index);
+               BUG_ON(error);
+       }
+
+       /* free eaten memory */
+       c = eaten_memory;
+       while (c) {
+               printk(":");
+               f = c;
+               c = *c;
+               free_pages((unsigned long)f, 0);
+       }
+
+       printk(" done\n");
+
+       pagedir_nosave = addr;
+
+       return 0;
+}
+
+/**
+ * read_one_pagedir - read one pagedir from swap device 
+ * @pgdir:     the pgdir pointer
+ * @i:         
+ */
+static int __init read_one_pagedir(suspend_pagedir_t *pgdir, int i)
+{
+       unsigned long offset = swp_offset(swsusp_info.pagedir[i]);
+       unsigned long next;
+       int error = 0;
+
+       next = pgdir->dummy.val;
+       pr_debug("read_one_pagedir: %p, %d, %lu, %p\n", 
+                       pgdir, i, offset, (void*)next);
+       if ((error = bio_read_page(offset, (void *)pgdir))) {
+               return error;
+       }
+       pgdir->dummy.val = next;
+
+       return error;
+}
+
+/**
+ *  for_each_pbe_copy_back - 
+ *
+ *  That usefuly for help us writing the code in assemble code
+ *
+ *  1: enable CREATE_ASM_CODE
+ *  2: make kernel/power/swsusp.o
+ *  3: objdump -dx kernel/power/swsusp.o > /tmp/swsusp.s
+ *  4: vi /tmp/swsusp.s
+ *
+ */
+/*#define CREATE_ASM_CODE*/
+#ifdef CREATE_ASM_CODE
+#if 0 /* if your copy back code is running in real mode, enable it */
+#define GET_ADDRESS(x) __pa(x) 
+#else
+#define GET_ADDRESS(x) (x)
+#endif
+asmlinkage void for_each_pbe_copy_back(void)
+{
+       register struct pbe *pgdir, *next;
+
+       pgdir = pagedir_nosave;
+       while (pgdir != NULL) {
+               register unsigned long i;
+               pgdir = (struct pbe *)GET_ADDRESS(pgdir);
+               next = (struct pbe*)pgdir->dummy.val;
+               /* copy a suspend pagedir */
+               for (i = 0; i < PBE_PAGE_NUMS; i++, pgdir ++) {
+                       register unsigned long *orig, *copy;
+                       orig = (unsigned long *)pgdir->orig_address;
+                       if (orig == 0) goto end;
+                       orig = (unsigned long *)GET_ADDRESS(orig);
+                       copy = (unsigned long *)GET_ADDRESS(pgdir->address);
+#if 1
+                       /* copy page data */
+                       for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); 
i+=4) {
+                               *(orig + i) = *(copy + i);
+                               *(orig + i+1) = *(copy + i+1);
+                               *(orig + i+2) = *(copy + i+2);
+                               *(orig + i+3) = *(copy + i+3);
+                       }
+#else
+                       memcpy(orig, copy, PAGE_SIZE);
+#endif
+               }
+               pgdir = next;
+       }
+end:
+       panic("just asm code");
+}
+#endif
+/**
  *     data_free - Free the swap entries used by the saved image.
  *
  *     Walk the list of used swap entries and free each one. 
@@ -271,14 +681,15 @@ static void data_free(void)
 {
        swp_entry_t entry;
        int i;
+       struct pbe *next, *pos;
 
-       for (i = 0; i < nr_copy_pages; i++) {
-               entry = (pagedir_nosave + i)->swap_address;
+       pbe_for_each(pos, next, i, nr_copy_pages, pagedir_nosave) {
+               entry = pos->swap_address;
                if (entry.val)
                        swap_free(entry);
                else
                        break;
-               (pagedir_nosave + i)->swap_address = (swp_entry_t){0};
+               pos->swap_address = (swp_entry_t){0};
        }
 }
 
@@ -293,17 +704,15 @@ static int data_write(void)
 {
        int error = 0;
        int i;
-       unsigned int mod = nr_copy_pages / 100;
+       struct pbe *pos, *next;
 
-       if (!mod)
-               mod = 1;
+       mod_progress = nr_copy_pages / 100;
 
        printk( "Writing data to swap (%d pages)...     ", nr_copy_pages );
-       for (i = 0; i < nr_copy_pages && !error; i++) {
-               if (!(i%mod))
-                       printk( "\b\b\b\b%3d%%", i / mod );
-               error = write_page((pagedir_nosave+i)->address,
-                                         &((pagedir_nosave+i)->swap_address));
+       pbe_for_each(pos, next, i, nr_copy_pages, pagedir_nosave) {
+               BUG_ON(pos->orig_address == 0);
+               error = write_one_pbe(pos, (void*)pos->address, i);
+               if (error) break;
        }
        printk("\b\b\b\bdone\n");
        return error;
@@ -373,15 +782,19 @@ static void free_pagedir_entries(void)
 
 static int write_pagedir(void)
 {
-       unsigned long addr = (unsigned long)pagedir_nosave;
        int error = 0;
-       int n = SUSPEND_PD_PAGES(nr_copy_pages);
-       int i;
+       int n = 0;
+       suspend_pagedir_t *pgdir, *next;
 
-       swsusp_info.pagedir_pages = n;
+       pgdir_for_each(pgdir, next, pagedir_nosave) {
+               error = write_page((unsigned long)pgdir, 
&swsusp_info.pagedir[n]);
+               pr_debug("write_pagedir: <%p>, %lu\n", 
+                               pgdir, swp_offset(swsusp_info.pagedir[n]));
+               if (error) break;
+               n ++;
+       }
        printk( "Writing pagedir (%d pages)\n", n);
-       for (i = 0; i < n && !error; i++, addr += PAGE_SIZE)
-               error = write_page(addr, &swsusp_info.pagedir[i]);
+       swsusp_info.pagedir_pages = n;
        return error;
 }
 
@@ -566,9 +979,9 @@ static void copy_data_pages(void)
 {
        struct zone *zone;
        unsigned long zone_pfn;
-       struct pbe * pbe = pagedir_nosave;
+       struct pbe * pbe = NULL;
        int to_copy = nr_copy_pages;
-       
+
        for_each_zone(zone) {
                if (is_highmem(zone))
                        continue;
@@ -576,92 +989,31 @@ static void copy_data_pages(void)
                for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
                        if (saveable(zone, &zone_pfn)) {
                                struct page * page;
+                               pbe = find_pbe_by_index(pagedir_nosave, 
nr_copy_pages-to_copy);
+                               BUG_ON(pbe == NULL);
                                page = pfn_to_page(zone_pfn + 
zone->zone_start_pfn);
                                pbe->orig_address = (long) page_address(page);
+                               BUG_ON(pbe->orig_address == 0);
+                               BUG_ON(pbe->address == 0);
                                /* copy_page is not usable for copying task 
structs. */
                                memcpy((void *)pbe->address, (void 
*)pbe->orig_address, PAGE_SIZE);
-                               pbe++;
-                               to_copy--;
+                               to_copy --;
                        }
                }
        }
        BUG_ON(to_copy);
 }
 
-
-/**
- *     calc_order - Determine the order of allocation needed for pagedir_save.
- *
- *     This looks tricky, but is just subtle. Please fix it some time.
- *     Since there are %nr_copy_pages worth of pages in the snapshot, we need
- *     to allocate enough contiguous space to hold 
- *             (%nr_copy_pages * sizeof(struct pbe)), 
- *     which has the saved/orig locations of the page.. 
- *
- *     SUSPEND_PD_PAGES() tells us how many pages we need to hold those 
- *     structures, then we call get_bitmask_order(), which will tell us the
- *     last bit set in the number, starting with 1. (If we need 30 pages, that
- *     is 0x0000001e in hex. The last bit is the 5th, which is the order we 
- *     would use to allocate 32 contiguous pages).
- *
- *     Since we also need to save those pages, we add the number of pages that
- *     we need to nr_copy_pages, and in case of an overflow, do the 
- *     calculation again to update the number of pages needed. 
- *
- *     With this model, we will tend to waste a lot of memory if we just cross
- *     an order boundary. Plus, the higher the order of allocation that we try
- *     to do, the more likely we are to fail in a low-memory situtation 
- *     (though we're unlikely to get this far in such a case, since swsusp 
- *     requires half of memory to be free anyway).
- */
-
-
-static void calc_order(void)
-{
-       int diff = 0;
-       int order = 0;
-
-       do {
-               diff = get_bitmask_order(SUSPEND_PD_PAGES(nr_copy_pages)) - 
order;
-               if (diff) {
-                       order += diff;
-                       nr_copy_pages += 1 << diff;
-               }
-       } while(diff);
-       pagedir_order = order;
-}
-
-
-/**
- *     alloc_pagedir - Allocate the page directory.
- *
- *     First, determine exactly how many contiguous pages we need and
- *     allocate them.
- */
-
-static int alloc_pagedir(void)
-{
-       calc_order();
-       pagedir_save = (suspend_pagedir_t *)__get_free_pages(GFP_ATOMIC | 
__GFP_COLD,
-                                                            pagedir_order);
-       if (!pagedir_save)
-               return -ENOMEM;
-       memset(pagedir_save, 0, (1 << pagedir_order) * PAGE_SIZE);
-       pagedir_nosave = pagedir_save;
-       return 0;
-}
-
 /**
  *     free_image_pages - Free pages allocated for snapshot
  */
 
 static void free_image_pages(void)
 {
-       struct pbe * p;
+       struct pbe * p, * n;
        int i;
 
-       p = pagedir_save;
-       for (i = 0, p = pagedir_save; i < nr_copy_pages; i++, p++) {
+       pbe_for_each(p, n, i, nr_copy_pages, pagedir_save) {
                if (p->address) {
                        ClearPageNosave(virt_to_page(p->address));
                        free_page(p->address);
@@ -677,10 +1029,10 @@ static void free_image_pages(void)
 
 static int alloc_image_pages(void)
 {
-       struct pbe * p;
+       struct pbe * p, * n;
        int i;
 
-       for (i = 0, p = pagedir_save; i < nr_copy_pages; i++, p++) {
+       pbe_for_each(p, n, i, nr_copy_pages, pagedir_save) {
                p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
                if (!p->address)
                        return -ENOMEM;
@@ -694,7 +1046,7 @@ void swsusp_free(void)
        BUG_ON(PageNosave(virt_to_page(pagedir_save)));
        BUG_ON(PageNosaveFree(virt_to_page(pagedir_save)));
        free_image_pages();
-       free_pages((unsigned long) pagedir_save, pagedir_order);
+       pagedir_free(pagedir_save);
 }
 
 
@@ -752,18 +1104,19 @@ static int swsusp_alloc(void)
        if (!enough_swap())
                return -ENOSPC;
 
-       if ((error = alloc_pagedir())) {
+       if ((error = alloc_pagedir(&pagedir_save, nr_copy_pages, 0, 0)) < 0) {
                printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
                return error;
        }
+       pr_debug("alloc_pagedir: addon %d\n", error);
+       nr_copy_pages += error;
        if ((error = alloc_image_pages())) {
                printk(KERN_ERR "suspend: Allocating image pages failed.\n");
                swsusp_free();
                return error;
        }
-
+       pagedir_nosave = pagedir_save;
        nr_copy_pages_check = nr_copy_pages;
-       pagedir_order_check = pagedir_order;
        return 0;
 }
 
@@ -867,7 +1220,6 @@ int swsusp_suspend(void)
 asmlinkage int swsusp_restore(void)
 {
        BUG_ON (nr_copy_pages_check != nr_copy_pages);
-       BUG_ON (pagedir_order_check != pagedir_order);
        
        /* Even mappings of "global" things (vmalloc) need to be fixed */
        __flush_tlb_global();
@@ -893,99 +1245,6 @@ int swsusp_resume(void)
        return error;
 }
 
-
-
-/* More restore stuff */
-
-#define does_collide(addr) does_collide_order(pagedir_nosave, addr, 0)
-
-/*
- * Returns true if given address/order collides with any orig_address 
- */
-static int __init does_collide_order(suspend_pagedir_t *pagedir, unsigned long 
addr,
-               int order)
-{
-       int i;
-       unsigned long addre = addr + (PAGE_SIZE<<order);
-       
-       for (i=0; i < nr_copy_pages; i++)
-               if ((pagedir+i)->orig_address >= addr &&
-                       (pagedir+i)->orig_address < addre)
-                       return 1;
-
-       return 0;
-}
-
-/*
- * 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
- */
-static int __init check_pagedir(void)
-{
-       int i;
-
-       for(i=0; i < nr_copy_pages; i++) {
-               unsigned long addr;
-
-               do {
-                       addr = get_zeroed_page(GFP_ATOMIC);
-                       if(!addr)
-                               return -ENOMEM;
-               } while (does_collide(addr));
-
-               (pagedir_nosave+i)->address = addr;
-       }
-       return 0;
-}
-
-static int __init swsusp_pagedir_relocate(void)
-{
-       /*
-        * We have to avoid recursion (not to overflow kernel stack),
-        * and that's why code looks pretty cryptic 
-        */
-       suspend_pagedir_t *old_pagedir = pagedir_nosave;
-       void **eaten_memory = NULL;
-       void **c = eaten_memory, *m, *f;
-       int ret = 0;
-
-       printk("Relocating pagedir ");
-
-       if (!does_collide_order(old_pagedir, (unsigned long)old_pagedir, 
pagedir_order)) {
-               printk("not necessary\n");
-               return check_pagedir();
-       }
-
-       while ((m = (void *) __get_free_pages(GFP_ATOMIC, pagedir_order)) != 
NULL) {
-               if (!does_collide_order(old_pagedir, (unsigned long)m, 
pagedir_order))
-                       break;
-               eaten_memory = m;
-               printk( "." ); 
-               *eaten_memory = c;
-               c = eaten_memory;
-       }
-
-       if (!m) {
-               printk("out of memory\n");
-               ret = -ENOMEM;
-       } else {
-               pagedir_nosave =
-                       memcpy(m, old_pagedir, PAGE_SIZE << pagedir_order);
-       }
-
-       c = eaten_memory;
-       while (c) {
-               printk(":");
-               f = c;
-               c = *c;
-               free_pages((unsigned long)f, pagedir_order);
-       }
-       if (ret)
-               return ret;
-       printk("|\n");
-       return check_pagedir();
-}
-
 /**
  *     Using bio to read from swap.
  *     This code requires a bit more work than just using buffer heads
@@ -1100,7 +1359,6 @@ static int __init check_header(void)
                return -EPERM;
        }
        nr_copy_pages = swsusp_info.image_pages;
-       pagedir_order = get_bitmask_order(SUSPEND_PD_PAGES(nr_copy_pages));
        return error;
 }
 
@@ -1136,23 +1394,20 @@ static int __init check_sig(void)
 
 static int __init data_read(void)
 {
-       struct pbe * p;
+       struct pbe * p, * n;
        int error;
        int i;
-       int mod = nr_copy_pages / 100;
 
-       if (!mod)
-               mod = 1;
+       if ((error = check_pagedir())) {
+               return -ENOMEM;
+       }
 
-       if ((error = swsusp_pagedir_relocate()))
-               return error;
+       mod_progress = nr_copy_pages / 100;
 
        printk( "Reading image data (%d pages):     ", nr_copy_pages );
-       for(i = 0, p = pagedir_nosave; i < nr_copy_pages && !error; i++, p++) {
-               if (!(i%mod))
-                       printk( "\b\b\b\b%3d%%", i / mod );
-               error = bio_read_page(swp_offset(p->swap_address),
-                                 (void *)p->address);
+       pbe_for_each(p, n, i, nr_copy_pages, pagedir_nosave) {
+               error = read_one_pbe(p, (void*)p->address, i);
+               if (error) break;
        }
        printk(" %d done.\n",i);
        return error;
@@ -1163,26 +1418,24 @@ extern dev_t __init name_to_dev_t(const 
 
 static int __init read_pagedir(void)
 {
-       unsigned long addr;
-       int i, n = swsusp_info.pagedir_pages;
-       int error = 0;
+       int error = 0, i = 0, n = swsusp_info.pagedir_pages;
+       suspend_pagedir_t *pgdir, *next;
 
-       addr = __get_free_pages(GFP_ATOMIC, pagedir_order);
-       if (!addr)
-               return -ENOMEM;
-       pagedir_nosave = (struct pbe *)addr;
+       error = alloc_pagedir(&pagedir_nosave, nr_copy_pages, 0, n);
+       if (error < 0)
+               return error;
 
        pr_debug("swsusp: Reading pagedir (%d Pages)\n",n);
 
-       for (i = 0; i < n && !error; i++, addr += PAGE_SIZE) {
-               unsigned long offset = swp_offset(swsusp_info.pagedir[i]);
-               if (offset)
-                       error = bio_read_page(offset, (void *)addr);
-               else
-                       error = -EFAULT;
+       pgdir_for_each(pgdir, next, pagedir_nosave) {
+               error = read_one_pagedir(pgdir, i);
+               if (error) break;
+               pgdir[PBE_PAGE_NUMS-1].dummy.val = pgdir ? pgdir ->dummy.val : 
0;
+               i++;
        }
+       BUG_ON(i != n);
        if (error)
-               free_pages((unsigned long)pagedir_nosave, pagedir_order);
+               pagedir_free(pagedir_nosave);
        return error;
 }
 
@@ -1197,7 +1450,7 @@ static int __init read_suspend_image(voi
        if ((error = read_pagedir()))
                return error;
        if ((error = data_read()))
-               free_pages((unsigned long)pagedir_nosave, pagedir_order);
+               pagedir_free(pagedir_nosave);
        return error;
 }
 
2005-1-16.i386.diff

--- 2.6.11-rc1-mm1/arch/i386/power/swsusp.S     2004-12-30 14:56:21.000000000 
+0800
+++ 2.6.11-rc1-mm1-swsusp/arch/i386/power/swsusp.S      2005-01-14 
21:46:08.000000000 +0800
@@ -31,24 +31,36 @@ ENTRY(swsusp_arch_resume)
        movl $swsusp_pg_dir-__PAGE_OFFSET,%ecx
        movl %ecx,%cr3
 
-       movl    pagedir_nosave, %ebx
-       xorl    %eax, %eax
-       xorl    %edx, %edx
-       .p2align 4,,7
+       movl  pagedir_nosave, %eax
+       test %eax, %eax
+       je   copy_loop_end
+       movl  $1024, %edx
 
-copy_loop:
-       movl    4(%ebx,%edx),%edi
-       movl    (%ebx,%edx),%esi
-
-       movl    $1024, %ecx
-       rep
-       movsl
-
-       incl    %eax
-       addl    $16, %edx
-       cmpl    nr_copy_pages,%eax
-       jb copy_loop
        .p2align 4,,7
+copy_loop_start:
+       movl  0xc(%eax), %ebp
+       xorl  %ebx, %ebx
+       leal  0x0(%esi),%esi
+
+copy_one_pgdir:
+       movl  0x4(%eax),%edi
+       test %edi, %edi
+       je   copy_loop_end
+
+       movl  (%eax), %esi
+       movl  %edx, %ecx
+       repz movsl %ds:(%esi),%es:(%edi)
+
+       incl  %ebx
+       addl  $0x10, %eax
+       cmpl  $0xff, %ebx
+       jbe  copy_one_pgdir
+       test %ebp, %ebp
+       movl  %ebp, %eax
+       jne  copy_loop_start
+       
+       .p2align 4,,7
+copy_loop_end:
 
        movl saved_context_esp, %esp
        movl saved_context_ebp, %ebp


2005-1-16.x86_64.diff

--- 2.6.11-rc1-mm1/arch/x86_64/kernel/suspend_asm.S     2004-12-30 
14:56:35.000000000 +0800
+++ 2.6.11-rc1-mm1-swsusp/arch/x86_64/kernel/suspend_asm.S      2005-01-16 
14:08:16.000000000 +0800
@@ -35,6 +35,7 @@ ENTRY(swsusp_arch_suspend)
        call swsusp_save
        ret
 
+       .section    .data.nosave
 ENTRY(swsusp_arch_resume)
        /* set up cr3 */        
        leaq    init_level4_pgt(%rip),%rax
@@ -49,43 +50,47 @@ ENTRY(swsusp_arch_resume)
        movq    %rcx, %cr3;
        movq    %rax, %cr4;  # turn PGE back on
 
-       movl    nr_copy_pages(%rip), %eax
-       xorl    %ecx, %ecx
-       movq    $0, %r10
-       testl   %eax, %eax
-       jz      done
-.L105:
-       xorl    %esi, %esi
-       movq    $0, %r11
-       jmp     .L104
-       .p2align 4,,7
+       movq    pagedir_nosave(%rip), %rdi
+       testq   %rdi, %rdi
+       je              done
+
+copyback_page:
+       movq    24(%rdi), %r9
+       xorl    %r8d, %r8d
+
+copy_one_pgdir:
+       movq    8(%rdi), %rsi
+       testq   %rsi, %rsi
+       je      done
+       movq    (%rdi), %rcx
+       xorl    %edx, %edx
+
 copy_one_page:
-       movq    %r10, %rcx
-.L104:
-       movq    pagedir_nosave(%rip), %rdx
-       movq    %rcx, %rax
-       salq    $5, %rax
-       movq    8(%rdx,%rax), %rcx
-       movq    (%rdx,%rax), %rax
-       movzbl  (%rsi,%rax), %eax
-       movb    %al, (%rsi,%rcx)
-
-       movq    %cr3, %rax;  # flush TLB
-       movq    %rax, %cr3;
-
-       movq    %r11, %rax
-       incq    %rax
-       cmpq    $4095, %rax
-       movq    %rax, %rsi
-       movq    %rax, %r11
-       jbe     copy_one_page
-       movq    %r10, %rax
-       incq    %rax
-       movq    %rax, %rcx
-       movq    %rax, %r10
-       mov     nr_copy_pages(%rip), %eax
-       cmpq    %rax, %rcx
-       jb      .L105
+       movq    (%rcx,%rdx,8), %rax
+       movq    %rax, (%rsi,%rdx,8)
+       movq    8(%rcx,%rdx,8), %rax
+       movq    %rax, 8(%rsi,%rdx,8)
+       movq    16(%rcx,%rdx,8), %rax
+       movq    %rax, 16(%rsi,%rdx,8)
+       movq    24(%rcx,%rdx,8), %rax
+       movq    %rax, 24(%rsi,%rdx,8)
+#if 0 /* XXX speep up in qemu */
+       movq    %cr3, %rax;  # flush TLB
+       movq    %rax, %cr3;
+#endif
+       addq    $4, %rdx
+       cmpq    $511, %rdx
+       jbe     copy_one_page; # copy one page
+
+       incq    %r8
+       addq    $32, %rdi
+       cmpq    $127, %r8
+       jbe     copy_one_pgdir; # copy one pgdir
+
+       testq   %r9, %r9
+       movq    %r9, %rdi
+       jne     copyback_page
+
 done:
        movl    $24, %eax
        movl    %eax, %ds

2005-1-18.core.eatmem.diff

--- 2.6.11-rc1-mm1/kernel/power/disk.c  2005-01-14 20:19:58.000000000 +0800
+++ 2.6.11-rc1-mm1-swsusp/kernel/power/disk.c   2005-01-18 09:26:31.000000000 
+0800
@@ -86,23 +86,25 @@ static int in_suspend __nosavedata = 0;
 
 static void free_some_memory(void)
 {
-       unsigned int i = 0;
-       unsigned int tmp;
-       unsigned long pages = 0;
-       char *p = "-\\|/";
-
-       printk("Freeing memory...  ");
-       while ((tmp = shrink_all_memory(10000))) {
-               pages += tmp;
-               printk("\b%c", p[i]);
-               i++;
-               if (i > 3)
-                       i = 0;
+       int i;
+       for (i=0; i<5; i++) {
+               int i = 0, tmp;
+               long pages = 0;
+               char *p = "-\\|/";
+
+               printk("Freeing memory...  ");
+               while ((tmp = shrink_all_memory(10000))) {
+                       pages += tmp;
+                       printk("\b%c", p[i]);
+                       i++;
+                       if (i > 3)
+                               i = 0;
+               }
+               printk("\bdone (%li pages freed)\n", pages);
+               msleep_interruptible(200);
        }
-       printk("\bdone (%li pages freed)\n", pages);
 }
 
-
 static inline void platform_finish(void)
 {
        if (pm_disk_mode == PM_DISK_PLATFORM) {
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to