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
This commit is contained in:
Linus Torvalds 2009-02-21 14:17:26 -08:00
commit adfafefd10
10 changed files with 77 additions and 36 deletions

View file

@ -18,9 +18,11 @@
*/
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/async.h>
#include "base.h"
#include "power/power.h"
@ -167,6 +169,21 @@ int driver_probe_done(void)
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
* @drv: driver to bind a device to

View file

@ -147,6 +147,8 @@ extern void put_driver(struct device_driver *drv);
extern struct device_driver *driver_find(const char *name,
struct bus_type *bus);
extern int driver_probe_done(void);
extern int wait_for_device_probe(void);
/* sysfs interface for exporting driver attributes */

View file

@ -370,10 +370,14 @@ void __init prepare_namespace(void)
ssleep(root_delay);
}
/* wait for the known devices to complete their probing */
while (driver_probe_done() != 0)
msleep(100);
async_synchronize_full();
/*
* wait for the known devices to complete their probing
*
* 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();
@ -399,6 +403,7 @@ void __init prepare_namespace(void)
while (driver_probe_done() != 0 ||
(ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)
msleep(100);
async_synchronize_full();
}
is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;

View file

@ -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: 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);
if (fd >= 0) {
sys_ioctl(fd, RAID_AUTORUN, raid_autopart);

View file

@ -78,6 +78,12 @@ void pm_restore_console(void)
}
set_console(orig_fgconsole);
release_console_sem();
if (vt_waitactive(orig_fgconsole)) {
pr_debug("Resume: Can't switch VCs.");
return;
}
kmsg_redirect = orig_kmsg;
}
#endif

View file

@ -594,6 +594,12 @@ static int software_resume(void)
int error;
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
* is configured into the kernel. Since the regular hibernate
@ -610,6 +616,11 @@ static int software_resume(void)
mutex_unlock(&pm_mutex);
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);
pr_debug("PM: Resume from partition %s\n", resume_file);
} else {

View file

@ -95,15 +95,15 @@ static int snapshot_open(struct inode *inode, struct file *filp)
data->swap = swsusp_resume_device ?
swap_type_of(swsusp_resume_device, 0, NULL) : -1;
data->mode = O_RDONLY;
error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
if (error)
pm_notifier_call_chain(PM_POST_RESTORE);
} else {
data->swap = -1;
data->mode = O_WRONLY;
error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
if (error)
pm_notifier_call_chain(PM_POST_HIBERNATION);
} else {
data->swap = -1;
data->mode = O_WRONLY;
error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
if (error)
pm_notifier_call_chain(PM_POST_RESTORE);
}
if (error)
atomic_inc(&snapshot_device_available);

View file

@ -73,7 +73,6 @@ EXPORT_SYMBOL(oops_in_progress);
* driver system.
*/
static DECLARE_MUTEX(console_sem);
static DECLARE_MUTEX(secondary_console_sem);
struct console *console_drivers;
EXPORT_SYMBOL_GPL(console_drivers);
@ -891,12 +890,14 @@ void suspend_console(void)
printk("Suspending console(s) (use no_console_suspend to debug)\n");
acquire_console_sem();
console_suspended = 1;
up(&console_sem);
}
void resume_console(void)
{
if (!console_suspend_enabled)
return;
down(&console_sem);
console_suspended = 0;
release_console_sem();
}
@ -912,11 +913,9 @@ void resume_console(void)
void acquire_console_sem(void)
{
BUG_ON(in_interrupt());
if (console_suspended) {
down(&secondary_console_sem);
return;
}
down(&console_sem);
if (console_suspended)
return;
console_locked = 1;
console_may_schedule = 1;
}
@ -926,6 +925,10 @@ int try_acquire_console_sem(void)
{
if (down_trylock(&console_sem))
return -1;
if (console_suspended) {
up(&console_sem);
return -1;
}
console_locked = 1;
console_may_schedule = 0;
return 0;
@ -979,7 +982,7 @@ void release_console_sem(void)
unsigned wake_klogd = 0;
if (console_suspended) {
up(&secondary_console_sem);
up(&console_sem);
return;
}

View file

@ -635,7 +635,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
if (!bdev) {
if (bdev_p)
*bdev_p = sis->bdev;
*bdev_p = bdget(sis->bdev->bd_dev);
spin_unlock(&swap_lock);
return i;
@ -647,7 +647,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
struct swap_extent, list);
if (se->start_block == offset) {
if (bdev_p)
*bdev_p = sis->bdev;
*bdev_p = bdget(sis->bdev->bd_dev);
spin_unlock(&swap_lock);
bdput(bdev);

View file

@ -2057,31 +2057,31 @@ static unsigned long shrink_all_zones(unsigned long nr_pages, int prio,
int pass, struct scan_control *sc)
{
struct zone *zone;
unsigned long nr_to_scan, ret = 0;
enum lru_list l;
unsigned long ret = 0;
for_each_zone(zone) {
enum lru_list l;
if (!populated_zone(zone))
continue;
if (zone_is_all_unreclaimable(zone) && prio != DEF_PRIORITY)
continue;
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 */
if (pass == 0 &&
(l == LRU_ACTIVE || l == LRU_ACTIVE_FILE))
if (pass == 0 && (l == LRU_ACTIVE_ANON ||
l == LRU_ACTIVE_FILE))
continue;
zone->lru[l].nr_scan +=
(zone_page_state(zone, NR_LRU_BASE + l)
>> prio) + 1;
zone->lru[l].nr_scan += (lru_pages >> prio) + 1;
if (zone->lru[l].nr_scan >= nr_pages || pass > 3) {
unsigned long nr_to_scan;
zone->lru[l].nr_scan = 0;
nr_to_scan = min(nr_pages,
zone_page_state(zone,
NR_LRU_BASE + l));
nr_to_scan = min(nr_pages, lru_pages);
ret += shrink_list(l, nr_to_scan, zone,
sc, prio);
if (ret >= nr_pages)
@ -2089,7 +2089,6 @@ static unsigned long shrink_all_zones(unsigned long nr_pages, int prio,
}
}
}
return ret;
}
@ -2112,7 +2111,6 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
.may_swap = 0,
.swap_cluster_max = nr_pages,
.may_writepage = 1,
.swappiness = vm_swappiness,
.isolate_pages = isolate_pages_global,
};
@ -2146,10 +2144,8 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
int prio;
/* Force reclaiming mapped pages in the passes #3 and #4 */
if (pass > 2) {
if (pass > 2)
sc.may_swap = 1;
sc.swappiness = 100;
}
for (prio = DEF_PRIORITY; prio >= 0; prio--) {
unsigned long nr_to_scan = nr_pages - ret;