linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [Suspend2][ 00/20] Prepare image
@ 2006-06-26 22:34 Nigel Cunningham
  2006-06-26 22:34 ` [Suspend2][ 01/20] [Suspend2] Prepare_image.c header Nigel Cunningham
                   ` (19 more replies)
  0 siblings, 20 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:34 UTC (permalink / raw)
  To: linux-kernel


Routines for calculating the contents and metadata of an image, prior
to actually beginning to write it.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [Suspend2][ 01/20] [Suspend2] Prepare_image.c header.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
@ 2006-06-26 22:34 ` Nigel Cunningham
  2006-06-26 22:34 ` [Suspend2][ 02/20] [Suspend2] Get number of pcp pages Nigel Cunningham
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:34 UTC (permalink / raw)
  To: linux-kernel

Add header for prepare_image.c, containing functions that are used in
preparing an image (ie getting processes frozen, calculating the contents
and vital statistics of the image, getting the writer to allocate storage,
freeing memory if needs-be and allocating extra memory if required. Whew!)

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |   42 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 42 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
new file mode 100644
index 0000000..9e13418
--- /dev/null
+++ b/kernel/power/prepare_image.c
@@ -0,0 +1,42 @@
+/*
+ * kernel/power/prepare_image.c
+ *
+ * Copyright (C) 2003-2006 Nigel Cunningham <nigel@suspend.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ * We need to eat memory until we can:
+ * 1. Perform the save without changing anything (RAM_NEEDED < max_pfn)
+ * 2. Fit it all in available space (suspend_active_writer->available_space() >=
+ *    storage_needed())
+ * 3. Reload the pagedir and pageset1 to places that don't collide with their
+ *    final destinations, not knowing to what extent the resumed kernel will
+ *    overlap with the one loaded at boot time. I think the resumed kernel
+ *    should overlap completely, but I don't want to rely on this as it is 
+ *    an unproven assumption. We therefore assume there will be no overlap at
+ *    all (worse case).
+ * 4. Meet the user's requested limit (if any) on the size of the image.
+ *    The limit is in MB, so pages/256 (assuming 4K pages).
+ *
+ */
+
+#include <linux/highmem.h>
+#include <linux/freezer.h>
+#include <linux/hardirq.h>
+
+#include "suspend2.h"
+#include "pageflags.h"
+#include "modules.h"
+#include "suspend2_common.h"
+#include "io.h"
+#include "ui.h"
+#include "extent.h"
+#include "prepare_image.h"
+#include "block_io.h"
+
+static int are_frozen = 0, num_nosave = 0;
+static long header_space_allocated = 0;
+static long storage_allocated = 0;
+static long storage_available = 0;
+long extra_pd1_pages_allowance = MIN_EXTRA_PAGES_ALLOWANCE;
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 02/20] [Suspend2] Get number of pcp pages.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
  2006-06-26 22:34 ` [Suspend2][ 01/20] [Suspend2] Prepare_image.c header Nigel Cunningham
@ 2006-06-26 22:34 ` Nigel Cunningham
  2006-06-26 22:34 ` [Suspend2][ 03/20] [Suspend2] Get the real number of free pages (incl. pcp) Nigel Cunningham
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:34 UTC (permalink / raw)
  To: linux-kernel

Return the number of pages currently in the pcp lists.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |   33 +++++++++++++++++++++++++++++++++
 1 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index 9e13418..9f6e96d 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -40,3 +40,36 @@ static long storage_allocated = 0;
 static long storage_available = 0;
 long extra_pd1_pages_allowance = MIN_EXTRA_PAGES_ALLOWANCE;
 
+/*
+ * num_pcp_pages: Count pcp pages.
+ */
+static long num_pcp_pages(void)
+{
+	struct zone *zone;
+	long result = 0, i = 0;
+
+	/* PCP lists */
+	for_each_zone(zone) {
+		struct per_cpu_pageset *pset;
+		int cpu;
+		
+		if (!zone->present_pages)
+			continue;
+		
+		for (cpu = 0; cpu < NR_CPUS; cpu++) {
+			if (!cpu_possible(cpu))
+				continue;
+
+			pset = zone_pcp(zone, cpu);
+
+			for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
+				struct per_cpu_pages *pcp;
+
+				pcp = &(pset->pcp[i]);
+				result += pcp->count;
+			}
+		}
+	}
+	return result;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 03/20] [Suspend2] Get the real number of free pages (incl. pcp).
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
  2006-06-26 22:34 ` [Suspend2][ 01/20] [Suspend2] Prepare_image.c header Nigel Cunningham
  2006-06-26 22:34 ` [Suspend2][ 02/20] [Suspend2] Get number of pcp pages Nigel Cunningham
@ 2006-06-26 22:34 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 04/20] [Suspend2] Calculate pagedir1 growth allowance Nigel Cunningham
                   ` (16 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:34 UTC (permalink / raw)
  To: linux-kernel

Return the total number of free pages, including pcp pages.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index 9f6e96d..cb1a3da 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -73,3 +73,11 @@ static long num_pcp_pages(void)
 	return result;
 }
 
+/*
+ * Number of free pages, including pcp pages.
+ */
+long real_nr_free_pages(void)
+{
+	return nr_free_pages() + num_pcp_pages();
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 04/20] [Suspend2] Calculate pagedir1 growth allowance.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (2 preceding siblings ...)
  2006-06-26 22:34 ` [Suspend2][ 03/20] [Suspend2] Get the real number of free pages (incl. pcp) Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 05/20] [Suspend2] Get the amount of storage needed for the image proper Nigel Cunningham
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

While writing the LRU, and (more importantly) as a result of suspending the
drivers, the amount of memory needed for the atomic copy may increase
significantly. This amount is always predictable - LRU I/O will only ever
get a few more slab pages allocated, and drivers suspend and resume will
allocate a fixed number. The problem is that most drivers use virtually
nothing, so that the default allowance of 100 pages is ample. NVidia
drivers especially, however, allocate thousands of pages in some
configurations, so we need a way for the user to be able to tune or
autotune this value.

This routine provides a method for autotuning. If the allowance is set to
zero, this routine will be invoked, determining how much extra memory will
be allocated by the drivers when the real call is made later. We can then
take that, plus our normal 100 page allowance, as the value to use.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |   26 ++++++++++++++++++++++++++
 1 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index cb1a3da..271f904 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -81,3 +81,29 @@ long real_nr_free_pages(void)
 	return nr_free_pages() + num_pcp_pages();
 }
 
+/*
+ * Discover how much extra memory will be required by the drivers
+ * when they're asked to suspend. We can then ensure that amount
+ * of memory is available when we really want it.
+ */
+static void get_extra_pd1_allowance(void)
+{
+	int orig_num_free = real_nr_free_pages(), final;
+	
+	suspend_prepare_status(CLEAR_BAR, "Finding allowance for drivers.");
+	device_suspend(PMSG_FREEZE);
+	local_irq_disable(); /* irqs might have been re-enabled on us */
+	device_power_down(PMSG_FREEZE);
+	
+	final = real_nr_free_pages();
+
+	device_power_up();
+	local_irq_enable();
+
+	device_resume();
+
+	extra_pd1_pages_allowance = max(
+		orig_num_free - final + MIN_EXTRA_PAGES_ALLOWANCE,
+		MIN_EXTRA_PAGES_ALLOWANCE);
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 05/20] [Suspend2] Get the amount of storage needed for the image proper.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (3 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 04/20] [Suspend2] Calculate pagedir1 growth allowance Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 06/20] [Suspend2] Calculate header storage needed Nigel Cunningham
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Calculate the amount of storage required for the image proper, possibly
taking into account the expected compression ratio and possibly also
ignoring the extra pagedir1 allowance.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index 271f904..9f1eb74 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -107,3 +107,16 @@ static void get_extra_pd1_allowance(void
 		MIN_EXTRA_PAGES_ALLOWANCE);
 }
 
+/*
+ * Amount of storage needed, possibly taking into account the
+ * expected compression ratio and possibly also ignoring our
+ * allowance for extra pages.
+ */
+static long main_storage_needed(int use_ecr,
+		int ignore_extra_pd1_allow)
+{
+	return ((pagedir1.pageset_size + pagedir2.pageset_size +
+	  (ignore_extra_pd1_allow ? 0 : extra_pd1_pages_allowance)) *
+	 (use_ecr ? suspend_expected_compression_ratio() : 100) / 100);
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 06/20] [Suspend2] Calculate header storage needed.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (4 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 05/20] [Suspend2] Get the amount of storage needed for the image proper Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 07/20] [Suspend2] Display image vital statistics Nigel Cunningham
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Calculate the total amount of storage needed (in pages) for the image header.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index 9f1eb74..5070735 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -120,3 +120,16 @@ static long main_storage_needed(int use_
 	 (use_ecr ? suspend_expected_compression_ratio() : 100) / 100);
 }
 
+/*
+ * Storage needed for the image header, in bytes until the return.
+ */
+static int header_storage_needed(void)
+{
+	unsigned long bytes =
+		sizeof(struct suspend_header) +
+	 	(int) suspend_header_storage_for_modules() +
+		suspend_pageflags_space_needed();
+
+	return ((int) ((bytes + (int) PAGE_SIZE - 1) >> PAGE_SHIFT));
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 07/20] [Suspend2] Display image vital statistics.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (5 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 06/20] [Suspend2] Calculate header storage needed Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 08/20] [Suspend2] Generate free page bitmap Nigel Cunningham
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Display the vital statistics of the image.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |   36 ++++++++++++++++++++++++++++++++++++
 1 files changed, 36 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index 5070735..e54865a 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -133,3 +133,39 @@ static int header_storage_needed(void)
 	return ((int) ((bytes + (int) PAGE_SIZE - 1) >> PAGE_SHIFT));
 }
 
+static void display_stats(int always, int sub_extra_pd1_allow)
+{ 
+	char buffer[255];
+	snprintf(buffer, 254, 
+		"Free:%d(%d). Sets:%ld(%ld),%ld(%ld). Header:%d. Nosave:%d-%d=%d. Storage:%lu/%lu(%lu). Needed:%ld|%ld|%ld.\n", 
+		
+		/* Free */
+		nr_free_pages(),
+		nr_free_pages() - nr_free_highpages(),
+		
+		/* Sets */
+		pagedir1.pageset_size, pageset1_sizelow,
+		pagedir2.pageset_size, pageset2_sizelow,
+
+		/* Header */
+		header_storage_needed(),
+
+		/* Nosave */
+		num_nosave, extra_pagedir_pages_allocated,
+		num_nosave - extra_pagedir_pages_allocated,
+
+		/* Storage - converted to pages for comparison */
+		storage_allocated,
+		storage_needed(1, sub_extra_pd1_allow),
+		storage_available,
+
+		/* Needed */
+		ram_to_suspend() - nr_free_pages() - nr_free_highpages(),
+		storage_needed(1, sub_extra_pd1_allow) - storage_available, 
+		(image_size_limit > 0) ? (storage_needed(1, sub_extra_pd1_allow) - (image_size_limit << 8)) : 0);
+	if (always)
+		printk(buffer);
+	else
+		suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_MEDIUM, 1, buffer);
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 08/20] [Suspend2] Generate free page bitmap.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (6 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 07/20] [Suspend2] Display image vital statistics Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 09/20] [Suspend2] Get size of a free region Nigel Cunningham
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Generate a bitmap of pages that are free (including in pcp lists).

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |   53 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 53 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index e54865a..bf38334 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -169,3 +169,56 @@ static void display_stats(int always, in
 		suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_MEDIUM, 1, buffer);
 }
 
+/* generate_free_page_map
+ *
+ * Description:	This routine generates a bitmap of free pages from the
+ * 		lists used by the memory manager. We then use the bitmap
+ * 		to quickly calculate which pages to save and in which
+ * 		pagesets.
+ */
+static void generate_free_page_map(void) 
+{
+	int i, order, loop, cpu;
+	struct page *page;
+	unsigned long flags;
+	struct zone *zone;
+	struct per_cpu_pageset *pset;
+
+	for_each_zone(zone) {
+		if (!zone->present_pages)
+			continue;
+		for(i=0; i < zone->spanned_pages; i++)
+			SetPageInUse(pfn_to_page(zone->zone_start_pfn + i));
+	}
+	
+	for_each_zone(zone) {
+		if (!zone->present_pages)
+			continue;
+		spin_lock_irqsave(&zone->lock, flags);
+		for (order = MAX_ORDER - 1; order >= 0; --order) {
+			list_for_each_entry(page, &zone->free_area[order].free_list, lru)
+				for(loop=0; loop < (1 << order); loop++)
+					ClearPageInUse(page+loop);
+		}
+
+		
+		for (cpu = 0; cpu < NR_CPUS; cpu++) {
+			if (!cpu_possible(cpu))
+				continue;
+
+			pset = zone_pcp(zone, cpu);
+
+			for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
+				struct per_cpu_pages *pcp;
+				struct page *page;
+
+				pcp = &pset->pcp[i];
+				list_for_each_entry(page, &pcp->list, lru)
+					ClearPageInUse(page);
+			}
+		}
+		
+		spin_unlock_irqrestore(&zone->lock, flags);
+	}
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 09/20] [Suspend2] Get size of a free region.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (7 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 08/20] [Suspend2] Generate free page bitmap Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 10/20] [Suspend2] Count pages in image parts Nigel Cunningham
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Get the size of a range of free pages beginning at the given page, and
finishing at the end of the zone in which the page is found if not before.
The page given may not itself be free, in which case the return value will
be zero.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index bf38334..0030661 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -222,3 +222,21 @@ static void generate_free_page_map(void)
 	}
 }
 
+/* size_of_free_region
+ * 
+ * Description:	Return the number of pages that are free, beginning with and 
+ * 		including this one.
+ */
+static int size_of_free_region(struct page *page)
+{
+	struct zone *zone = page_zone(page);
+	struct page *posn = page, *last_in_zone =
+		pfn_to_page(zone->zone_start_pfn) + zone->spanned_pages - 1;
+
+	while (posn < last_in_zone && !PageInUse(posn)) {
+		BUG_ON(PagePageset2(posn));
+		posn++;
+	}
+	return (posn - page);
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 10/20] [Suspend2] Count pages in image parts.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (8 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 09/20] [Suspend2] Get size of a free region Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 11/20] [Suspend2] Amount of memory still to be freed Nigel Cunningham
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Iterate over zones and pages, counting the number of pages of each type and
populating the pageset1 and pageset1_copy bitmaps (the pages that will be
atomically copied, and the destination pages for the copies).

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |  103 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 103 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index 0030661..14ab1a4 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -240,3 +240,106 @@ static int size_of_free_region(struct pa
 	return (posn - page);
 }
 
+static struct page *rotext_start, *rotext_end;
+static struct page *rodata_start, *rodata_end;
+static struct page *nosave_start, *nosave_end;
+
+static __init int page_nosave_init(void)
+{
+	rodata_start = rodata_start_page();
+	rodata_end = rodata_end_page();
+
+	rotext_start = rotext_start_page();
+	rotext_end = rotext_end_page();
+	
+	nosave_start = nosave_start_page();
+	nosave_end = nosave_end_page();
+
+	return 0;
+}
+
+subsys_initcall(page_nosave_init);
+
+/* count_data_pages
+ *
+ * This routine generates our lists of pages to be stored in each
+ * pageset. Since we store the data using extents, and adding new
+ * extents might allocate a new extent page, this routine may well
+ * be called more than once.
+ */
+static struct pageset_sizes_result count_data_pages(void)
+{
+	int num_free = 0;
+	unsigned long loop;
+	int use_pagedir2;
+	struct pageset_sizes_result result;
+	struct zone *zone;
+
+	result.size1 = 0;
+	result.size1low = 0;
+	result.size2 = 0;
+	result.size2low = 0;
+
+	num_nosave = 0;
+
+	clear_dyn_pageflags(pageset1_map);
+
+	generate_free_page_map();
+
+	if (test_result_state(SUSPEND_ABORTED))
+		return result;
+
+	/*
+	 * Pages not to be saved are marked Nosave irrespective of being reserved
+	 */
+	for_each_zone(zone) {
+		for (loop = 0; loop < zone->spanned_pages; loop++) {
+			unsigned long pfn = zone->zone_start_pfn + loop;
+			struct page *page;
+			int chunk_size;
+
+			if (!pfn_valid(pfn))
+				continue;
+
+			page = pfn_to_page(pfn);
+			chunk_size = size_of_free_region(page);
+
+			if (PageNosave(page) ||
+			    (page >= rodata_start && page < rodata_end) ||
+			    (PageReserved(page) &&
+			     ((page >= nosave_start && page < nosave_end) ||
+			      is_highmem(zone)))) {
+				num_nosave++;
+				continue;
+			}
+
+			if (chunk_size) {
+				num_free += chunk_size;
+				loop += chunk_size - 1;
+				continue;
+			}
+
+			use_pagedir2 = PagePageset2(page);
+
+			if (use_pagedir2) {
+				result.size2++;
+				if (!PageHighMem(page)) {
+					result.size2low++;
+					SetPagePageset1Copy(page);
+				}
+			} else {
+				result.size1++;
+				SetPagePageset1(page);
+				if (!PageHighMem(page))
+					result.size1low++;
+			}
+		}
+	}
+
+	suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_MEDIUM, 0,
+		"Count data pages: Set1 (%d) + Set2 (%d) + Nosave (%d) + NumFree (%d) = %d.\n",
+		result.size1, result.size2, num_nosave, num_free,
+		result.size1 + result.size2 + num_nosave + num_free);
+	return result;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 11/20] [Suspend2] Amount of memory still to be freed.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (9 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 10/20] [Suspend2] Count pages in image parts Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 12/20] [Suspend2] Recalculate image contents Nigel Cunningham
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Calculate the amount of memory that needs to be freed to meet hard
constraints such as available storage and possibly also the soft
user-defined image size limit.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |   19 +++++++++++++++++++
 1 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index 14ab1a4..c85ce6b 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -343,3 +343,22 @@ static struct pageset_sizes_result count
 	return result;
 }
 
+/* amount_needed
+ *
+ * Calculates the amount by which the image size needs to be reduced to meet
+ * our constraints.
+ */
+static int amount_needed(int use_image_size_limit)
+{
+
+	int max1 = max( (int) (ram_to_suspend() - real_nr_free_pages() - 
+			  nr_free_highpages()),
+			((int) (storage_needed(1, 0) -  
+			  storage_available)));
+	if (use_image_size_limit)
+		return max( max1,
+			    (image_size_limit > 0) ? 
+			    ((int) (storage_needed(1, 0) - (image_size_limit << 8))) : 0);
+	return max1;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 12/20] [Suspend2] Recalculate image contents.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (10 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 11/20] [Suspend2] Amount of memory still to be freed Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 13/20] [Suspend2] Try to refreeze processes Nigel Cunningham
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Calculate anew which pages should be saved, and which pageset they should
belong to.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |   32 ++++++++++++++++++++++++++++++++
 1 files changed, 32 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index c85ce6b..6b3f2c9 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -362,3 +362,35 @@ static int amount_needed(int use_image_s
 	return max1;
 }
 
+/* suspend_recalculate_image_contents
+ *
+ * Eaten is the number of pages which have been eaten.
+ * Pagedirincluded is the number of pages which have been allocated for the pagedir.
+ */
+void suspend_recalculate_image_contents(int atomic_copy) 
+{
+	struct pageset_sizes_result result;
+
+	clear_dyn_pageflags(pageset1_map);
+	if (!atomic_copy) {
+		int pfn;
+		BITMAP_FOR_EACH_SET(pageset2_map, pfn)
+			ClearPagePageset1Copy(pfn_to_page(pfn));
+		/* Need to call this before getting pageset1_size! */
+		suspend_mark_pages_for_pageset2();
+	}
+	BUG_ON(in_atomic() && !irqs_disabled());
+	result = count_data_pages();
+	pageset1_sizelow = result.size1low;
+	pageset2_sizelow = result.size2low;
+	pagedir1.lastpageset_size = pagedir1.pageset_size = result.size1;
+	pagedir2.lastpageset_size = pagedir2.pageset_size = result.size2;
+
+	if (!atomic_copy) {
+		storage_available = suspend_active_writer->storage_available();
+		display_stats(1, 0);
+	}
+	BUG_ON(in_atomic() && !irqs_disabled());
+	return;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 13/20] [Suspend2] Try to refreeze processes.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (11 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 12/20] [Suspend2] Recalculate image contents Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 14/20] [Suspend2] Update the image Nigel Cunningham
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Try to refreeze processes after thawing kernel threads to eat memory. This
shouldn't fail, but if it does, we ensure it's handled nicely.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index 6b3f2c9..4e012a7 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -394,3 +394,11 @@ void suspend_recalculate_image_contents(
 	return;
 }
 
+static void try_freeze_processes(void)
+{
+	if (freeze_processes()) {
+		set_result_state(SUSPEND_FREEZING_FAILED);
+		set_result_state(SUSPEND_ABORTED);
+	}
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 14/20] [Suspend2] Update the image.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (12 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 13/20] [Suspend2] Try to refreeze processes Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 15/20] [Suspend2] Attempt to freeze processes Nigel Cunningham
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Recalculate what is needed in terms of storage and memory, and seek to
fulfil those allocations. The return value indicates whether all of the
prerequisites for moving on to writing the image have been met.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |   89 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 89 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index 4e012a7..a23722d 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -402,3 +402,92 @@ static void try_freeze_processes(void)
 	}
 }
 
+/* update_image
+ *
+ * Allocate [more] memory and storage for the image.
+ */
+static int update_image(void) 
+{ 
+	int result2, param_used;
+
+	suspend_recalculate_image_contents(0);
+
+	/* Include allowance for growth in pagedir1 while writing pagedir 2 */
+	if (suspend_allocate_extra_pagedir_memory(&pagedir1,
+		pagedir1.pageset_size + extra_pd1_pages_allowance,
+				pageset2_sizelow)) {
+		suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
+			"Still need to get more pages for pagedir 1.\n");
+		return 1;
+	}
+
+	thaw_processes(FREEZER_KERNEL_THREADS);
+
+	param_used = main_storage_needed(1, 0);
+	if ((result2 = suspend_active_writer->allocate_storage(param_used))) {
+		suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
+			"Allocate storage returned %d. Still need to get more"
+			" storage space for the image proper.\n",
+			result2);
+		storage_allocated = suspend_active_writer->storage_allocated();
+		try_freeze_processes();
+		return 1;
+	}
+
+	/* 
+	 * Allocate remaining storage space, if possible, up to the
+	 * maximum we know we'll need. It's okay to allocate the
+	 * maximum if the writer is the swapwriter, but
+	 * we don't want to grab all available space on an NFS share.
+	 * We therefore ignore the expected compression ratio here,
+	 * thereby trying to allocate the maximum image size we could
+	 * need (assuming compression doesn't expand the image), but
+	 * don't complain if we can't get the full amount we're after.
+	 */
+
+	suspend_active_writer->allocate_storage(
+		min(storage_available, main_storage_needed(0, 1)));
+
+	storage_allocated = suspend_active_writer->storage_allocated();
+
+	/* Allocate the header storage after allocating main storage
+	 * so that the overhead for metadata doesn't change the amount
+	 * of storage needed for the header itself.
+	 */
+
+	param_used = header_storage_needed();
+
+	result2 = suspend_active_writer->allocate_header_space(param_used);
+
+	try_freeze_processes();
+
+	if (result2) {
+		suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
+			"Still need to get more storage space for header.\n");
+		return 1;
+	}
+
+	header_space_allocated = param_used;
+
+	suspend_recalculate_image_contents(0);
+
+	suspend_message(SUSPEND_EAT_MEMORY, SUSPEND_LOW, 1,
+		"Amount still needed (%d) > 0:%d. Header: %d < %d: %d,"
+		" Storage allocd: %d < %d + %d: %d.\n",
+			amount_needed(0),
+			(amount_needed(0) > 0),
+			header_space_allocated, header_storage_needed(),
+			header_space_allocated < header_storage_needed(),
+		 	storage_allocated,
+			header_storage_needed(), main_storage_needed(1, 1),
+			storage_allocated <
+			(header_storage_needed() + main_storage_needed(1, 1)));
+
+	suspend_cond_pause(0, NULL);
+
+	return ((amount_needed(0) > 0) ||
+		header_space_allocated < header_storage_needed() ||
+		 storage_allocated < 
+		 (header_storage_needed() + main_storage_needed(1, 1)));
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 15/20] [Suspend2] Attempt to freeze processes.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (13 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 14/20] [Suspend2] Update the image Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-27 13:45   ` Pavel Machek
  2006-06-26 22:35 ` [Suspend2][ 16/20] [Suspend2] Calculate storage needed for an image Nigel Cunningham
                   ` (4 subsequent siblings)
  19 siblings, 1 reply; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Call the freezer code to get processes frozen, and abort suspending if that
