[prev in list] [next in list] [prev in thread] [next in thread] 

List:       git-commits-head
Subject:    dm io: fix I/O to multiple destinations
From:       "Linux Kernel Mailing List" <linux-kernel () vger ! kernel ! org>
Date:       2014-02-28 22:55:16
Message-ID: 20140228225516.A762B660CDD () gitolite ! kernel ! org
[Download RAW message or body]

Gitweb:     http://git.kernel.org/linus/;a=commit;h=d73f9907294c670da14baea3fb31be27879e818e
Commit:     d73f9907294c670da14baea3fb31be27879e818e
Parent:     4d1662a30dde6e545086fe0e8fd7e474c4e0b639
Author:     Mikulas Patocka <mpatocka@redhat.com>
AuthorDate: Wed Feb 12 16:37:30 2014 -0500
Committer:  Mike Snitzer <snitzer@redhat.com>
CommitDate: Mon Feb 17 11:00:05 2014 -0500

    dm io: fix I/O to multiple destinations
    
    Commit 003b5c5719f159f4f4bf97511c4702a0638313dd ("block: Convert drivers
    to immutable biovecs") broke dm-mirror due to dm-io breakage.
    
    dm-io had three possible iterators (DM_IO_PAGE_LIST, DM_IO_BVEC,
    DM_IO_VMA) that iterate over pages where the I/O should be performed.
    
    The switch to immutable biovecs changed the DM_IO_BVEC iterator to
    DM_IO_BIO.  Before this change the iterator stored the pointer to a bio
    vector in the dpages structure.  The iterator incremented the pointer in
    the dpages structure as it advanced over the pages.  After the immutable
    biovecs change, the DM_IO_BIO iterator stores a pointer to the bio in
    the dpages structure and uses bio_advance to change the bio as it
    advances.
    
    The problem is that the function dispatch_io stores the content of the
    dpages structure into the variable old_pages and restores it before
    issuing I/O to each of the devices.  Before the change, the statement
    "*dp = old_pages;" restored the iterator to its starting position.
    After the change, struct dpages holds a pointer to the bio, thus the
    statement "*dp = old_pages;" doesn't restore the iterator.
    
    Consequently, in the context of dm-mirror: only the first mirror leg is
    written correctly, the kernel locks up when trying to write the other
    mirror legs because the number of sectors to write in the where->count
    variable doesn't match the number of sectors returned by the iterator.
    
    This patch fixes the bug by partially reverting the original patch - it
    changes the code so that struct dpages holds a pointer to the bio vector,
    so that the statement "*dp = old_pages;" restores the iterator correctly.
    
    The field "context_u" holds the offset from the beginning of the current
    bio vector entry, just like the "bio->bi_iter.bi_bvec_done" field.
    
    Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
    Signed-off-by: Mike Snitzer <snitzer@redhat.com>
---
 drivers/md/dm-io.c |   23 +++++++++++------------
 1 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index b2b8a10..3842ac7 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -201,29 +201,28 @@ static void list_dp_init(struct dpages *dp, struct page_list *pl, unsigned offse
 /*
  * Functions for getting the pages from a bvec.
  */
-static void bio_get_page(struct dpages *dp,
-		  struct page **p, unsigned long *len, unsigned *offset)
+static void bio_get_page(struct dpages *dp, struct page **p,
+			 unsigned long *len, unsigned *offset)
 {
-	struct bio *bio = dp->context_ptr;
-	struct bio_vec bvec = bio_iovec(bio);
-	*p = bvec.bv_page;
-	*len = bvec.bv_len;
-	*offset = bvec.bv_offset;
+	struct bio_vec *bvec = dp->context_ptr;
+	*p = bvec->bv_page;
+	*len = bvec->bv_len - dp->context_u;
+	*offset = bvec->bv_offset + dp->context_u;
 }
 
 static void bio_next_page(struct dpages *dp)
 {
-	struct bio *bio = dp->context_ptr;
-	struct bio_vec bvec = bio_iovec(bio);
-
-	bio_advance(bio, bvec.bv_len);
+	struct bio_vec *bvec = dp->context_ptr;
+	dp->context_ptr = bvec + 1;
+	dp->context_u = 0;
 }
 
 static void bio_dp_init(struct dpages *dp, struct bio *bio)
 {
 	dp->get_page = bio_get_page;
 	dp->next_page = bio_next_page;
-	dp->context_ptr = bio;
+	dp->context_ptr = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
+	dp->context_u = bio->bi_iter.bi_bvec_done;
 }
 
 /*
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic