lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Sat, 25 Sep 2010 14:16:53 +1000
From:	Nigel Cunningham <nigel@...onice.net>
To:	"Rafael J. Wysocki" <rjw@...k.pl>,
	Linux PM <linux-pm@...ts.linux-foundation.org>,
	LKML <linux-kernel@...r.kernel.org>,
	TuxOnIce-devel <tuxonice-devel@...onice.net>
Subject: [PATCH 11/22] Hibernation: Move block i/o fns to block_io.c

Move the functions that specifically deal with submitting I/O
to block_io.c. This helps us in working towards having a clean
separation between swap specific functions (which will be all
that will be in swap.c eventually) and low level block i/o
functions (block_io.c) that are/will be agnostic with regard to
the source of the storage. The block_io.c functions will thus
also be useable when support for storing an image in a generic
file (non swap) is added later.

Signed-off-by: Nigel Cunningham <nigel@...onice.net>
---
 kernel/power/block_io.c |  199 ++++++++++++++++++++++++++++++++++++++++++++++
 kernel/power/block_io.h |   23 ++++++
 kernel/power/swap.c     |  202 +++--------------------------------------------
 3 files changed, 235 insertions(+), 189 deletions(-)
 create mode 100644 kernel/power/block_io.h

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index aa239a2..5edcb08 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -13,6 +13,7 @@
 #include <linux/swap.h>
 
 #include "power.h"
+#include "extents.h"
 
 static struct bio *bio_chain;
 
@@ -102,3 +103,201 @@ int hib_wait_on_bio_chain(void)
 	bio_chain = NULL;
 	return ret;
 }
