linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Nigel Cunningham <nigel@tuxonice.net>
To: "Rafael J. Wysocki" <rjw@sisk.pl>,
	Linux PM <linux-pm@lists.linux-foundation.org>,
	LKML <linux-kernel@vger.kernel.org>,
	TuxOnIce-devel <tuxonice-devel@tuxonice.net>
Subject: [PATCH 16/21] Hibernation: Replace bio chain
Date: Wed,  2 Jun 2010 22:19:15 +1000	[thread overview]
Message-ID: <1275481160-31150-17-git-send-email-nigel@tuxonice.net> (raw)
In-Reply-To: <1275481160-31150-1-git-send-email-nigel@tuxonice.net>

Replace the bio_chain concept with:
(1) simple atomic_t recording how many pages are in flight
(2) a wait queue for waiting for all I/O to complete
(3) a custom completion routine that frees bio structs and pages used
    for async writes as they complete, undates the atomic_t and
    wakes any waiters.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   77 ++++++++++++++++++++++++++++------------------
 1 files changed, 47 insertions(+), 30 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index 9028f74..c9569e5 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -16,23 +16,61 @@
 #include "extents.h"
 #include "block_io.h"
 
-static struct bio *bio_chain;
-
 static char *hib_ppio_buffer;
 static int hib_ppio_buffer_posn;
 int hib_prepare_buffer(void);
 void hib_free_buffer(void);
 
+static atomic_t hib_io_in_progress;
+static DECLARE_WAIT_QUEUE_HEAD(num_in_progress_wait);
+
+/**
+ * hib_end_bio - bio completion function.
+ * @bio: bio that has completed.
+ * @err: Error value. Yes, like end_swap_bio_read, we ignore it.
+ *
+ * Function called by the block driver from interrupt context when I/O is
+ * completed. If we were writing the page, we want to free it and will have
+ * set bio->bi_private to the parameter we should use in telling the page
+ * allocation accounting code what the page was allocated for. If we're
+ * reading the page, it will be in the singly linked list made from
+ * page->private pointers.
+ **/
+static void hib_end_bio(struct bio *bio, int err)
+{
+	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+	struct page *page = bio->bi_io_vec[0].bv_page;
+
+	if (!uptodate) {
+		SetPageError(page);
+		ClearPageUptodate(page);
+		printk(KERN_ALERT "I/O on swap-device (%u:%u:%Lu)\n",
+				imajor(bio->bi_bdev->bd_inode),
+				iminor(bio->bi_bdev->bd_inode),
+				(unsigned long long)bio->bi_sector);
+	} else {
+		SetPageUptodate(page);
+	}
+	unlock_page(page);
+	bio_put(bio);
+
+	if (bio->bi_private)
+		__free_page(page);
+
+	atomic_dec(&hib_io_in_progress);
+	wake_up(&num_in_progress_wait);
+}
+
 /**
  *	submit - submit BIO request.
  *	@rw:	READ or WRITE.
  *	@off	physical offset of page.
  *	@page:	page we're reading or writing.
- *	@bio_chain: list of pending biod (for async reading)
+ *	@sync:	whether the i/o should be done synchronously
  *
  *	Straight from the textbook - allocate and initialize the bio.
  *	If we're reading, make sure the page is marked as dirty.
- *	Then submit it and, if @bio_chain == NULL, wait.
+ *	Then submit it and, if @sync, wait.
  */
 static int submit(int rw, struct block_device *bdev, sector_t sector,
 		struct page *page, int sync)
@@ -43,7 +81,8 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
 	bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1);
 	bio->bi_sector = sector;
 	bio->bi_bdev = bdev;
