Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 84e1d836 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* '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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ void device_pm_init(struct device *dev)
{
	dev->power.status = DPM_ON;
	init_completion(&dev->power.completion);
	complete_all(&dev->power.completion);
	dev->power.wakeup_count = 0;
	pm_runtime_init(dev);
}
+3 −1
Original line number Diff line number Diff line
@@ -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') */
		if (copy_from_user(ascii_value, buf, 11))
			return -EFAULT;
		if (strlen(ascii_value) != 10)
			return -EINVAL;
		x = sscanf(ascii_value, "%x", &value);
		if (x != 1)
			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
		return -EINVAL;

+65 −20
Original line number Diff line number Diff line
@@ -1121,9 +1121,19 @@ static unsigned long preallocate_image_pages(unsigned long nr_pages, gfp_t mask)
	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
@@ -1169,15 +1179,22 @@ static inline unsigned long preallocate_highmem_fraction(unsigned long nr_pages,
 */
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_highmem = count_highmem_pages();
	if (alloc_highmem > save_highmem) {
		to_free_highmem = alloc_highmem - save_highmem;
	save = count_data_pages();
	if (alloc_normal >= save) {
		to_free_normal = alloc_normal - save;
		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 {
		to_free_highmem = 0;
		to_free_normal -= save_highmem - alloc_highmem;
		to_free_normal -= save - alloc_highmem;
	}

	memory_bm_position_reset(&copy_bm);
@@ -1258,7 +1275,7 @@ int hibernate_preallocate_memory(void)
{
	struct zone *zone;
	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;
	int error;

@@ -1295,6 +1312,7 @@ int hibernate_preallocate_memory(void)
		else
			count += zone_page_state(zone, NR_FREE_PAGES);
	}
	avail_normal = count;
	count += highmem;
	count -= totalreserve_pages;

@@ -1309,12 +1327,21 @@ int hibernate_preallocate_memory(void)
	 */
	if (size >= saveable) {
		pages = preallocate_image_highmem(save_highmem);
		pages += preallocate_image_memory(saveable - pages);
		pages += preallocate_image_memory(saveable - pages, avail_normal);
		goto out;
	}

	/* Estimate the minimum size of the image. */
	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)
		size = min_t(unsigned long, pages, max_size);

@@ -1335,16 +1362,34 @@ int hibernate_preallocate_memory(void)
	 */
	pages_highmem = preallocate_image_highmem(highmem / 2);
	alloc = (count - max_size) - pages_highmem;
	pages = preallocate_image_memory(alloc);
	if (pages < alloc)
	pages = preallocate_image_memory(alloc, avail_normal);
	if (pages < alloc) {
		/* We have exhausted non-highmem pages, try highmem. */
		alloc -= pages;
		pages += pages_highmem;
		pages_highmem = preallocate_image_highmem(alloc);
		if (pages_highmem < alloc)
			goto err_out;
	size = max_size - size;
	alloc = size;
	size = preallocate_highmem_fraction(size, highmem, count);
		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;
	pages += preallocate_image_memory(alloc);
	pages += pages_highmem;
		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