+
+/*
+ *	The swap map is a data structure used for keeping track of each page
+ *	written to a swap partition.  It consists of many swap_map_page
+ *	structures that contain each an array of MAP_PAGE_SIZE swap entries.
+ *	These structures are stored on the swap and linked together with the
+ *	help of the .next_swap member.
+ *
+ *	The swap map is created during suspend.  The swap map pages are
+ *	allocated and populated one at a time, so we only need one memory
+ *	page to set up the entire structure.
+ *
+ *	During resume we also only need to use one swap_map_page structure
+ *	at a time.
+ */
+
+#define MAP_PAGE_ENTRIES	(PAGE_SIZE / sizeof(sector_t) - 1)
+
+struct swap_map_page {
+	sector_t entries[MAP_PAGE_ENTRIES];
+	sector_t next_swap;
+};
+
+/**
+ *	The swap_map_handle structure is used for handling swap in
+ *	a file-alike way
+ */
+
+struct swap_map_handle {
+	struct swap_map_page *cur;
+	sector_t cur_swap;
+	sector_t first_sector;
+	unsigned int k;
+};
+
+static struct swap_map_handle handle;
+
+extern struct hib_extent_state sector_extents;
+
+/* Calculate the overhead needed for storing n pages */
+unsigned int hib_bio_overhead(unsigned int nr_pages)
+{
+	return DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
+}
+
+/* Get the first sector of the image proper, for storing in the signature */
+sector_t hib_get_first_sector(void)
+{
+	return handle.first_sector;
+}
+
+/**
+ *	write_page - Write one page to given swap location.
+ *	@buf:		Address we're writing.
+ *	@offset:	Offset of the swap page we're writing to.
+ *	@sync:		Whether to force synchronous i/o.
+ */
+
+static int write_page(void *buf, sector_t offset, int sync)
+{
+	void *src;
+
+	if (!offset)
+		return -ENOSPC;
+
+	if (!sync) {
+		src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
+		if (src) {
+			memcpy(src, buf, PAGE_SIZE);
+		} else {
+			WARN_ON_ONCE(1);
+			sync = 1;	/* Go synchronous */
+			src = buf;
+		}
+	} else {
+		src = buf;
+	}
+	return hib_bio_write_page(offset, src, sync);
+}
+
+void release_swap_writer(void)
+{
+	if (handle.cur)
+		free_page((unsigned long)handle.cur);
+	handle.cur = NULL;
+}
+
+int hib_bio_prepare_write(void)
+{
+	handle.cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
+
+	if (!handle.cur)
+		return -ENOMEM;
+
+	handle.cur_swap = hib_extent_next(&sector_extents);
+
+	if (!handle.cur_swap) {
+		release_swap_writer();
+		return -ENOSPC;
+	}
+
+	handle.k = 0;
+	handle.first_sector = handle.cur_swap;
+	return 0;
+}
+
+int swap_write_page(void *buf, int sync)
+{
+	int error = 0;
+	sector_t offset;
+
+	if (!handle.cur)
+		return -EINVAL;
+	offset = hib_extent_next(&sector_extents);
+	error = write_page(buf, offset, sync);
+	if (error)
+		return error;
+	handle.cur->entries[handle.k++] = offset;
+	if (handle.k >= MAP_PAGE_ENTRIES) {
+		error = hib_wait_on_bio_chain();
+		if (error)
+			goto out;
+		offset = hib_extent_next(&sector_extents);
+		if (!offset)
+			return -ENOSPC;
+		handle.cur->next_swap = offset;
+		error = write_page(handle.cur, handle.cur_swap, 1);
+		if (error)
+			goto out;
+		memset(handle.cur, 0, PAGE_SIZE);
+		handle.cur_swap = offset;
+		handle.k = 0;
+	}
+ out:
+	return error;
+}
+
+int flush_swap_writer(void)
+{
+	if (handle.cur && handle.cur_swap)
+		return write_page(handle.cur, handle.cur_swap, 1);
+	else
+		return -EINVAL;
+}
+
+/**
+ *	The following functions allow us to read data using a swap map
+ *	in a file-alike way
+ */
+
+void release_swap_reader(void)
+{
+	if (handle.cur)
+		free_page((unsigned long)handle.cur);
+	handle.cur = NULL;
+}
+
+int get_swap_reader(unsigned int *flags_p, sector_t first_page)
+{
+	int error;
+
+	handle.cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
+	if (!handle.cur)
+		return -ENOMEM;
+
+	error = hib_bio_read_page(first_page, handle.cur, 1);
+	if (error) {
+		release_swap_reader();
+		return error;
+	}
+	handle.k = 0;
+	return 0;
+}
+
+int swap_read_page(void *buf, int sync)
+{
+	sector_t offset;
+	int error;
+
+	if (!handle.cur)
+		return -EINVAL;
+	offset = handle.cur->entries[handle.k];
+	if (!offset)
+		return -EFAULT;
+	error = hib_bio_read_page(offset, buf, sync);
+	if (error)
+		return error;
+	if (++handle.k >= MAP_PAGE_ENTRIES) {
+		error = hib_wait_on_bio_chain();
+		handle.k = 0;
+		offset = handle.cur->next_swap;
+		if (!offset)
+			release_swap_reader();
+		else if (!error)
+			error = hib_bio_read_page(offset, handle.cur, 1);
+	}
+	return error;
+}
diff --git a/kernel/power/block_io.h b/kernel/power/block_io.h
new file mode 100644
index 0000000..2f91d6d
--- /dev/null
+++ b/kernel/power/block_io.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@....cz>
+ * Copyright (C) 2006 Rafael J. Wysocki <rjw@...k.pl>
+ * Copyright (C) 2010 Nigel Cunningham <nigel@...onice.net>
+ *
+ * This file is released under the GPLv2.
+ */
+
+/* Low level routines */
+int hib_bio_read_page(pgoff_t page_off, void *addr, int sync);
+int hib_bio_write_page(pgoff_t page_off, void *addr, int sync);
+int hib_wait_on_bio_chain(void);
+
+unsigned int hib_bio_overhead(unsigned int nr_pages);
+sector_t hib_get_first_sector(void);
+extern struct hib_extent_state sector_extents;
+void release_swap_writer(void);
+int hib_bio_prepare_write(void);
+int flush_swap_writer(void);
+int swap_write_page(void *buf, int sync);
+int get_swap_reader(unsigned int *flags_p, sector_t first_page);
+void release_swap_reader(void);
+int swap_read_page(void *buf, int sync);
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index a881086..d217a6f 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -26,45 +26,10 @@
 
 #include "power.h"
 #include "extents.h"