-	bio->bi_end_io = end_swap_bio_read;
+	bio->bi_private = (void *) (rw && !sync);
+	bio->bi_end_io = hib_end_bio;
 
 	if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
 		printk(KERN_ERR "PM: Adding page to bio failed at %llu\n",
@@ -54,6 +93,7 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
 
 	lock_page(page);
 	bio_get(bio);
+	atomic_inc(&hib_io_in_progress);
 
 	if (sync) {
 		submit_bio(bio_rw, bio);
@@ -64,8 +104,6 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
 	} else {
 		if (rw == READ)
 			get_page(page);	/* These pages are freed later */
-		bio->bi_private = bio_chain;
-		bio_chain = bio;
 		submit_bio(bio_rw, bio);
 	}
 	return 0;
@@ -85,29 +123,8 @@ int hib_bio_write_page(pgoff_t page_off, void *addr, int sync)
 
 int hib_wait_on_bio_chain(void)
 {
-	struct bio *bio;
-	struct bio *next_bio;
-	int ret = 0;
-
-	if (bio_chain == NULL)
-		return 0;
-
-	bio = bio_chain;
-
-	while (bio) {
-		struct page *page;
-
-		next_bio = bio->bi_private;
-		page = bio->bi_io_vec[0].bv_page;
-		wait_on_page_locked(page);
-		if (!PageUptodate(page) || PageError(page))
-			ret = -EIO;
-		put_page(page);
-		bio_put(bio);
-		bio = next_bio;
-	}
-	bio_chain = NULL;
-	return ret;
+	wait_event(num_in_progress_wait, !atomic_read(&hib_io_in_progress));
+	return 0;
 }
 
 /*
-- 
1.7.0.4


  parent reply	other threads:[~2010-06-02 12:20 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
2010-06-02 12:19 ` [PATCH 01/21] Hibernation: Swap iteration functions Nigel Cunningham
2010-06-02 12:19 ` [PATCH 02/21] Hibernation: Move root_swap declaration Nigel Cunningham
2010-06-02 12:19 ` [PATCH 03/21] Hibernation: Add mass swap allocation routine Nigel Cunningham
2010-06-02 12:19 ` [PATCH 04/21] Hibernation: Switch to preallocating swap Nigel Cunningham
2010-06-02 12:19 ` [PATCH 05/21] Hiberation: Fix speed display Nigel Cunningham
2010-06-02 12:19 ` [PATCH 06/21] Hibernation: Generic extents support Nigel Cunningham
2010-06-02 12:19 ` [PATCH 07/21] Hibernation: Iterate over sectors not swap entries Nigel Cunningham
2010-06-02 12:19 ` [PATCH 08/21] Hibernation: Stop passing swap_map_handle struct Nigel Cunningham
2010-06-02 12:19 ` [PATCH 09/21] Hibernation: Stop passing bio_chain around Nigel Cunningham
2010-06-02 12:19 ` [PATCH 10/21] Hibernation: Move block i/o fns to block_io.c Nigel Cunningham
2010-06-02 12:19 ` [PATCH 11/21] Hibernation: Partial page I/O support Nigel Cunningham
2010-06-02 12:19 ` [PATCH 12/21] Hibernation: Extent save/load routines Nigel Cunningham
2010-06-02 12:19 ` [PATCH 13/21] Hibernation: Store block extents at start of image Nigel Cunningham
2010-06-02 12:19 ` [PATCH 14/21] Hibernation: Use block extents for reading image Nigel Cunningham
2010-06-02 12:19 ` [PATCH 15/21] Remove first_sector from swap_map_handle Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham [this message]
2010-06-02 12:19 ` [PATCH 17/21] Hibernation: Remove swap_map_pages Nigel Cunningham
2010-06-02 12:19 ` [PATCH 18/21] Hibernation: Remove wait_on_bio_chain result Nigel Cunningham
2010-06-02 12:19 ` [PATCH 19/21] Hibernation: Prepare for handle.cur removal Nigel Cunningham
2010-06-02 12:19 ` [PATCH 20/21] Hibernation: Remove swap_map structure Nigel Cunningham
2010-06-02 12:19 ` [PATCH 21/21] Hibernation: Remove now-empty routines Nigel Cunningham
2010-08-03  6:55 ` Nigel's current for-rafael queue Pavel Machek
2010-08-03  7:00   ` Nigel Cunningham

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=1275481160-31150-17-git-send-email-nigel@tuxonice.net \
    --to=nigel@tuxonice.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@lists.linux-foundation.org \
    --cc=rjw@sisk.pl \
    --cc=tuxonice-devel@tuxonice.net \
    /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;
as well as URLs for NNTP newsgroup(s).