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:
@@ -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)
|
|||||||
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);
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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);
|
|
||||||
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);
|
error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
|
||||||
if (error)
|
if (error)
|
||||||
pm_notifier_call_chain(PM_POST_HIBERNATION);
|
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)
|
if (error)
|
||||||
atomic_inc(&snapshot_device_available);
|
atomic_inc(&snapshot_device_available);
|
||||||
|
@@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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);
|
||||||
|
28
mm/vmscan.c
28
mm/vmscan.c
@@ -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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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)
|
|||||||
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;
|
||||||
|
Reference in New Issue
Block a user