Commit 84e1d836 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'pm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6

* 'pm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6:
  PM / Hibernate: Avoid hitting OOM during preallocation of memory
  PM QoS: Correct pr_debug() misuse and improve parameter checks
  PM: Prevent waiting forever on asynchronous resume after failing suspend
parents 20f4cad6 6715045d
...@@ -59,6 +59,7 @@ void device_pm_init(struct device *dev) ...@@ -59,6 +59,7 @@ void device_pm_init(struct device *dev)
{ {
dev->power.status = DPM_ON; dev->power.status = DPM_ON;
init_completion(&dev->power.completion); init_completion(&dev->power.completion);
complete_all(&dev->power.completion);
dev->power.wakeup_count = 0; dev->power.wakeup_count = 0;
pm_runtime_init(dev); pm_runtime_init(dev);
} }
......
...@@ -389,10 +389,12 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, ...@@ -389,10 +389,12 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
} else if (count == 11) { /* len('0x12345678/0') */ } else if (count == 11) { /* len('0x12345678/0') */
if (copy_from_user(ascii_value, buf, 11)) if (copy_from_user(ascii_value, buf, 11))
return -EFAULT; return -EFAULT;
if (strlen(ascii_value) != 10)
return -EINVAL;
x = sscanf(ascii_value, "%x", &value); x = sscanf(ascii_value, "%x", &value);
if (x != 1) if (x != 1)
return -EINVAL; return -EINVAL;
pr_debug(KERN_ERR "%s, %d, 0x%x\n", ascii_value, x, value); pr_debug("%s, %d, 0x%x\n", ascii_value, x, value);
} else } else
return -EINVAL; return -EINVAL;
......
...@@ -1121,9 +1121,19 @@ static unsigned long preallocate_image_pages(unsigned long nr_pages, gfp_t mask) ...@@ -1121,9 +1121,19 @@ static unsigned long preallocate_image_pages(unsigned long nr_pages, gfp_t mask)
return nr_alloc; return nr_alloc;
} }
static unsigned long preallocate_image_memory(unsigned long nr_pages) static unsigned long preallocate_image_memory(unsigned long nr_pages,
unsigned long avail_normal)
{ {
return preallocate_image_pages(nr_pages, GFP_IMAGE); unsigned long alloc;
if (avail_normal <= alloc_normal)
return 0;
alloc = avail_normal - alloc_normal;
if (nr_pages < alloc)
alloc = nr_pages;
return preallocate_image_pages(alloc, GFP_IMAGE);
} }
#ifdef CONFIG_HIGHMEM #ifdef CONFIG_HIGHMEM
...@@ -1169,15 +1179,22 @@ static inline unsigned long preallocate_highmem_fraction(unsigned long nr_pages, ...@@ -1169,15 +1179,22 @@ static inline unsigned long preallocate_highmem_fraction(unsigned long nr_pages,
*/ */
static void free_unnecessary_pages(void) static void free_unnecessary_pages(void)
{ {
unsigned long save_highmem, to_free_normal, to_free_highmem; unsigned long save, to_free_normal, to_free_highmem;
to_free_normal = alloc_normal - count_data_pages(); save = count_data_pages();
save_highmem = count_highmem_pages(); if (alloc_normal >= save) {
if (alloc_highmem > save_highmem) { to_free_normal = alloc_normal - save;
to_free_highmem = alloc_highmem - save_highmem; save = 0;
} else {
to_free_normal = 0;
save -= alloc_normal;
}
save += count_highmem_pages();
if (alloc_highmem >= save) {
to_free_highmem = alloc_highmem - save;
} else { } else {
to_free_highmem = 0; to_free_highmem = 0;
to_free_normal -= save_highmem - alloc_highmem; to_free_normal -= save - alloc_highmem;
} }
memory_bm_position_reset(&copy_bm); memory_bm_position_reset(&copy_bm);
...@@ -1258,7 +1275,7 @@ int hibernate_preallocate_memory(void) ...@@ -1258,7 +1275,7 @@ int hibernate_preallocate_memory(void)
{ {
struct zone *zone; struct zone *zone;
unsigned long saveable, size, max_size, count, highmem, pages = 0; unsigned long saveable, size, max_size, count, highmem, pages = 0;
unsigned long alloc, save_highmem, pages_highmem; unsigned long alloc, save_highmem, pages_highmem, avail_normal;
struct timeval start, stop; struct timeval start, stop;
int error; int error;
...@@ -1295,6 +1312,7 @@ int hibernate_preallocate_memory(void) ...@@ -1295,6 +1312,7 @@ int hibernate_preallocate_memory(void)
else else
count += zone_page_state(zone, NR_FREE_PAGES); count += zone_page_state(zone, NR_FREE_PAGES);
} }
avail_normal = count;
count += highmem; count += highmem;
count -= totalreserve_pages; count -= totalreserve_pages;
...@@ -1309,12 +1327,21 @@ int hibernate_preallocate_memory(void) ...@@ -1309,12 +1327,21 @@ int hibernate_preallocate_memory(void)
*/ */
if (size >= saveable) { if (size >= saveable) {
pages = preallocate_image_highmem(save_highmem); pages = preallocate_image_highmem(save_highmem);
pages += preallocate_image_memory(saveable - pages); pages += preallocate_image_memory(saveable - pages, avail_normal);
goto out; goto out;
} }
/* Estimate the minimum size of the image. */ /* Estimate the minimum size of the image. */
pages = minimum_image_size(saveable); pages = minimum_image_size(saveable);
/*
* To avoid excessive pressure on the normal zone, leave room in it to
* accommodate an image of the minimum size (unless it's already too
* small, in which case don't preallocate pages from it at all).
*/
if (avail_normal > pages)
avail_normal -= pages;
else
avail_normal = 0;
if (size < pages) if (size < pages)
size = min_t(unsigned long, pages, max_size); size = min_t(unsigned long, pages, max_size);
...@@ -1335,16 +1362,34 @@ int hibernate_preallocate_memory(void) ...@@ -1335,16 +1362,34 @@ int hibernate_preallocate_memory(void)
*/ */
pages_highmem = preallocate_image_highmem(highmem / 2); pages_highmem = preallocate_image_highmem(highmem / 2);
alloc = (count - max_size) - pages_highmem; alloc = (count - max_size) - pages_highmem;
pages = preallocate_image_memory(alloc); pages = preallocate_image_memory(alloc, avail_normal);
if (pages < alloc) if (pages < alloc) {
goto err_out; /* We have exhausted non-highmem pages, try highmem. */
size = max_size - size; alloc -= pages;
alloc = size; pages += pages_highmem;
size = preallocate_highmem_fraction(size, highmem, count); pages_highmem = preallocate_image_highmem(alloc);
pages_highmem += size; if (pages_highmem < alloc)
alloc -= size; goto err_out;
pages += preallocate_image_memory(alloc); pages += pages_highmem;
pages += pages_highmem; /*
* size is the desired number of saveable pages to leave in
* memory, so try to preallocate (all memory - size) pages.
*/
alloc = (count - pages) - size;
pages += preallocate_image_highmem(alloc);
} else {
/*
* There are approximately max_size saveable pages at this point
* and we want to reduce this number down to size.
*/
alloc = max_size - size;
size = preallocate_highmem_fraction(alloc, highmem, count);
pages_highmem += size;
alloc -= size;
size = preallocate_image_memory(alloc, avail_normal);
pages_highmem += preallocate_image_highmem(alloc - size);
pages += pages_highmem + size;
}
/* /*
* We only need as many page frames for the image as there are saveable * We only need as many page frames for the image as there are saveable
......
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