diff -ruNp 831-core-extents-old/kernel/power/suspend2_core/extent.c 831-core-extents-new/kernel/power/suspend2_core/extent.c
--- 831-core-extents-old/kernel/power/suspend2_core/extent.c	1970-01-01 10:00:00.000000000 +1000
+++ 831-core-extents-new/kernel/power/suspend2_core/extent.c	2004-12-24 12:02:32.000000000 +1100
@@ -0,0 +1,788 @@
+/* Suspend2 routines for manipulating extents.
+ *
+ * (C) 2003-2004 Nigel Cunningham <ncunningham@linuxmail.org>
+ *
+ * Distributed under GPLv2.
+ * 
+ * These encapsulate the manipulation of extents.
+ * They work like this:
+ *
+ * A lot of the data that suspend saves involves continguous extents of memory
+ * or storage. Let's say that we're storing data on disk in blocks 1-32768 and
+ * 49152-49848 of a swap partition. Rather than recording 1, 2, 3... in arrays
+ * pointing to the locations, we simply use:
+ *
+ * struct extent {
+ * 	unsigned long min;
+ * 	unsigned long max;
+ * 	struct extent * next;
+ * }
+ *
+ * We can then store 1-32768 and 49152-49848 in 2 struct extents, using 24 bytes
+ * instead of something like 133,860. This is of course inefficient where a extent
+ * covers only one or two values, but the benefits gained by the much larger
+ * extents more than outweight these instances.
+ *
+ * Whole pages are allocated to store extents, with unused structs being chained
+ * together and linked into an unused_extents list:
+ *
+ * struct extent * unused_extents; (just below).
+ *
+ * We can fit 341 extents in a 4096 byte page (extentpage), with 4 bytes left over.
+ * These four bytes, referred to as the ExtentPageLink, are used to link the pages
+ * together. The ExtentPageLink is a pointer to the next page, or'd with the index
+ * number of the page.
+ *
+ * ExtentPages are stored in the header of the suspend image. For portability
+ * between suspend time and resume time, we 'relativise' the contents of each page
+ * before writing them to disk. That is, each .next and each ExtentPageLink is
+ * changed to point not to an absolute location, but to the relative location in
+ * the list of pages. This makes all the information valid and usable (after it
+ * has been absolutised again, of course) regardless of where it is reloaded to
+ * at resume time.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/suspend.h>
+#include <linux/mm.h>
+
+#include "pageflags.h"
+#include "suspend.h"
+
+struct extent * unused_extents = NULL;
+int nr_unused_extents = 0;
+int max_extents_used = 0;
+int num_extent_pages = 0;
+static unsigned long extents_allocated = 0;
+struct extent * first_extent_page = NULL, * last_extent_page = NULL;
+
+static int get_extentpages_list(void);
+static void put_extentpages_list(void);
+
+/* Add_extent_pages
+ *
+ * Allocates and initialises new pages for storing extents.
+ * Returns 1 on failure to get a page.
+ * Otherwise adds the new pages to the unused_extents pool and returns 0.
+ * During resuming, it ensures the page added doesn't collide with memory that
+ * will be overwritten when copying the original kernel back.
+ */
+
+static int add_extent_pages(int number_requested)
+{
+	int i, j;
+	struct extent * extents;
+	void **eaten_memory = NULL, **this;
+
+	for (j = 0; j < number_requested; j++) {
+		if (test_suspend_state(SUSPEND_NOW_RESUMING)) {
+			struct page * pageaddr;
+			/* Make sure page doesn't collide when we're resuming */
+			while ((this = (void **) get_zeroed_page(GFP_ATOMIC))) {
+				pageaddr = virt_to_page(this);
+				if (!PageInUse(pageaddr))
+					break;
+				*this = eaten_memory;
+				eaten_memory = this;
+			}
+			// Free unwanted memory
+			while(eaten_memory) {
+				this = eaten_memory;
+				eaten_memory = *eaten_memory;
+				free_page((unsigned long) this);
+			}
+		} else
+			this = (void *) get_grabbed_pages(0);
+
+		if (!this)
+			return 1;
+
+		num_extent_pages++;
+		if (!first_extent_page)
+			first_extent_page = (struct extent *) this;
+		if (last_extent_page)
+			*EXTENTPAGELINK(last_extent_page) |= (unsigned long) this;
+		*EXTENTPAGELINK(this) = num_extent_pages;
+		last_extent_page = (struct extent *) this;
+		extents = (struct extent *) this;
+		for (i = 0; i < EXTENTS_PER_PAGE; i++)
+			(extents+i)->next = (extents+i+1);
+		(extents + i - 1)->next = unused_extents;
+		unused_extents = extents;
+		nr_unused_extents += i;
+	}
+
+	return get_extentpages_list();
+}
+
+
+/* 
+ * Free extents.
+ *
+ * Frees pages allocated by add_extent_pages()
+ *
+ * Checks that all extents allocated have been freed and emits a warning if this
+ * is not true.
+ */
+
+int free_extents(void)
+{
+	int i;
+	struct extent * this_extent_page = first_extent_page, 
+		* next_extent_page = NULL;
+
+	if (extents_allocated)
+		printk(" *** Warning: %ld extents still allocated when "
+				"free_extents() called.\n", extents_allocated);
+
+	for (i = 0; i < num_extent_pages; i++) {
+		next_extent_page = (struct extent *) 
+			(((unsigned long)
+			  (*EXTENTPAGELINK(this_extent_page))) & PAGE_MASK);
+		free_pages((unsigned long) this_extent_page, 0);
+		this_extent_page = next_extent_page;
+	}
+
+	nr_unused_extents = num_extent_pages = extents_allocated = 0;
+	unused_extents = last_extent_page = first_extent_page = NULL;
+
+	put_extentpages_list();
+
+	return 0;
+}
+
+/* get_extent
+ *
+ * Returns a free extent, having removed it from the unused list and having
+ * incremented the usage count. May imply allocating a new page and may
+ * therefore fail, returning NULL instead.
+ * 
+ * No locking. This is because we are only called from suspend, which is single
+ * threaded.
+ */
+
+static struct extent * get_extent(void)
+{
+	struct extent * result;
+	
+	if ((!unused_extents) && (add_extent_pages(1)))
+		return NULL;
+
+	result = unused_extents;
+	unused_extents = unused_extents->next;
+	nr_unused_extents--;
+	extents_allocated++;
+	if (extents_allocated > max_extents_used)
+		max_extents_used++;
+	result->minimum = result->maximum = 0;
+	result->next = NULL;
+	return result;
+}
+
+/*
+ * put_extent.
+ *
+ * Returns a extent to the pool of unused pages and decrements the usage count.
+ *
+ * Assumes unlinking is done by the caller.
+ */
+void put_extent(struct extent * extent)
+{
+	if (!extent) {
+		printk("Error! put_extent called with NULL extent.\n");
+		return;
+	}
+	extent->minimum = extent->maximum = 0;
+	extent->next = unused_extents;
+	unused_extents = extent;
+	extents_allocated--;
+	nr_unused_extents++;
+}
+
+/*
+ * put_extent_chain.
+ *
+ * Returns a whole chain of extents to the unused pool.
+ */
+void put_extent_chain(struct extentchain * chain)
+{
+	int count = 0;
+	struct extent * this;
+
+	if (chain->first) {
+		this = chain->first;
+		while (this) {
+			this->minimum = this->maximum = 0;
+			this=this->next;
+		}
+		chain->last->next = unused_extents;
+		unused_extents = chain->first;
+		count = chain->allocs - chain->frees;
+		extents_allocated -= count;
+		nr_unused_extents += count;
+
+		chain->first = NULL;
+		chain->last = NULL;
+		chain->size = 0;
+		chain->allocs = 0;
+		chain->frees = 0;
+		chain->timesusedoptimisation = 0;
+		chain->lastaccessed = NULL; /* Invalidate optimisation info */
+		chain->prevtolastaccessed = NULL;
+		chain->prevtoprev = NULL;
+	}
+}
+
+/* print_chain.
+ *
+ * Displays the contents of a chain.
+ *
+ * printmethod:
+ * 0: integer
+ * 1: hex
+ * 2: page number
+ */
+void print_chain(int debuglevel, struct extentchain * chain, int printmethod)
+{
+	struct extent * this = chain->first;
+	int count = 0, size = 0;
+	
+	if ((console_loglevel < debuglevel) || (!this) ||
+			(!TEST_DEBUG_STATE(SUSPEND_EXTENTS)))
+		return;
+
+	if (!chain->name)
+		suspend_message(SUSPEND_EXTENTS, debuglevel, 1, "Chain %p\n", chain);
+	else
+		suspend_message(SUSPEND_EXTENTS, debuglevel, 1, "%s\n", chain->name);
+	
+	while (this) {
+		/*
+		 * 'This' is printed separately so it is displayed if an oops
+		 * results.
+		 */
+		switch (printmethod) {
+			case 0:
+				suspend_message(SUSPEND_EXTENTS, debuglevel, 1, "(%p) ",
+					this);
+				suspend_message(SUSPEND_EXTENTS, debuglevel, 1, "%lx-%lx; ",
+					this->minimum, this->maximum);
+				break;
+			case 1:
+				suspend_message(SUSPEND_EXTENTS, debuglevel, 1, "(%p)",
+					this);
+				suspend_message(SUSPEND_EXTENTS, debuglevel, 1, "%lu-%lu; ",
+					this->minimum, this->maximum);
+				break;
+			case 2:
+				suspend_message(SUSPEND_EXTENTS, debuglevel, 1, "(%p)",
+					this);
+				suspend_message(SUSPEND_EXTENTS, debuglevel, 1, "%p-%p; ",
+					page_address(pfn_to_page(this->minimum)),
+					page_address(pfn_to_page(this->maximum)) +
+						PAGE_SIZE - 1);
+				break;
+		}
+		size+= this->maximum - this->minimum + 1;
+		this = this->next;
+		count++;
+		if (!(count%4))
+			suspend_message(SUSPEND_EXTENTS, debuglevel, 1, "\n");
+	}
+	
+	if ((count%4))
+		suspend_message(SUSPEND_EXTENTS, debuglevel, 1, "\n");
+
+	suspend_message(SUSPEND_EXTENTS, debuglevel, 1,"%d entries/%ld allocated. "
+			"Allocated %d and freed %d. Size %d.",
+			count, 
+			extents_allocated,
+			chain->allocs,
+			chain->frees,
+			size);
+	if (count != (chain->allocs - chain->frees)) {
+		chain->debug = 1;
+		check_shift_keys(1, "Discrepancy in chain.");
+	}
+	suspend_message(SUSPEND_EXTENTS, debuglevel, 1, "\n");
+}
+
+/*
+ * add_to_extent_chain.
+ *
+ * Takes a value to be stored and a pointer to a chain and adds the value to 
+ * the extent chain, merging with an existing extent or  adding a new entry as
+ * necessary. Extents  are stored in increasing order.
+ *
+ * Values should be consecutive, and so may need to be transformed first. (eg
+ * for pages, would want to call with page-mem_map).
+ *
+ * Important optimisation:
+ * We store in the chain info the location of the last extent accessed or added
+ * (and its previous). If the next value is outside this extent by one, we start
+ * from the previous entry instead of the start of the chain. In cases of heavy
+ * fragmentation, this saves a lot of time searching.
+ * 
+ * Returns:
+ * 0 if successful
+ * 1 if the value is already included.
+ * 2 if unable to allocate memory.
+ * 3 if fall out bottom (shouldn't happen).
+ */
+
+int add_to_extent_chain(struct extentchain * chain, unsigned long value)
+{
+	struct extent * this, * prev = NULL, * prevtoprev = NULL;
+	int usedoptimisation = 0;
+	
+	if (!chain->first) {	/* Empty */
+		chain->last = chain->first = get_extent();
+		if (!chain->first) {
+			printk("Error unable to allocate the first extent for "
+					"the chain.\n");
+			return 2;
+		}
+		chain->allocs++;
+		chain->first->maximum = value;
+		chain->first->minimum = value;
+		chain->size++;
+		return 0;
+	}
+	
+	this = chain->first;
+
+	if (chain->lastaccessed && chain->prevtolastaccessed &&
+		       chain->prevtoprev) {
+		if ((value + 1) == chain->lastaccessed->minimum) {
+			prev = chain->prevtoprev;
+			this = chain->prevtolastaccessed;
+			usedoptimisation = 1;
+		} else if (((value - 1) == chain->lastaccessed->maximum)) {
+			prev = chain->prevtolastaccessed;
+			this = chain->lastaccessed;
+			usedoptimisation = 1;
+		}
+	}
+
+	while (this) {
+		/* Need new entry prior to this? */
+		if ((value + 1) < this->minimum) {
+			struct extent * new = get_extent();
+			if (!new)
+				return 2;
+			chain->allocs++;
+			new->minimum = value;
+			new->maximum = value;
+			new->next = this;
+			/* Prior to start of chain? */
+			if (!prev)
+				chain->first = new;
+			else
+				prev->next = new;
+			if (!usedoptimisation) {
+				chain->prevtoprev = prevtoprev;
+				chain->prevtolastaccessed = prev;
+				chain->lastaccessed = new;
+			}
+			chain->size++;
+			return 0;
+		}
+
+		if ((this->minimum <= value) && (this->maximum >= value)) {
+			if (chain->name)
+				printk("%s:", chain->name);
+			else
+				printk("%p:", chain);
+				printk("Trying to add a value (%ld/0x%lx) already "
+				"included in chain.\n",
+				value, value);
+			print_chain(SUSPEND_ERROR, chain, 0);
+			check_shift_keys(1, NULL);
+			return 1;
+		}
+		if ((value + 1) == this->minimum) {
+			this->minimum = value;
+			if (!usedoptimisation) {
+				chain->prevtoprev = prevtoprev;
+				chain->prevtolastaccessed = prev;
+				chain->lastaccessed = this;
+			}
+			chain->size++;
+			return 0;
+		}
+		if ((value - 1) == this->maximum) {
+			if ((this->next) && 
+					(this->next->minimum == value + 1)) {
+				struct extent * oldnext = this->next;
+				this->maximum = this->next->maximum;
+				this->next = this->next->next;
+				if ((chain->last) == oldnext)
+					chain->last = this;
+				put_extent(oldnext);
+				/* Invalidate optimisation info */
+				chain->lastaccessed = NULL;	
+				chain->frees++;
+				if (!usedoptimisation) {
+					chain->prevtoprev = prevtoprev;
+					chain->prevtolastaccessed = prev;
+					chain->lastaccessed = this;
+				}
+				chain->size++;
+				return 0;
+			} 
+			this->maximum = value;
+			if (!usedoptimisation) {
+				chain->prevtoprev = prevtoprev;
+				chain->prevtolastaccessed = prev;
+				chain->lastaccessed = this;
+			}
+			chain->size++;
+			return 0;
+		}
+		if (!this->next) {
+			struct extent * new = get_extent();
+			if (!new) {
+				printk("Error unable to append a new extent to "
+						"the chain.\n");
+				return 2;
+			}
+			chain->allocs++;
+			new->minimum = value;
+			new->maximum = value;
+			new->next = NULL;
+			this->next = new;
+			chain->last = new;
+			if (!usedoptimisation) {
+				chain->prevtoprev = prev;
+				chain->prevtolastaccessed = this;
+				chain->lastaccessed = new;
+			}
+			chain->size++;
+			return 0;
+		}
+		prevtoprev = prev;
+		prev = this;
+		this = this->next;
+	}
+	printk("\nFell out the bottom of add_to_extent_chain. This shouldn't "
+			"happen!\n");
+	SET_RESULT_STATE(SUSPEND_ABORTED);
+	return 3;
+}
+
+/* append_extent
+ * Used where we know a extent is to be added to the end of the list
+ * and does not need merging with the current last extent.
+ * (count_data_pages only at the moment)
+ */
+
+int append_extent_to_extent_chain(struct extentchain * chain, 
+		unsigned long minimum, unsigned long maximum)
+{
+	struct extent * newextent = NULL;
+
+	newextent = get_extent();
+	if (!newextent) {
+		printk("Error unable to append a new extent to the chain.\n");
+		return 2;
+	}
+
+	chain->allocs++;
+	chain->size+= (maximum - minimum + 1);
+	newextent->minimum = minimum;
+	newextent->maximum = maximum;
+	newextent->next = NULL;
+
+	if (chain->last) {
+		chain->last->next = newextent;
+		chain->last = newextent;
+	} else 
+		chain->last = chain->first = newextent;
+
+	/* No need to reset optimisation info since added to end */
+	return 0;
+}
+
+int append_to_extent_chain(int chain, unsigned long min, unsigned long max)
+{
+	int result = 0;
+
+	switch (chain) {
+		case 0:
+			return 0;
+		case 1:
+			BUG();
+		case 2:
+			BUG();
+	}
+	return result;
+}
+
+/* -------------- Routines for relativising and absoluting extents -------------
+ *
+ * Prepare extentsets for save by translating addresses to relative indices.
+ */
+void relativise_extents(void)
+{
+	struct extent * this_extent_page = first_extent_page;
+	int i;
+	
+	while (this_extent_page) {
+		struct extent * this_extent = this_extent_page;
+		for (i = 0; i < EXTENTS_PER_PAGE; i++) {
+			if (this_extent->next) {
+				struct extent * orig = this_extent->next;
+				this_extent->next =
+					EXTENT_RELATIVE(this_extent->next);
+				suspend_message(SUSPEND_EXTENTS, SUSPEND_VERBOSE, 1,
+					"Relativised extent %d on this page is %p. Absolutised extent is %p.\n",
+					i, this_extent->next, orig);
+			}
+			this_extent++;
+		}
+		this_extent_page = (struct extent *)
+			((*EXTENTPAGELINK(this_extent_page)) & PAGE_MASK);
+	}
+}
+
+/* Convert ->next pointers for extents back to absolute values.
+ * The issue is finding out what page the absolute value is now at.
+ * If we use an array of values, we gain speed, but then we need to
+ * be able to allocate contiguous pages. Fortunately, this is done
+ * prior to loading pagesets, so we can just allocate the pages
+ * needed, set up our array and use it and then discard the data
+ * before we exit.
+ */
+
+void absolutise_extents()
+{
+	struct extent * this_extent_page = first_extent_page;
+	int i;
+	
+	while (this_extent_page) {
+		struct extent * this_extent = this_extent_page;
+		for (i = 0; i < EXTENTS_PER_PAGE; i++) {
+			if (this_extent->next) {
+				struct extent * orig = this_extent->next;
+				this_extent->next = 
+					EXTENT_ABSOLUTE(this_extent->next);
+				suspend_message(SUSPEND_EXTENTS, SUSPEND_VERBOSE, 1,
+					"Relativised extent %d on this page is %p. Absolutised extent is %p.\n",
+					i, orig, this_extent->next);
+			}
+			this_extent++;
+		}
+		this_extent_page = (struct extent *)
+			((*EXTENTPAGELINK(this_extent_page)) & PAGE_MASK);
+	}
+}
+
+void absolutise_chain(struct extentchain * chain)
+{
+	if (chain->first)
+		chain->first = EXTENT_ABSOLUTE(chain->first);
+	if (chain->last)
+		chain->last = EXTENT_ABSOLUTE(chain->last);
+	if (chain->lastaccessed)
+		chain->lastaccessed = EXTENT_ABSOLUTE(chain->lastaccessed);
+	if (chain->prevtolastaccessed)
+		chain->prevtolastaccessed =
+			EXTENT_ABSOLUTE(chain->prevtolastaccessed);
+	if (chain->prevtoprev)
+		chain->prevtoprev =
+			EXTENT_ABSOLUTE(chain->prevtoprev);
+}
+
+void relativise_chain(struct extentchain * chain)
+{
+	if (chain->first)
+		chain->first = EXTENT_RELATIVE(chain->first);
+	if (chain->last)
+		chain->last = EXTENT_RELATIVE(chain->last);
+	if (chain->lastaccessed)
+		chain->lastaccessed = EXTENT_RELATIVE(chain->lastaccessed);
+	if (chain->prevtolastaccessed)
+		chain->prevtolastaccessed =
+			EXTENT_RELATIVE(chain->prevtolastaccessed);
+	if (chain->prevtoprev)
+		chain->prevtoprev = EXTENT_RELATIVE(chain->prevtoprev);
+}
+
+/*
+ * Each page in the extentpages lists starts with a pointer to the next page
+ * containing the list. This lets us only use order zero allocations.
+ */
+#define POINTERS_PER_PAGE ((PAGE_SIZE / sizeof(void *)) - 1)
+static unsigned long * extent_pagelist = NULL;
+
+unsigned long * get_extentpages_list_entry(int index)
+{
+	int pagenum, offset, i;
+	unsigned long * current_list_page;
+
+	BUG_ON(index > num_extent_pages);
+
+	if ((!extent_pagelist) && (get_extentpages_list()))
+		return NULL;
+
+	current_list_page = extent_pagelist;
+
+	pagenum = index / POINTERS_PER_PAGE;
+	offset = index - (pagenum * POINTERS_PER_PAGE);
+
+	for (i = 0; i < pagenum; i++)
+		current_list_page = *((unsigned long **) current_list_page);
+
+	return (unsigned long *) current_list_page[offset];
+}
+
+static int get_extentpages_list(void)
+{
+	struct extent * this_extent_page = first_extent_page;
+	int i, j, pages_needed, num_in_this_page;
+	unsigned long * current_list_page = extent_pagelist;
+	unsigned long * prev_list_page = NULL;
+
+	pages_needed =
+		((num_extent_pages + POINTERS_PER_PAGE - 1) / POINTERS_PER_PAGE);
+	
+	for (i = 0; i < pages_needed; i++) {
+		int page_start = i * POINTERS_PER_PAGE;
+		
+		if (!current_list_page) {
+			current_list_page = test_suspend_state(SUSPEND_NOW_RESUMING) ?
+				(unsigned long *) get_zeroed_page(GFP_ATOMIC) :
+				(unsigned long *) get_grabbed_pages(0);
+			if (!current_list_page)
+				current_list_page = (unsigned long *) get_zeroed_page(GFP_ATOMIC);
+			if (!current_list_page) {
+				abort_suspend("Unable to allocate memory for a extent pages list.");
+				printk("Number of extent pages is %d.\n", num_extent_pages);
+				return -ENOMEM;
+			}
+
+			current_list_page[0] = 0;
+			if (!prev_list_page)
+				extent_pagelist = current_list_page;
+			else {
+				*prev_list_page = (unsigned long) current_list_page;
+				prev_list_page = current_list_page;
+			}
+		}
+	
+		num_in_this_page = num_extent_pages - page_start;
+		if (num_in_this_page > POINTERS_PER_PAGE)
+			num_in_this_page = POINTERS_PER_PAGE;
+		
+		for (j = 1; j <= num_in_this_page; j++) {
+			current_list_page[j] = (unsigned long) this_extent_page;
+
+			this_extent_page = (struct extent *) (((unsigned long)
+				(*EXTENTPAGELINK(this_extent_page))) & PAGE_MASK);
+		}
+		
+		for (j = (num_in_this_page + 1); j <= POINTERS_PER_PAGE; j++)
+			current_list_page[j] = 0;
+
+		if ((num_extent_pages - page_start) > POINTERS_PER_PAGE)
+			current_list_page = (unsigned long *) current_list_page[0];
+	}
+
+	return 0;
+}
+
+static void put_extentpages_list(void)
+{
+	unsigned long * last;
+
+	while (extent_pagelist) {
+		last = extent_pagelist;
+		extent_pagelist = *((unsigned long **) extent_pagelist);
+		free_pages((unsigned long) last, 0);
+	}
+}
+
+int PageExtentPage(char * seeking)
+{
+	int i;
+	
+	for (i = 1; i <= num_extent_pages; i++)
+		if (get_extentpages_list_entry(i) == 
+			(unsigned long *) seeking)
+			return 1;
+
+	return 0;
+}
+/* relocate_extentpages
+ * 
+ * Called at the start of resuming. As well as absolutising pages, we need
+ * to ensure they won't be overwritten by the kernel we're restoring. 
+ */
+int relocate_extentpages()
+{
+	void **eaten_memory = NULL;
+	void **c = eaten_memory, *m = NULL, *f;
+	int oom = 0, i, numeaten = 0;
+	unsigned long * prev_page = NULL;
+
+	for (i = 1; i <= num_extent_pages; i++) {
+		int this_collides = 0;
+		unsigned long * this_page = get_extentpages_list_entry(i);
+
+		this_collides = PageInUse(virt_to_page(this_page));
+
+		if (!this_collides) {
+			prev_page = this_page;
+			continue;
+		}
+
+		while ((m = (void *) get_zeroed_page(GFP_ATOMIC))) {
+			memset(m, 0, PAGE_SIZE);
+			if (!PageInUse(virt_to_page(m))) {
+				copy_page(m, (void *) this_page);
+				free_page((unsigned long) this_page);
+				if (i == 1)
+					first_extent_page = m;
+				else
+					*EXTENTPAGELINK(prev_page) =
+						(i | (unsigned long) m);
+				prev_page = m;
+				break;
+			}
+			numeaten++;
+			eaten_memory = m;
+			*eaten_memory = c;
+			c = eaten_memory;
+		}
+
+		if (!m) {
+			printk("\nRan out of memory trying to relocate "
+				"extentpages (tried %d pages).\n", numeaten);
+			oom = 1;
+			break;
+		}
+	}
+		
+	c = eaten_memory;
+	while(c) {
+		f = c;
+		c = *c;
+		if (f)
+			free_pages((unsigned long) f, 0);
+	}
+	eaten_memory = NULL;
+	
+	if (oom) 
+		return -ENOMEM;
+	else
+		return 0;
+}
+
+EXPORT_SYMBOL_GPL(get_extentpages_list_entry);
+EXPORT_SYMBOL_GPL(absolutise_chain);
+EXPORT_SYMBOL_GPL(relativise_chain);
+EXPORT_SYMBOL_GPL(put_extent);
+EXPORT_SYMBOL_GPL(put_extent_chain);
+EXPORT_SYMBOL_GPL(add_to_extent_chain);
+EXPORT_SYMBOL_GPL(PageExtentPage);