+#include "block_io.h"
 
 #define SWSUSP_SIG	"S1SUSPEND"
 
-/*
- *	The swap map is a data structure used for keeping track of each page
- *	written to a swap partition.  It consists of many swap_map_page
- *	structures that contain each an array of MAP_PAGE_ENTRIES swap entries.
- *	These structures are stored on the swap and linked together with the
- *	help of the .next_swap member.
- *
- *	The swap map is created during suspend.  The swap map pages are
- *	allocated and populated one at a time, so we only need one memory
- *	page to set up the entire structure.
- *
- *	During resume we also only need to use one swap_map_page structure
- *	at a time.
- */
-
-#define MAP_PAGE_ENTRIES	(PAGE_SIZE / sizeof(sector_t) - 1)
-
-struct swap_map_page {
-	sector_t entries[MAP_PAGE_ENTRIES];
-	sector_t next_swap;
-};
-
-/**
- *	The swap_map_handle structure is used for handling swap in
- *	a file-alike way
- */
-
-struct swap_map_handle {
-	struct swap_map_page *cur;
-	sector_t cur_swap;
-	sector_t first_sector;
-	unsigned int k;
-};
-
-static struct swap_map_handle handle;
-
 static unsigned short root_swap = 0xffff;
 
 struct swsusp_header {
@@ -79,7 +44,7 @@ struct swsusp_header {
 static struct swsusp_header *swsusp_header;
 
 static struct hib_extent_state swap_extents;
-static struct hib_extent_state sector_extents;
+struct hib_extent_state sector_extents;
 
 /**
  *	alloc_swapdev_block - allocate a swap page and register that it has
@@ -127,7 +92,7 @@ static int allocate_swap(unsigned int nr_pages)
 {
 	unsigned int free_swap = count_swap_pages(root_swap, 1);
 
-	nr_pages += DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
+	nr_pages += hib_bio_overhead(nr_pages);
 
 	pr_debug("PM: Free swap pages: %u\n", free_swap);
 	if (free_swap < nr_pages)
@@ -185,7 +150,7 @@ static int mark_swapfiles(unsigned int flags)
 		memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
 		memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
 		swsusp_header->write_speed = write_speed;
-		swsusp_header->image = handle.first_sector;
+		swsusp_header->image = hib_get_first_sector();
 		swsusp_header->flags = flags;
 		error = hib_bio_write_page(swsusp_resume_block,
 					swsusp_header, 1);
@@ -223,42 +188,6 @@ static int swsusp_swap_check(void)
 	return res;
 }
 
-/**
- *	write_page - Write one page to given swap location.
- *	@buf:		Address we're writing.
- *	@offset:	Offset of the swap page we're writing to.
- *	@sync:		Whether to force synchronous i/o.
- */
-
-static int write_page(void *buf, sector_t offset, int sync)
-{
-	void *src;
-
-	if (!offset)
-		return -ENOSPC;
-
-	if (!sync) {
-		src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
-		if (src) {
-			memcpy(src, buf, PAGE_SIZE);
-		} else {
-			WARN_ON_ONCE(1);
-			sync = 1;	/* Go synchronous */
-			src = buf;
-		}
-	} else {
-		src = buf;
-	}
-	return hib_bio_write_page(offset, src, sync);
-}
-
-static void release_swap_writer(void)
-{
-	if (handle.cur)
-		free_page((unsigned long)handle.cur);
-	handle.cur = NULL;
-}
-
 static int get_swap_writer(unsigned long pages)
 {
 	int ret;
@@ -270,70 +199,19 @@ static int get_swap_writer(unsigned long pages)
 					"swapon -a.\n");
 		return ret;
 	}
-	handle.cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
-	if (!handle.cur) {
-		ret = -ENOMEM;
-		goto err_close;
-	}
 	if (!allocate_swap(pages)) {
 		printk(KERN_ERR "PM: Not enough free swap\n");
 		ret = -ENOSPC;
 		goto err_close;
 	}
-	handle.cur_swap = hib_extent_next(&sector_extents);
-	if (!handle.cur_swap) {
-		ret = -ENOSPC;
-		goto err_rel;
-	}
-	handle.k = 0;
-	handle.first_sector = handle.cur_swap;
-	return 0;
-err_rel:
-	release_swap_writer();
+	ret = hib_bio_prepare_write();
+	if (!ret)
+		return 0;
 err_close:
 	swsusp_close(FMODE_WRITE);
 	return ret;
 }
 
-static int swap_write_page(void *buf, int sync)
-{
-	int error = 0;
-	sector_t offset;
-
-	if (!handle.cur)
-		return -EINVAL;
-	offset = hib_extent_next(&sector_extents);
-	error = write_page(buf, offset, sync);
-	if (error)
-		return error;
-	handle.cur->entries[handle.k++] = offset;
-	if (handle.k >= MAP_PAGE_ENTRIES) {
-		error = hib_wait_on_bio_chain();
-		if (error)
-			goto out;
-		offset = hib_extent_next(&sector_extents);
-		if (!offset)
-			return -ENOSPC;
-		handle.cur->next_swap = offset;
-		error = write_page(handle.cur, handle.cur_swap, 1);
-		if (error)
-			goto out;
-		memset(handle.cur, 0, PAGE_SIZE);
-		handle.cur_swap = offset;
-		handle.k = 0;
-	}
- out:
-	return error;
-}
-
-static int flush_swap_writer(void)
-{
-	if (handle.cur && handle.cur_swap)
-		return write_page(handle.cur, handle.cur_swap, 1);
-	else
-		return -EINVAL;
-}
-
 static int swap_writer_finish(unsigned int flags, int error)
 {
 	if (!error) {
@@ -437,65 +315,6 @@ out_finish:
 	return error;
 }
 
-/**
- *	The following functions allow us to read data using a swap map
- *	in a file-alike way
- */
-
-static void release_swap_reader(void)
-{
-	if (handle.cur)
-		free_page((unsigned long)handle.cur);
-	handle.cur = NULL;
-}
-
-static int get_swap_reader(unsigned int *flags_p)
-{
-	int error;
-
-	*flags_p = swsusp_header->flags;
-
-	if (!swsusp_header->image) /* how can this happen? */
-		return -EINVAL;
-
-	handle.cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
-	if (!handle.cur)
-		return -ENOMEM;
-
-	error = hib_bio_read_page(swsusp_header->image, handle.cur, 1);
-	if (error) {
-		release_swap_reader();
-		return error;
-	}
-	handle.k = 0;
-	return 0;
-}
-
-static int swap_read_page(void *buf, int sync)
-{
-	sector_t offset;
-	int error;
-
-	if (!handle.cur)
-		return -EINVAL;
-	offset = handle.cur->entries[handle.k];
-	if (!offset)
-		return -EFAULT;
-	error = hib_bio_read_page(offset, buf, sync);
-	if (error)
-		return error;
-	if (++handle.k >= MAP_PAGE_ENTRIES) {
-		error = hib_wait_on_bio_chain();
-		handle.k = 0;
-		offset = handle.cur->next_swap;
-		if (!offset)
-			release_swap_reader();
-		else if (!error)
-			error = hib_bio_read_page(offset, handle.cur, 1);
-	}
-	return error;
-}
-
 static int swap_reader_finish(void)
 {
 	release_swap_reader();
@@ -574,7 +393,12 @@ int swsusp_read(unsigned int *flags_p)
 	if (error < PAGE_SIZE)
 		return error < 0 ? error : -EFAULT;
 	header = (struct swsusp_info *)data_of(snapshot);
-	error = get_swap_reader(flags_p);
+	*flags_p = swsusp_header->flags;
+	if (!swsusp_header->image) { /* how can this happen? */
+		error = -EINVAL;
+		goto end;
+	}
+	error = get_swap_reader(flags_p, swsusp_header->image);
 	if (error)
 		goto end;
 	if (!error)
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists