mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Jiri Slaby <jslaby@suse.cz>
To: rjw@sisk.pl
Cc: pavel@ucw.cz, linux-pm@lists.linux-foundation.org,
	linux-kernel@vger.kernel.org, jirislaby@gmail.com
Subject: [PATCH 5/9] PM / Hibernate: add chunk i/o support
Date: Wed,  2 Jun 2010 10:52:44 +0200	[thread overview]
Message-ID: <1275468768-28229-5-git-send-email-jslaby@suse.cz> (raw)
In-Reply-To: <1275468768-28229-1-git-send-email-jslaby@suse.cz>

Chunk support is useful when not writing whole pages at once. It takes
care of joining the buffers into the pages and writing at once when
needed.

This adds functions for both reads and writes.

In the end when pages are compressed they use this interface as well
(because they are indeed shorter than PAGE_SIZE).

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
---
 kernel/power/block_io.c |  126 +++++++++++++++++++++++++++++++++++++++++++++++
 kernel/power/power.h    |   16 ++++++
 2 files changed, 142 insertions(+), 0 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index 97024fd..5b6413d 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
  * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
+ * Copyright (C) 2004-2008 Nigel Cunningham (nigel at tuxonice net)
  *
  * This file is released under the GPLv2.
  */
@@ -74,6 +75,131 @@ int hib_bio_write_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
 			virt_to_page(addr), bio_chain);
 }
 
+static int hib_buffer_init_rw(struct hibernate_io_handle *io_handle,
+		int writing)
+{
+	/* should never happen - it means we didn't finish properly last time */
+	BUG_ON(io_handle->chunk_buffer || io_handle->chunk_buffer_pos);
+
+	io_handle->chunk_buffer =
+		(void *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
+	if (io_handle->chunk_buffer && !writing)
+		io_handle->chunk_buffer_pos = PAGE_SIZE;
+
+	return io_handle->chunk_buffer ? 0 : -ENOMEM;
+}
+
+int hib_buffer_init_read(struct hibernate_io_handle *io_handle)
+{
+	return hib_buffer_init_rw(io_handle, 0);
+}
+
+int hib_buffer_init_write(struct hibernate_io_handle *io_handle)
+{
+	return hib_buffer_init_rw(io_handle, 1);
+}
+
+/**
+ * hib_buffer_rw - combine smaller buffers into PAGE_SIZE I/O
+ * @io_handle: handle from reader/writer
+ * @writing: whether writing (or reading).
+ * @buffer: the start of the buffer to write or fill.
+ * @buffer_size: the size of the buffer to write or fill.
+ **/
+static int hib_buffer_rw(struct hibernate_io_handle *io_handle, int writing,
+		char *buffer, int buffer_size)
+{
+	int bytes_left = buffer_size, ret;
+
+	while (bytes_left) {
+		char *source_start = buffer + buffer_size - bytes_left;
+		char *dest_start = io_handle->chunk_buffer +
+			io_handle->chunk_buffer_pos;
+		int capacity = PAGE_SIZE - io_handle->chunk_buffer_pos;
+		char *to = writing ? dest_start : source_start;
+		char *from = writing ? source_start : dest_start;
+
+		if (bytes_left <= capacity) {
+			memcpy(to, from, bytes_left);
+			io_handle->chunk_buffer_pos += bytes_left;
+			return 0;
+		}
+
+		/* Complete this page and start a new one */
+		memcpy(to, from, capacity);
+		bytes_left -= capacity;
+
+		if (writing)
+			ret = hibernate_io_ops->write_page(io_handle,
+					io_handle->chunk_buffer, NULL);
+		else
+			ret = hibernate_io_ops->read_page(io_handle,
+					io_handle->chunk_buffer, NULL);
+
+		if (ret)
+			return ret;
+
+		io_handle->chunk_buffer_pos = 0;
+	}
+
+	return 0;
+}
+
+int hib_buffer_read(struct hibernate_io_handle *io_handle, char *buffer,
+		int buffer_size)
+{
+	return hib_buffer_rw(io_handle, 0, buffer, buffer_size);
+}
+
+int hib_buffer_write(struct hibernate_io_handle *io_handle, char *buffer,
+		int buffer_size)
+{
+	return hib_buffer_rw(io_handle, 1, buffer, buffer_size);
+}
+
+int hib_buffer_flush_page_read(struct hibernate_io_handle *io_handle)
+{
+	io_handle->chunk_buffer_pos = PAGE_SIZE;
+
+	return 0;
+}
+
+int hib_buffer_finish_read(struct hibernate_io_handle *io_handle)
+{
+	int ret;
+
+	ret = hib_buffer_flush_page_read(io_handle);
+
+	free_page((unsigned long)io_handle->chunk_buffer);
+	io_handle->chunk_buffer = NULL;
+	io_handle->chunk_buffer_pos = 0;
+
+	return ret;
+}
+
+int hib_buffer_flush_page_write(struct hibernate_io_handle *io_handle)
+{
+	int ret = 0;
+	if (io_handle->chunk_buffer_pos)
+		ret = hibernate_io_ops->write_page(io_handle,
+				io_handle->chunk_buffer, NULL);
+	io_handle->chunk_buffer_pos = 0;
+	return ret;
+}
+
+int hib_buffer_finish_write(struct hibernate_io_handle *io_handle)
+{
+	int ret = 0;
+
+	ret = hib_buffer_flush_page_write(io_handle);
+
+	free_page((unsigned long)io_handle->chunk_buffer);
+	io_handle->chunk_buffer = NULL;
+	io_handle->chunk_buffer_pos = 0;
+
+	return ret;
+}
+
 int hib_wait_on_bio_chain(struct bio **bio_chain)
 {
 	struct bio *bio;
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 32a40f9..812b66c 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -119,9 +119,14 @@ struct snapshot_handle {
 /**
  * struct hibernate_io_handle - handle for image I/O processing
  *
+ * @chunk_buffer: temporary buffer used by chunk I/O to fill whole page
+ * @chunk_buffer_pos: position in chio_buffer
  * @priv: private data for each processor (swap_map_handle etc.)
  */
 struct hibernate_io_handle {
+	char *chunk_buffer;
+	unsigned long chunk_buffer_pos;
+
 	void *priv;
 };
 
@@ -200,6 +205,17 @@ extern int hib_bio_write_page(pgoff_t page_off, void *addr,
 		struct bio **bio_chain);
 extern int hib_wait_on_bio_chain(struct bio **bio_chain);
 
+extern int hib_buffer_init_read(struct hibernate_io_handle *io_handle);
+extern int hib_buffer_init_write(struct hibernate_io_handle *io_handle);
+extern int hib_buffer_finish_read(struct hibernate_io_handle *io_handle);
+extern int hib_buffer_finish_write(struct hibernate_io_handle *io_handle);
+extern int hib_buffer_flush_page_read(struct hibernate_io_handle *io_handle);
+extern int hib_buffer_flush_page_write(struct hibernate_io_handle *io_handle);
+extern int hib_buffer_read(struct hibernate_io_handle *io_handle, char *buffer,
+		int buffer_size);
+extern int hib_buffer_write(struct hibernate_io_handle *io_handle, char *buffer,
+		int buffer_size);
+
 struct timeval;
 /* kernel/power/swsusp.c */
 extern void swsusp_show_speed(struct timeval *, struct timeval *,
-- 
1.7.1



  parent reply	other threads:[~2010-06-02  8:54 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-06-02  8:52 [PATCH 1/9] PM / Hibernate: swap, switch to hibernate_io_handle Jiri Slaby
2010-06-02  8:52 ` [PATCH 2/9] PM / Hibernate: add hibernate_io_ops Jiri Slaby
2010-06-24 15:23   ` Rafael J. Wysocki
2010-06-02  8:52 ` [PATCH 3/9] PM / Hibernate: user, implement user_ops writer Jiri Slaby
2010-06-24 16:27   ` Rafael J. Wysocki
2010-06-02  8:52 ` [PATCH 4/9] PM / Hibernate: user, implement user_ops reader Jiri Slaby
2010-06-25 13:37   ` Rafael J. Wysocki
2010-06-02  8:52 ` Jiri Slaby [this message]
2010-06-25 13:44   ` [PATCH 5/9] PM / Hibernate: add chunk i/o support Rafael J. Wysocki
2010-06-02  8:52 ` [PATCH 6/9] PM / Hibernate: split snapshot_read_next Jiri Slaby
2010-06-25 13:53   ` Rafael J. Wysocki
2010-07-19 16:42     ` Jiri Slaby
2010-06-02  8:52 ` [PATCH 7/9] PM / Hibernate: split snapshot_write_next Jiri Slaby
2010-06-25 13:54   ` Rafael J. Wysocki
2010-06-02  8:52 ` [PATCH 8/9] PM / Hibernate: dealign swsusp_info Jiri Slaby
2010-06-25 13:54   ` Rafael J. Wysocki
2010-06-02  8:52 ` [PATCH 9/9] PM / Hibernate: move non-swap code to image.c Jiri Slaby
2010-06-25 13:55   ` Rafael J. Wysocki
2010-06-02 11:40 ` [PATCH 1/9] PM / Hibernate: swap, switch to hibernate_io_handle Nigel Cunningham
2010-06-02 12:37 ` [linux-pm] " Nigel Cunningham
2010-06-10 13:55 ` Pavel Machek
2010-06-21 15:23   ` Jiri Slaby
2010-07-18 12:36     ` Pavel Machek
2010-06-11  9:46 ` [linux-pm] " Nigel Cunningham
2010-06-21 15:21   ` Jiri Slaby
2010-06-21 21:58     ` Nigel Cunningham
2010-06-25 14:00       ` Rafael J. Wysocki
2010-06-24 15:20 ` Rafael J. Wysocki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1275468768-28229-5-git-send-email-jslaby@suse.cz \
    --to=jslaby@suse.cz \
    --cc=jirislaby@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@lists.linux-foundation.org \
    --cc=pavel@ucw.cz \
    --cc=rjw@sisk.pl \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®