netfilter: nfnetlink_log: fix silly refcount leak
[safe/jmp/linux-2.6] / kernel / power / hibernate.c
index 81d2e74..bbfe472 100644 (file)
@@ -32,6 +32,7 @@ static int noresume = 0;
 static char resume_file[256] = CONFIG_PM_STD_PARTITION;
 dev_t swsusp_resume_device;
 sector_t swsusp_resume_block;
+int in_suspend __nosavedata = 0;
 
 enum {
        HIBERNATION_INVALID,
@@ -202,6 +203,35 @@ static void platform_recover(int platform_mode)
 }
 
 /**
+ *     swsusp_show_speed - print the time elapsed between two events.
+ *     @start: Starting event.
+ *     @stop: Final event.
+ *     @nr_pages -     number of pages processed between @start and @stop
+ *     @msg -          introductory message to print
+ */
+
+void swsusp_show_speed(struct timeval *start, struct timeval *stop,
+                       unsigned nr_pages, char *msg)
+{
+       s64 elapsed_centisecs64;
+       int centisecs;
+       int k;
+       int kps;
+
+       elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start);
+       do_div(elapsed_centisecs64, NSEC_PER_SEC / 100);
+       centisecs = elapsed_centisecs64;
+       if (centisecs == 0)
+               centisecs = 1;  /* avoid div-by-zero */
+       k = nr_pages * (PAGE_SIZE / 1024);
+       kps = (k * 100) / centisecs;
+       printk(KERN_INFO "PM: %s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n",
+                       msg, k,
+                       centisecs / 100, centisecs % 100,
+                       kps / 1000, (kps % 1000) / 10);
+}
+
+/**
  *     create_image - freeze devices that need to be frozen with interrupts
  *     off, create the hibernation image and thaw those devices.  Control
  *     reappears in this routine after a restore.
@@ -298,8 +328,8 @@ int hibernation_snapshot(int platform_mode)
        if (error)
                return error;
 
-       /* Free memory before shutting down devices. */
-       error = swsusp_shrink_memory();
+       /* Preallocate image memory before shutting down devices. */
+       error = hibernate_preallocate_memory();
        if (error)
                goto Close;
 
@@ -315,6 +345,10 @@ int hibernation_snapshot(int platform_mode)
        /* Control returns here after successful restore */
 
  Resume_devices:
+       /* We may need to release the preallocated image pages here. */
+       if (error || !in_suspend)
+               swsusp_free();
+
        dpm_resume_end(in_suspend ?
                (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
        resume_console();
@@ -460,11 +494,11 @@ int hibernation_platform_enter(void)
 
        error = hibernation_ops->prepare();
        if (error)
-               goto Platofrm_finish;
+               goto Platform_finish;
 
        error = disable_nonboot_cpus();
        if (error)
-               goto Platofrm_finish;
+               goto Platform_finish;
 
        local_irq_disable();
        sysdev_suspend(PMSG_HIBERNATE);
@@ -476,7 +510,7 @@ int hibernation_platform_enter(void)
         * We don't need to reenable the nonboot CPUs or resume consoles, since
         * the system is going to be halted anyway.
         */
- Platofrm_finish:
+ Platform_finish:
        hibernation_ops->finish();
 
        dpm_suspend_noirq(PMSG_RESTORE);
@@ -578,7 +612,10 @@ int hibernate(void)
                goto Thaw;
 
        error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
-       if (in_suspend && !error) {
+       if (error)
+               goto Thaw;
+
+       if (in_suspend) {
                unsigned int flags = 0;
 
                if (hibernation_mode == HIBERNATION_PLATFORM)
@@ -590,8 +627,8 @@ int hibernate(void)
                        power_down();
        } else {
                pr_debug("PM: Image restored successfully.\n");
-               swsusp_free();
        }
+
  Thaw:
        thaw_processes();
  Finish:
@@ -686,21 +723,22 @@ static int software_resume(void)
        /* The snapshot device should not be opened while we're running */
        if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
                error = -EBUSY;
+               swsusp_close(FMODE_READ);
                goto Unlock;
        }
 
        pm_prepare_console();
        error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
        if (error)
-               goto Finish;
+               goto close_finish;
 
        error = usermodehelper_disable();
        if (error)
-               goto Finish;
+               goto close_finish;
 
        error = create_basic_memory_bitmaps();
        if (error)
-               goto Finish;
+               goto close_finish;
 
        pr_debug("PM: Preparing processes for restore.\n");
        error = prepare_processes();
@@ -712,6 +750,7 @@ static int software_resume(void)
        pr_debug("PM: Reading hibernation image.\n");
 
        error = swsusp_read(&flags);
+       swsusp_close(FMODE_READ);
        if (!error)
                hibernation_restore(flags & SF_PLATFORM_MODE);
 
@@ -730,6 +769,9 @@ static int software_resume(void)
        mutex_unlock(&pm_mutex);
        pr_debug("PM: Resume from disk failed.\n");
        return error;
+close_finish:
+       swsusp_close(FMODE_READ);
+       goto Finish;
 }
 
 late_initcall(software_resume);