fails. May be called multiple times as we thaw kernel space (only) if we
need to free memory to meet constraints.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index a23722d..12d715a 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -491,3 +491,26 @@ static int update_image(void) 
 		 (header_storage_needed() + main_storage_needed(1, 1)));
 }
 
+/* attempt_to_freeze
+ * 
+ * Try to freeze processes.
+ */
+
+static int attempt_to_freeze(void)
+{
+	int result;
+	
+	/* Stop processes before checking again */
+	thaw_processes(FREEZER_ALL_THREADS);
+	suspend_prepare_status(CLEAR_BAR, "Freezing processes");
+	result = freeze_processes();
+
+	if (result) {
+		set_result_state(SUSPEND_ABORTED);
+		set_result_state(SUSPEND_FREEZING_FAILED);
+	} else
+		are_frozen = 1;
+
+	return result;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 16/20] [Suspend2] Calculate storage needed for an image.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (14 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 15/20] [Suspend2] Attempt to freeze processes Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 17/20] [Suspend2] Calculate the amount of free memory needed Nigel Cunningham
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Calculate the storage (in pages) needed for an image, possibly ignoring the
expected compression ratio and/or allowance for extra pagedir1 pages.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index 12d715a..604089f 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -514,3 +514,9 @@ static int attempt_to_freeze(void)
 	return result;
 }
 
+long storage_needed(int use_ecr, int ignore_extra_pd1_allow)
+{
+	return 	(main_storage_needed(use_ecr, ignore_extra_pd1_allow)
+		       + header_storage_needed());
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 17/20] [Suspend2] Calculate the amount of free memory needed.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (15 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 16/20] [Suspend2] Calculate storage needed for an image Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 18/20] [Suspend2] Free up memory if necessary Nigel Cunningham
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Calculate the minimum amount of free ram before we will consider ourselves
to have enough to cover all expected needs. We can have the VM freeing
memory for us - that would create an inconsistent image.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index 604089f..054d0d4 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -520,3 +520,11 @@ long storage_needed(int use_ecr, int ign
 		       + header_storage_needed());
 }
 
+long ram_to_suspend(void)
+{
+	return (1 + 
+		max_t(long, (pagedir1.pageset_size + extra_pd1_pages_allowance - 
+			pageset2_sizelow - extra_pagedir_pages_allocated) / 2, 0) +
+		MIN_FREE_RAM + suspend_memory_for_modules());
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 18/20] [Suspend2] Free up memory if necessary.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (16 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 17/20] [Suspend2] Calculate the amount of free memory needed Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 19/20] [Suspend2] Prepare an image Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 20/20] [Suspend2] Prepare image header file Nigel Cunningham
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Seek to ensure memory constraints are met. If we need to free memory, we
thaw kernel space processes only, so that we won't deadlock with the swap
and filesystem code. We then call shrink_all_memory until the constraints
are met or we determine that we're not getting anywhere. We may also bail
immediately if the user has said they don't want any memory to be freed.
Kernel space is re-frozen before we exit.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |   94 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 94 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index 054d0d4..893ba72 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -528,3 +528,97 @@ long ram_to_suspend(void)
 		MIN_FREE_RAM + suspend_memory_for_modules());
 }
 
