Commit adfafefd authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'hibernate'

* hibernate:
  PM: Fix suspend_console and resume_console to use only one semaphore
  PM: Wait for console in resume
  PM: Fix pm_notifiers during user mode hibernation
  swsusp: clean up shrink_all_zones()
  swsusp: dont fiddle with swappiness
  PM: fix build for CONFIG_PM unset
  PM/hibernate: fix "swap breaks after hibernation failures"
  PM/resume: wait for device probing to finish
  Consolidate driver_probe_done() loops into one place
parents 460c1338 403f3075
...@@ -18,9 +18,11 @@ ...@@ -18,9 +18,11 @@
*/ */
#include <linux/device.h> #include <linux/device.h>
#include <linux/delay.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/async.h>
#include "base.h" #include "base.h"
#include "power/power.h" #include "power/power.h"
...@@ -167,6 +169,21 @@ int driver_probe_done(void) ...@@ -167,6 +169,21 @@ int driver_probe_done(void)
return 0; return 0;
} }
/**
* wait_for_device_probe
* Wait for device probing to be completed.
*
* Note: this function polls at 100 msec intervals.
*/
int wait_for_device_probe(void)
{
/* wait for the known devices to complete their probing */
while (driver_probe_done() != 0)
msleep(100);
async_synchronize_full();
return 0;
}
/** /**
* driver_probe_device - attempt to bind device & driver together * driver_probe_device - attempt to bind device & driver together
* @drv: driver to bind a device to * @drv: driver to bind a device to
......
...@@ -147,6 +147,8 @@ extern void put_driver(struct device_driver *drv); ...@@ -147,6 +147,8 @@ extern void put_driver(struct device_driver *drv);
extern struct device_driver *driver_find(const char *name, extern struct device_driver *driver_find(const char *name,
struct bus_type *bus); struct bus_type *bus);
extern int driver_probe_done(void); extern int driver_probe_done(void);
extern int wait_for_device_probe(void);
/* sysfs interface for exporting driver attributes */ /* sysfs interface for exporting driver attributes */
......
...@@ -370,10 +370,14 @@ void __init prepare_namespace(void) ...@@ -370,10 +370,14 @@ void __init prepare_namespace(void)
ssleep(root_delay); ssleep(root_delay);
} }
/* wait for the known devices to complete their probing */ /*
while (driver_probe_done() != 0) * wait for the known devices to complete their probing
msleep(100); *
async_synchronize_full(); * Note: this is a potential source of long boot delays.
* For example, it is not atypical to wait 5 seconds here
* for the touchpad of a laptop to initialize.
*/
wait_for_device_probe();
md_run_setup(); md_run_setup();
...@@ -399,6 +403,7 @@ void __init prepare_namespace(void) ...@@ -399,6 +403,7 @@ void __init prepare_namespace(void)
while (driver_probe_done() != 0 || while (driver_probe_done() != 0 ||
(ROOT_DEV = name_to_dev_t(saved_root_name)) == 0) (ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)
msleep(100); msleep(100);
async_synchronize_full();
} }
is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR; is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
......
...@@ -281,8 +281,9 @@ static void __init autodetect_raid(void) ...@@ -281,8 +281,9 @@ static void __init autodetect_raid(void)
*/ */
printk(KERN_INFO "md: Waiting for all devices to be available before autodetect\n"); printk(KERN_INFO "md: Waiting for all devices to be available before autodetect\n");
printk(KERN_INFO "md: If you don't use raid, use raid=noautodetect\n"); printk(KERN_INFO "md: If you don't use raid, use raid=noautodetect\n");
while (driver_probe_done() < 0)
msleep(100); wait_for_device_probe();
fd = sys_open("/dev/md0", 0, 0); fd = sys_open("/dev/md0", 0, 0);
if (fd >= 0) { if (fd >= 0) {
sys_ioctl(fd, RAID_AUTORUN, raid_autopart); sys_ioctl(fd, RAID_AUTORUN, raid_autopart);
......
...@@ -78,6 +78,12 @@ void pm_restore_console(void) ...@@ -78,6 +78,12 @@ void pm_restore_console(void)
} }
set_console(orig_fgconsole); set_console(orig_fgconsole);
release_console_sem(); release_console_sem();
if (vt_waitactive(orig_fgconsole)) {
pr_debug("Resume: Can't switch VCs.");
return;
}
kmsg_redirect = orig_kmsg; kmsg_redirect = orig_kmsg;
} }
#endif #endif
...@@ -594,6 +594,12 @@ static int software_resume(void) ...@@ -594,6 +594,12 @@ static int software_resume(void)
int error; int error;
unsigned int flags; unsigned int flags;
/*
* If the user said "noresume".. bail out early.
*/
if (noresume)
return 0;
/* /*
* name_to_dev_t() below takes a sysfs buffer mutex when sysfs * name_to_dev_t() below takes a sysfs buffer mutex when sysfs
* is configured into the kernel. Since the regular hibernate * is configured into the kernel. Since the regular hibernate
...@@ -610,6 +616,11 @@ static int software_resume(void) ...@@ -610,6 +616,11 @@ static int software_resume(void)
mutex_unlock(&pm_mutex); mutex_unlock(&pm_mutex);
return -ENOENT; return -ENOENT;
} }
/*
* Some device discovery might still be in progress; we need
* to wait for this to finish.
*/
wait_for_device_probe();
swsusp_resume_device = name_to_dev_t(resume_file); swsusp_resume_device = name_to_dev_t(resume_file);
pr_debug("PM: Resume from partition %s\n", resume_file); pr_debug("PM: Resume from partition %s\n", resume_file);
} else { } else {
......
...@@ -95,15 +95,15 @@ static int snapshot_open(struct inode *inode, struct file *filp) ...@@ -95,15 +95,15 @@ static int snapshot_open(struct inode *inode, struct file *filp)
data->swap = swsusp_resume_device ? data->swap = swsusp_resume_device ?
swap_type_of(swsusp_resume_device, 0, NULL) : -1; swap_type_of(swsusp_resume_device, 0, NULL) : -1;
data->mode = O_RDONLY; data->mode = O_RDONLY;
error = pm_notifier_call_chain(PM_RESTORE_PREPARE); error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
if (error) if (error)
pm_notifier_call_chain(PM_POST_RESTORE); pm_notifier_call_chain(PM_POST_HIBERNATION);
} else { } else {
data->swap = -1; data->swap = -1;
data->mode = O_WRONLY; data->mode = O_WRONLY;
error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE); error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
if (error) if (error)
pm_notifier_call_chain(PM_POST_HIBERNATION); pm_notifier_call_chain(PM_POST_RESTORE);
} }
if (error) if (error)
atomic_inc(&snapshot_device_available); atomic_inc(&snapshot_device_available);
......
...@@ -73,7 +73,6 @@ EXPORT_SYMBOL(oops_in_progress); ...@@ -73,7 +73,6 @@ EXPORT_SYMBOL(oops_in_progress);
* driver system. * driver system.
*/ */
static DECLARE_MUTEX(console_sem); static DECLARE_MUTEX(console_sem);
static DECLARE_MUTEX(secondary_console_sem);
struct console *console_drivers; struct console *console_drivers;
EXPORT_SYMBOL_GPL(console_drivers); EXPORT_SYMBOL_GPL(console_drivers);
...@@ -891,12 +890,14 @@ void suspend_console(void) ...@@ -891,12 +890,14 @@ void suspend_console(void)
printk("Suspending console(s) (use no_console_suspend to debug)\n"); printk("Suspending console(s) (use no_console_suspend to debug)\n");
acquire_console_sem(); acquire_console_sem();
console_suspended = 1; console_suspended = 1;
up(&console_sem);
} }
void resume_console(void) void resume_console(void)
{ {
if (!console_suspend_enabled) if (!console_suspend_enabled)
return; return;
down(&console_sem);
console_suspended = 0; console_suspended = 0;
release_console_sem(); release_console_sem();
} }
...@@ -912,11 +913,9 @@ void resume_console(void) ...@@ -912,11 +913,9 @@ void resume_console(void)
void acquire_console_sem(void) void acquire_console_sem(void)
{ {
BUG_ON(in_interrupt()); BUG_ON(in_interrupt());
if (console_suspended) {
down(&secondary_console_sem);
return;
}
down(&console_sem); down(&console_sem);
if (console_suspended)
return;
console_locked = 1; console_locked = 1;
console_may_schedule = 1; console_may_schedule = 1;
} }
...@@ -926,6 +925,10 @@ int try_acquire_console_sem(void) ...@@ -926,6 +925,10 @@ int try_acquire_console_sem(void)
{ {
if (down_trylock(&console_sem)) if (down_trylock(&console_sem))
return -1; return -1;
if (console_suspended) {
up(&console_sem);
return -1;
}
console_locked = 1; console_locked = 1;
console_may_schedule = 0; console_may_schedule = 0;
return 0; return 0;
...@@ -979,7 +982,7 @@ void release_console_sem(void) ...@@ -979,7 +982,7 @@ void release_console_sem(void)
unsigned wake_klogd = 0; unsigned wake_klogd = 0;
if (console_suspended) { if (console_suspended) {
up(&secondary_console_sem); up(&console_sem);
return; return;
} }
......
...@@ -635,7 +635,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p) ...@@ -635,7 +635,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
if (!bdev) { if (!bdev) {
if (bdev_p) if (bdev_p)
*bdev_p = sis->bdev; *bdev_p = bdget(sis->bdev->bd_dev);
spin_unlock(&swap_lock); spin_unlock(&swap_lock);
return i; return i;
...@@ -647,7 +647,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p) ...@@ -647,7 +647,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
struct swap_extent, list); struct swap_extent, list);
if (se->start_block == offset) { if (se->start_block == offset) {
if (bdev_p) if (bdev_p)
*bdev_p = sis->bdev; *bdev_p = bdget(sis->bdev->bd_dev);
spin_unlock(&swap_lock); spin_unlock(&swap_lock);
bdput(bdev); bdput(bdev);
......
...@@ -2057,31 +2057,31 @@ static unsigned long shrink_all_zones(unsigned long nr_pages, int prio, ...@@ -2057,31 +2057,31 @@ static unsigned long shrink_all_zones(unsigned long nr_pages, int prio,
int pass, struct scan_control *sc) int pass, struct scan_control *sc)
{ {
struct zone *zone; struct zone *zone;
unsigned long nr_to_scan, ret = 0; unsigned long ret = 0;
enum lru_list l;
for_each_zone(zone) { for_each_zone(zone) {
enum lru_list l;
if (!populated_zone(zone)) if (!populated_zone(zone))
continue; continue;
if (zone_is_all_unreclaimable(zone) && prio != DEF_PRIORITY) if (zone_is_all_unreclaimable(zone) && prio != DEF_PRIORITY)
continue; continue;
for_each_evictable_lru(l) { for_each_evictable_lru(l) {
enum zone_stat_item ls = NR_LRU_BASE + l;
unsigned long lru_pages = zone_page_state(zone, ls);
/* For pass = 0, we don't shrink the active list */ /* For pass = 0, we don't shrink the active list */
if (pass == 0 && if (pass == 0 && (l == LRU_ACTIVE_ANON ||
(l == LRU_ACTIVE || l == LRU_ACTIVE_FILE)) l == LRU_ACTIVE_FILE))
continue; continue;
zone->lru[l].nr_scan += zone->lru[l].nr_scan += (lru_pages >> prio) + 1;
(zone_page_state(zone, NR_LRU_BASE + l)
>> prio) + 1;
if (zone->lru[l].nr_scan >= nr_pages || pass > 3) { if (zone->lru[l].nr_scan >= nr_pages || pass > 3) {
unsigned long nr_to_scan;
zone->lru[l].nr_scan = 0; zone->lru[l].nr_scan = 0;
nr_to_scan = min(nr_pages, nr_to_scan = min(nr_pages, lru_pages);
zone_page_state(zone,
NR_LRU_BASE + l));
ret += shrink_list(l, nr_to_scan, zone, ret += shrink_list(l, nr_to_scan, zone,
sc, prio); sc, prio);
if (ret >= nr_pages) if (ret >= nr_pages)
...@@ -2089,7 +2089,6 @@ static unsigned long shrink_all_zones(unsigned long nr_pages, int prio, ...@@ -2089,7 +2089,6 @@ static unsigned long shrink_all_zones(unsigned long nr_pages, int prio,
} }
} }
} }
return ret; return ret;
} }
...@@ -2112,7 +2111,6 @@ unsigned long shrink_all_memory(unsigned long nr_pages) ...@@ -2112,7 +2111,6 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
.may_swap = 0, .may_swap = 0,
.swap_cluster_max = nr_pages, .swap_cluster_max = nr_pages,
.may_writepage = 1, .may_writepage = 1,
.swappiness = vm_swappiness,
.isolate_pages = isolate_pages_global, .isolate_pages = isolate_pages_global,
}; };
...@@ -2146,10 +2144,8 @@ unsigned long shrink_all_memory(unsigned long nr_pages) ...@@ -2146,10 +2144,8 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
int prio; int prio;
/* Force reclaiming mapped pages in the passes #3 and #4 */ /* Force reclaiming mapped pages in the passes #3 and #4 */
if (pass > 2) { if (pass > 2)
sc.may_swap = 1; sc.may_swap = 1;
sc.swappiness = 100;
}
for (prio = DEF_PRIORITY; prio >= 0; prio--) { for (prio = DEF_PRIORITY; prio >= 0; prio--) {
unsigned long nr_to_scan = nr_pages - ret; unsigned long nr_to_scan = nr_pages - ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment