Re: [linux-pm] [PATCH] hibernation should work ok with memoryhotplug

From: Dave Hansen
Date: Tue Nov 04 2008 - 12:01:58 EST


On Tue, 2008-11-04 at 17:34 +0100, Rafael J. Wysocki wrote:
> Now, I need to do one more thing, which is to check how much memory has to be
> freed before creating the image. For this purpose I need to lock memory
> hotplug temporarily, count pages to free and unlock it. What interface should
> I use for this purpose?
>
> [I'll also need to lock memory hotplug temporarily during resume.]

We currently don't have any big switch to disable memory hotplug, like
lock_memory_hotplug() or something. :)

If you are simply scanning and counting pages, I think the best thing to
use would be the zone_span_seq*() seqlock stuff. Do your count inside
the seqlock's while loop. That covers detecting a zone changing while
it is being scanned.

The other case to detect is when a new zone gets added. These are
really rare. Rare enough that we actually use a stop_machine() call in
build_all_zonelists() to do it. All you would have to do is detect when
one of these calls gets made. I think that's a good application for a
new seq_lock.

I've attached an utterly untested patch that should do the trick.
Yasunori and KAME should probably take a look at it since the node
addition code is theirs.

-- Dave


---

linux-2.6.git-dave/mm/page_alloc.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

diff -puN mm/page_alloc.c~zone-list-seqlock mm/page_alloc.c
--- linux-2.6.git/mm/page_alloc.c~zone-list-seqlock 2008-11-04 08:53:38.000000000 -0800
+++ linux-2.6.git-dave/mm/page_alloc.c 2008-11-04 08:57:04.000000000 -0800
@@ -2378,17 +2378,43 @@ static void build_zonelist_cache(pg_data

#endif /* CONFIG_NUMA */

+/*
+ * This provides a way for other parts of the
+ * system to detect when the list of zones
+ * might have changed underneath them.
+ *
+ * Use this if you are doing a for_each_zone()
+ * or for_each_node() and really, really care
+ * if you miss some memory.
+ */
+static seqlock_t zonelist_seqlock = SEQLOCK_UNLOCKED;
+
+/*
+ * We could #ifdef these under MEMORY_HOTPLUG, but they
+ * are tiny.
+ */
+unsigned zonelist_seqbegin(void)
+{
+ return read_seqbegin(&zonelist_seqlock);
+}
+int zonelist_seqretry(void)
+{
+ return read_seqretry(&zonelist_seqlock, iv);
+}
+
/* return values int ....just for stop_machine() */
static int __build_all_zonelists(void *dummy)
{
int nid;

+ write_seqlock(&zonelist_seqlock);
for_each_online_node(nid) {
pg_data_t *pgdat = NODE_DATA(nid);

build_zonelists(pgdat);
build_zonelist_cache(pgdat);
}
+ write_sequnlock(&zonelist_seqlock);
return 0;
}

_