+/* eat_memory
+ *
+ * Try to free some memory, either to meet hard or soft constraints on the image
+ * characteristics.
+ * 
+ * Hard constraints:
+ * - Pageset1 must be < half of memory;
+ * - We must have enough memory free at resume time to have pageset1
+ *   be able to be loaded in pages that don't conflict with where it has to
+ *   be restored.
+ * Soft constraints
+ * - User specificied image size limit.
+ */
+static int eat_memory(void)
+{
+	int amount_wanted = 0;
+	int free_flags = 0, did_eat_memory = 0;
+	
+	/*
+	 * Note that if we have enough storage space and enough free memory, we may
+	 * exit without eating anything. We give up when the last 10 iterations ate
+	 * no extra pages because we're not going to get much more anyway, but
+	 * the few pages we get will take a lot of time.
+	 *
+	 * We freeze processes before beginning, and then unfreeze them if we
+	 * need to eat memory until we think we have enough. If our attempts
+	 * to freeze fail, we give up and abort.
+	 */
+
+	/* -- Stage 1: Freeze Processes -- */
+
+	
+	suspend_recalculate_image_contents(0);
+	amount_wanted = amount_needed(1);
+
+	switch (image_size_limit) {
+		case -1: /* Don't eat any memory */
+			if (amount_wanted > 0) {
+				set_result_state(SUSPEND_ABORTED);
+				set_result_state(SUSPEND_WOULD_EAT_MEMORY);
+			}
+			break;
+		case -2:  /* Free caches only */
+			free_flags = GFP_NOIO | __GFP_HIGHMEM;
+			amount_wanted = 1 << 31; /* As much cache as we can get */
+			break;
+		default:
+			free_flags = GFP_ATOMIC | __GFP_HIGHMEM;
+	}
+		
+	thaw_processes(FREEZER_KERNEL_THREADS);
+
+	/* -- Stage 2: Eat memory -- */
+
+	if (amount_wanted > 0 && !test_result_state(SUSPEND_ABORTED) &&
+			image_size_limit != -1) {
+
+		suspend_prepare_status(CLEAR_BAR, "Seeking to free %dMB of memory.", MB(amount_wanted));
+
+		shrink_all_memory(amount_wanted);
+		suspend_recalculate_image_contents(0);
+
+		did_eat_memory = 1;
+
+		suspend_cond_pause(0, NULL);
+	}
+
+	if (freeze_processes()) {
+		set_result_state(SUSPEND_FREEZING_FAILED);
+		set_result_state(SUSPEND_ABORTED);
+	}
+	
+	if (did_eat_memory) {
+		unsigned long orig_state = get_suspend_state();
+		/* Freeze_processes will call sys_sync too */
+		restore_suspend_state(orig_state);
+		suspend_recalculate_image_contents(0);
+	}
+
+	/* Blank out image size display */
+	suspend_update_status(100, 100, NULL);
+
+	if (!test_result_state(SUSPEND_ABORTED) &&
+	    (amount_needed(0) - extra_pd1_pages_allowance > 0)) {
+		printk("Unable to free sufficient memory to suspend. Still need %d pages.\n",
+			amount_needed(1));
+		display_stats(1, 1);
+		set_result_state(SUSPEND_ABORTED);
+		set_result_state(SUSPEND_UNABLE_TO_FREE_ENOUGH_MEMORY);
+	}
+
+	return 0;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 19/20] [Suspend2] Prepare an image.
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (17 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 18/20] [Suspend2] Free up memory if necessary Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  2006-06-26 22:35 ` [Suspend2][ 20/20] [Suspend2] Prepare image header file Nigel Cunningham
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Attempt to prepare everything for suspending. This section of the code does
most of the work - freezing processes, allocating storage, freeing memory
and so on. Once it is complete, we are either going to abort or jump
straight into writing the image.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.c |   63 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.c b/kernel/power/prepare_image.c
index 893ba72..10159e5 100644
--- a/kernel/power/prepare_image.c
+++ b/kernel/power/prepare_image.c
@@ -622,3 +622,66 @@ static int eat_memory(void)
 	return 0;
 }
 
+/* prepare_image
+ *
+ * Entry point to the whole image preparation section.
+ *
+ * We do four things:
+ * - Freeze processes;
+ * - Ensure image size constraints are met;
+ * - Complete all the preparation for saving the image,
+ *   including allocation of storage. The only memory
+ *   that should be needed when we're finished is that
+ *   for actually storing the image (and we know how
+ *   much is needed for that because the modules tell
+ *   us).
+ * - Make sure that all dirty buffers are written out.
+ */
+#define MAX_TRIES 4
+int suspend_prepare_image(void)
+{
+	int result = 1, tries = 0;
+
+	are_frozen = 0;
+
+	header_space_allocated = 0;
+
+	if (attempt_to_freeze())
+		return 1;
+
+	if (!extra_pd1_pages_allowance)
+		get_extra_pd1_allowance();
+
+	storage_available = suspend_active_writer->storage_available();
+
+	if (!storage_available) {
+		printk(KERN_ERR "You need some storage available to be able to suspend.\n");
+		set_result_state(SUSPEND_ABORTED);
+		set_result_state(SUSPEND_NOSTORAGE_AVAILABLE);
+		return 1;
+	}
+
+	do {
+		suspend_prepare_status(CLEAR_BAR, "Preparing Image.");
+	
+		if (eat_memory() || test_result_state(SUSPEND_ABORTED))
+			break;
+
+		result = update_image();
+
+		suspend_cond_pause(0, NULL);
+		
+		tries++;
+
+	} while ((result) && (tries < MAX_TRIES) && (!test_result_state(SUSPEND_ABORTED)) &&
+		(!test_result_state(SUSPEND_UNABLE_TO_FREE_ENOUGH_MEMORY)));
+
+	if (tries == MAX_TRIES) {
+		abort_suspend("Unable to successfully prepare the image.\n");
+		display_stats(1, 0);
+	}
+
+	suspend_cond_pause(1, "Image preparation complete.");
+
+	return result;
+}

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [Suspend2][ 20/20] [Suspend2] Prepare image header file
  2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
                   ` (18 preceding siblings ...)
  2006-06-26 22:35 ` [Suspend2][ 19/20] [Suspend2] Prepare an image Nigel Cunningham
@ 2006-06-26 22:35 ` Nigel Cunningham
  19 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel

Header file for image preparation routines and exported functions.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/prepare_image.h |   92 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 92 insertions(+), 0 deletions(-)

diff --git a/kernel/power/prepare_image.h b/kernel/power/prepare_image.h
new file mode 100644
index 0000000..912f570
--- /dev/null
+++ b/kernel/power/prepare_image.h
@@ -0,0 +1,92 @@
+/*
+ * kernel/power/prepare_image.h
+ *
+ * Copyright (C) 2003-2006 Nigel Cunningham <nigel@suspend.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+extern int suspend_prepare_image(void);
+extern void suspend_recalculate_image_contents(int storage_available);
+extern long real_nr_free_pages(void);
+extern long image_size_limit;
+extern long pageset1_sizelow, pageset2_sizelow;
+
+struct pageset_sizes_result {
+	long size1; /* Can't be unsigned - breaks MAX function */
+	long size1low;
+	long size2;
+	long size2low;
+};
+
+#ifdef CONFIG_CRYPTO
+extern int suspend_expected_compression_ratio(void);
+#else
+static inline int suspend_expected_compression_ratio(void)
+{
+	return 0;
+};
+#endif
+
+#define MIN_FREE_RAM 2000
+#define MIN_EXTRA_PAGES_ALLOWANCE 500
+
+extern long extra_pd1_pages_allowance;
+extern long storage_needed(int use_ecr, int ignore_extra_p1_allowance);
+extern long ram_to_suspend(void);
+
+#ifdef CONFIG_DEBUG_RODATA
+extern char __start_rodata, __end_rodata;
+
+static inline struct page* rodata_start_page(void)
+{
+	return virt_to_page(&__start_rodata);
+}
+
+static inline struct page* rodata_end_page(void)
+{
+	return virt_to_page(&__end_rodata);
+}
+
+#else
+static inline struct page* rodata_start_page(void)
+{
+	return NULL;
+}
+
+static inline struct page* rodata_end_page(void)
+{
+	return NULL;
+}
+#endif
+
+#ifdef CONFIG_PPC
+extern char _etext[];
+
+static inline struct page* rotext_start_page(void)
+{
+	return virt_to_page(PAGE_OFFSET);
+}
+#else
+extern char _text[], _etext[];
+static inline struct page* rotext_start_page(void)
+{
+	return virt_to_page(_text);
+}
+#endif
+
+static inline struct page* rotext_end_page(void)
+{
+	return virt_to_page(_etext);
+}
+
+static inline struct page* nosave_start_page(void)
+{
+	return virt_to_page(&__nosave_begin);
+}
+
+static inline struct page* nosave_end_page(void)
+{
+	return virt_to_page(&__nosave_end);
+}

--
Nigel Cunningham		nigel at suspend2 dot net

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [Suspend2][ 15/20] [Suspend2] Attempt to freeze processes.
  2006-06-26 22:35 ` [Suspend2][ 15/20] [Suspend2] Attempt to freeze processes Nigel Cunningham
@ 2006-06-27 13:45   ` Pavel Machek
  2006-06-27 23:38     ` Nigel Cunningham
  0 siblings, 1 reply; 25+ messages in thread
From: Pavel Machek @ 2006-06-27 13:45 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: linux-kernel

Hi!

> Call the freezer code to get processes frozen, and abort suspending if that
> fails. May be called multiple times as we thaw kernel space (only) if we
> need to free memory to meet constraints.

Current code seems to free memory without need to thaw/re-freeze
kernel threads. Have you found bugs in that, or is this unneccessary?

> +static int attempt_to_freeze(void)
> +{
> +	int result;
> +	
> +	/* Stop processes before checking again */
> +	thaw_processes(FREEZER_ALL_THREADS);
> +	suspend_prepare_status(CLEAR_BAR, "Freezing processes");
> +	result = freeze_processes();
> +
> +	if (result) {
> +		set_result_state(SUSPEND_ABORTED);
> +		set_result_state(SUSPEND_FREEZING_FAILED);
> +	} else
> +		are_frozen = 1;
> +
> +	return result;
> +}
> +


-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Suspend2][ 15/20] [Suspend2] Attempt to freeze processes.
  2006-06-27 13:45   ` Pavel Machek
@ 2006-06-27 23:38     ` Nigel Cunningham
  2006-06-28 18:59       ` Hugh Dickins
  0 siblings, 1 reply; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-27 23:38 UTC (permalink / raw)
  To: Pavel Machek; +Cc: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1169 bytes --]

Hi.

On Tuesday 27 June 2006 23:45, Pavel Machek wrote:
> Hi!
>
> > Call the freezer code to get processes frozen, and abort suspending if
> > that fails. May be called multiple times as we thaw kernel space (only)
> > if we need to free memory to meet constraints.
>
> Current code seems to free memory without need to thaw/re-freeze
> kernel threads. Have you found bugs in that, or is this unneccessary?

Did you read my other email? Try it with a swap file on a journalled 
filesystem, in a situation where freeing memory will force the swap file to 
be used.

Regards,

Nigel

> > +static int attempt_to_freeze(void)
> > +{
> > +	int result;
> > +
> > +	/* Stop processes before checking again */
> > +	thaw_processes(FREEZER_ALL_THREADS);
> > +	suspend_prepare_status(CLEAR_BAR, "Freezing processes");
> > +	result = freeze_processes();
> > +
> > +	if (result) {
> > +		set_result_state(SUSPEND_ABORTED);
> > +		set_result_state(SUSPEND_FREEZING_FAILED);
> > +	} else
> > +		are_frozen = 1;
> > +
> > +	return result;
> > +}
> > +

-- 
See http://www.suspend2.net for Howtos, FAQs, mailing
lists, wiki and bugzilla info.

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Suspend2][ 15/20] [Suspend2] Attempt to freeze processes.
  2006-06-27 23:38     ` Nigel Cunningham
@ 2006-06-28 18:59       ` Hugh Dickins
  2006-06-28 22:10         ` Nigel Cunningham
  0 siblings, 1 reply; 25+ messages in thread
From: Hugh Dickins @ 2006-06-28 18:59 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Pavel Machek, linux-kernel

On Wed, 28 Jun 2006, Nigel Cunningham wrote:
> On Tuesday 27 June 2006 23:45, Pavel Machek wrote:
> >
> > Current code seems to free memory without need to thaw/re-freeze
> > kernel threads. Have you found bugs in that, or is this unneccessary?
> 
> Did you read my other email? Try it with a swap file on a journalled 
> filesystem, in a situation where freeing memory will force the swap file to 
> be used.

Hi Nigel,

I may have missed your "other email" in the avalanche ;)

That particular example sounds dubious to me: it may well have been
a problem on 2.4, but are you sure that it's still a problem on 2.6?

Andrew very nicely rewrote the swapfile handling, to bmap the whole
file at swapon time (see setup_swap_extents), and thereafter the only
difference between using a swapfile and using a disk partition is that
the swapfile blocks may be fragmented into many extents where the disk
partition is contiguous.  Much more reliable.

I don't see how your "journalled filesystem" would affect it at all.

Hugh

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [Suspend2][ 15/20] [Suspend2] Attempt to freeze processes.
  2006-06-28 18:59       ` Hugh Dickins
@ 2006-06-28 22:10         ` Nigel Cunningham
  0 siblings, 0 replies; 25+ messages in thread
From: Nigel Cunningham @ 2006-06-28 22:10 UTC (permalink / raw)
  To: Hugh Dickins; +Cc: Pavel Machek, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1650 bytes --]

Hi Hugh.

On Thursday 29 June 2006 04:59, Hugh Dickins wrote:
> On Wed, 28 Jun 2006, Nigel Cunningham wrote:
> > On Tuesday 27 June 2006 23:45, Pavel Machek wrote:
> > > Current code seems to free memory without need to thaw/re-freeze
> > > kernel threads. Have you found bugs in that, or is this unneccessary?
> >
> > Did you read my other email? Try it with a swap file on a journalled
> > filesystem, in a situation where freeing memory will force the swap file
> > to be used.
>
> Hi Nigel,
>
> I may have missed your "other email" in the avalanche ;)

:)

> That particular example sounds dubious to me: it may well have been
> a problem on 2.4, but are you sure that it's still a problem on 2.6?

Yes, I am sure but I'll double check again. What I recall at the moment is a 
deadlock in actually writing the page.

> Andrew very nicely rewrote the swapfile handling, to bmap the whole
> file at swapon time (see setup_swap_extents), and thereafter the only
> difference between using a swapfile and using a disk partition is that
> the swapfile blocks may be fragmented into many extents where the disk
> partition is contiguous.  Much more reliable.
>
> I don't see how your "journalled filesystem" would affect it at all.

Ok. I'll reproduce it and post the trace. Of course it may be that my 
examination was too superficial and the cause is more subtle.

I'm not sure if I'll have time to do this during this week, but I'll leave 
your message marked Todo so I don't forget.

Thanks for the reply!

Nigel

-- 
See http://www.suspend2.net for Howtos, FAQs, mailing
lists, wiki and bugzilla info.

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2006-06-28 22:10 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-06-26 22:34 [Suspend2][ 00/20] Prepare image Nigel Cunningham
2006-06-26 22:34 ` [Suspend2][ 01/20] [Suspend2] Prepare_image.c header Nigel Cunningham
2006-06-26 22:34 ` [Suspend2][ 02/20] [Suspend2] Get number of pcp pages Nigel Cunningham
2006-06-26 22:34 ` [Suspend2][ 03/20] [Suspend2] Get the real number of free pages (incl. pcp) Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 04/20] [Suspend2] Calculate pagedir1 growth allowance Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 05/20] [Suspend2] Get the amount of storage needed for the image proper Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 06/20] [Suspend2] Calculate header storage needed Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 07/20] [Suspend2] Display image vital statistics Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 08/20] [Suspend2] Generate free page bitmap Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 09/20] [Suspend2] Get size of a free region Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 10/20] [Suspend2] Count pages in image parts Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 11/20] [Suspend2] Amount of memory still to be freed Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 12/20] [Suspend2] Recalculate image contents Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 13/20] [Suspend2] Try to refreeze processes Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 14/20] [Suspend2] Update the image Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 15/20] [Suspend2] Attempt to freeze processes Nigel Cunningham
2006-06-27 13:45   ` Pavel Machek
2006-06-27 23:38     ` Nigel Cunningham
2006-06-28 18:59       ` Hugh Dickins
2006-06-28 22:10         ` Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 16/20] [Suspend2] Calculate storage needed for an image Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 17/20] [Suspend2] Calculate the amount of free memory needed Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 18/20] [Suspend2] Free up memory if necessary Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 19/20] [Suspend2] Prepare an image Nigel Cunningham
2006-06-26 22:35 ` [Suspend2][ 20/20] [Suspend2] Prepare image header file Nigel Cunningham

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).