Bug 60817

Summary: [PATCH]Hibernation may fails when memory utilization too high
Product: Power Management Reporter: Leon Drugi (eyak)
Component: Hibernation/SuspendAssignee: Aaron Lu (aaron.lu)
Status: CLOSED CODE_FIX    
Severity: normal CC: aaron.lu, alan
Priority: P1    
Hardware: i386   
OS: Linux   
Kernel Version: 3.6.10 Subsystem:
Regression: No Bisected commit-id:
Attachments: Quick fix patch for systems with a lot of highmem

Description Leon Drugi 2013-08-30 05:30:34 UTC
Hello,

I use 3.6.10 kernel on Debian Wheezy and have problems with hibernation. I have 16GiB RAM and 50GiB swap. I observed that when current memory utilization (with top command) is 3GiB or more (not exact value, but approximation) then hibernation not working and the system resumes immediatelly. The /var/log/messages file contains the following log:

Aug 28 12:51:03 debian kernel: [316490.714902] PM: Syncing filesystems ... done.
Aug 28 12:51:03 debian kernel: [316490.976982] Freezing user space processes ... (elapsed 0.01 seconds) done.
Aug 28 12:51:03 debian kernel: [316490.990581] PM: Preallocating image memory... 
Aug 28 12:51:03 debian kernel: [316506.417789] Restarting tasks ... done.


I added the following debug messages:

$ diff -u kernel/power/snapshot.c.oryg kernel/power/snapshot.c
--- kernel/power/snapshot.c.oryg        2013-08-29 09:20:30.879713207 +0200
+++ kernel/power/snapshot.c     2013-08-29 10:38:26.407108689 +0200
@@ -1312,15 +1312,15 @@
 
        printk(KERN_INFO "PM: Preallocating image memory... ");
        do_gettimeofday(&start);
-
+       printk(KERN_INFO "PM:%d\n",__LINE__);
        error = memory_bm_create(&orig_bm, GFP_IMAGE, PG_ANY);
        if (error)
                goto err_out;
-
+       printk(KERN_INFO "PM:%d\n",__LINE__);
        error = memory_bm_create(&copy_bm, GFP_IMAGE, PG_ANY);
        if (error)
                goto err_out;
-
+       printk(KERN_INFO "PM:%d\n",__LINE__);
        alloc_normal = 0;
        alloc_highmem = 0;
 
@@ -1362,12 +1362,13 @@
         * current number of saveable pages in memory, allocate page frames for
         * the image and we're done.
         */
+       printk(KERN_INFO "PM:%d size:%lu, saveable:%lu\n",__LINE__, size, saveable);
        if (size >= saveable) {
                pages = preallocate_image_highmem(save_highmem);
                pages += preallocate_image_memory(saveable - pages, avail_normal);
                goto out;
        }
-
+       printk(KERN_INFO "PM:%d\n",__LINE__);
        /* Estimate the minimum size of the image. */
        pages = minimum_image_size(saveable);
        /*
@@ -1400,11 +1401,15 @@
        pages_highmem = preallocate_image_highmem(highmem / 2);
        alloc = (count - max_size) - pages_highmem;
        pages = preallocate_image_memory(alloc, avail_normal);
+       printk(KERN_INFO "PM:%d highmem:%lu pages_highmem:%lu\n",__LINE__,highmem, pages_highmem);
+       printk(KERN_INFO "PM:%d count:%lu max_size:%lu\n",__LINE__,count, max_size);
+       printk(KERN_INFO "PM:%d pages:%lu alloc:%lu\n",__LINE__,pages, alloc);
        if (pages < alloc) {
                /* We have exhausted non-highmem pages, try highmem. */
                alloc -= pages;
                pages += pages_highmem;
                pages_highmem = preallocate_image_highmem(alloc);
+               printk(KERN_INFO "PM:%d pages_highmem:%lu\n",__LINE__,pages_highmem);
                if (pages_highmem < alloc)
                        goto err_out;
                pages += pages_highmem;

And then got the following info in /var/log/messages:

Aug 29 11:03:31 debian kernel: [  174.804982] PM: Syncing filesystems ... done.
Aug 29 11:03:32 debian kernel: [  175.018801] Freezing user space processes ... (elapsed 0.01 seconds) done.
Aug 29 11:03:32 debian kernel: [  175.034689] PM: Preallocating image memory... 
Aug 29 11:03:32 debian kernel: [  175.034690] PM:1315
Aug 29 11:03:32 debian kernel: [  175.034737] PM:1319
Aug 29 11:03:32 debian kernel: [  175.034781] PM:1323
Aug 29 11:03:32 debian kernel: [  175.198475] PM:1365 size:488282, saveable:818077
Aug 29 11:03:32 debian kernel: [  175.198477] PM:1371
Aug 29 11:03:32 debian kernel: [  175.947178] PM:1404 highmem:3956560 pages_highmem:1978280
Aug 29 11:03:32 debian kernel: [  175.947180] PM:1405 count:3943404 max_size:1970542
Aug 29 11:03:32 debian kernel: [  175.947181] PM:1406 pages:118426 alloc:4294961878
Aug 29 11:03:32 debian kernel: [  185.352026] PM:1412 pages_highmem:1927482
Aug 29 11:03:32 debian kernel: [  185.352028] 
Aug 29 11:03:32 debian kernel: [  185.695000] Restarting tasks ... done.

It looks that during computing 'alloc' variable there is overflow:

alloc = (3943404 - 1970542) - 1978280 = -5418 (signed)

And this function goes to err_out.

Best Regards
Leon
Comment 1 Aaron Lu 2013-09-17 01:54:47 UTC
Thanks for the report, I'm looking into this issue. In the mean time, does x86_64 kernel have this problem too?
Comment 2 Leon Drugi 2013-10-18 06:50:28 UTC
Hello,

Sorry for the delayed reponse. The notofication somehow went into spam. 

I have only 32-bit system installed and I cannot test the issue under 64-bit OS version.

Regards
Pawel
Comment 3 Aaron Lu 2013-11-01 09:02:19 UTC
Created attachment 113021 [details]
Quick fix patch for systems with a lot of highmem

Please test if this patch helps, thanks.
Apply on top of linus' tree or v3.11.x.
Comment 4 Leon Drugi 2013-11-05 05:31:25 UTC
Hello,

Yes, the patch working perfectly. With 6GB memory utilization I can sucessfully hibernate and resume the system.

Many thanks.

Regards
Leon
Comment 5 Aaron Lu 2013-11-05 07:04:51 UTC
That is due to your excellent data provided :-)
I'll send out the patch to maintainer and CC you, thanks.
Comment 6 Aaron Lu 2013-11-05 07:18:40 UTC
Patch sent out:
https://patchwork.kernel.org/patch/3139671/
Comment 7 Aaron Lu 2013-11-28 02:09:56 UTC
commit fd432b9f8c7c88428a4635b9f5a9c6e174df6e36
Author: Aaron Lu <aaron.lu@intel.com>
Date:   Wed Nov 6 08:41:31 2013 +0800

    PM / hibernate: Avoid overflow in hibernate_preallocate_memory()

entered Linus' tree.