From: Mike Snitzer <snit...@redhat.com>

[ Upstream commit cd15fb64ee56192760ad5c1e2ad97a65e735b18b ]

This reverts commit 12a7cf5ba6c776a2621d8972c7d42e8d3d959d20.

This commit apparently attempted to fix an issue that didn't really
exist, furthermore: this commit is the source of deadlocks and crashes
seen in multiple cases related to failing the primary mirror dev while
syncing.

Reported-by: Jonathan Brassow <jbras...@redhat.com>
Signed-off-by: Mike Snitzer <snit...@redhat.com>
Signed-off-by: Sasha Levin <alexander.le...@microsoft.com>
---
 drivers/md/dm-raid1.c | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 9a8b71067c6e..7a6254d54baf 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -145,6 +145,7 @@ static void dispatch_bios(void *context, struct bio_list 
*bio_list)
 
 struct dm_raid1_bio_record {
        struct mirror *m;
+       /* if details->bi_bdev == NULL, details were not saved */
        struct dm_bio_details details;
        region_t write_region;
 };
@@ -1199,6 +1200,8 @@ static int mirror_map(struct dm_target *ti, struct bio 
*bio)
        struct dm_raid1_bio_record *bio_record =
          dm_per_bio_data(bio, sizeof(struct dm_raid1_bio_record));
 
+       bio_record->details.bi_bdev = NULL;
+
        if (rw == WRITE) {
                /* Save region for mirror_end_io() handler */
                bio_record->write_region = dm_rh_bio_to_region(ms->rh, bio);
@@ -1257,12 +1260,22 @@ static int mirror_end_io(struct dm_target *ti, struct 
bio *bio, int error)
        }
 
        if (error == -EOPNOTSUPP)
-               return error;
+               goto out;
 
        if ((error == -EWOULDBLOCK) && (bio->bi_opf & REQ_RAHEAD))
-               return error;
+               goto out;
 
        if (unlikely(error)) {
+               if (!bio_record->details.bi_bdev) {
+                       /*
+                        * There wasn't enough memory to record necessary
+                        * information for a retry or there was no other
+                        * mirror in-sync.
+                        */
+                       DMERR_LIMIT("Mirror read failed.");
+                       return -EIO;
+               }
+
                m = bio_record->m;
 
                DMERR("Mirror read failed from %s. Trying alternative device.",
@@ -1278,6 +1291,7 @@ static int mirror_end_io(struct dm_target *ti, struct bio 
*bio, int error)
                        bd = &bio_record->details;
 
                        dm_bio_restore(bd, bio);
+                       bio_record->details.bi_bdev = NULL;
                        bio->bi_error = 0;
 
                        queue_bio(ms, bio, rw);
@@ -1286,6 +1300,9 @@ static int mirror_end_io(struct dm_target *ti, struct bio 
*bio, int error)
                DMERR("All replicated volumes dead, failing I/O");
        }
 
+out:
+       bio_record->details.bi_bdev = NULL;
+
        return error;
 }
 
-- 
2.15.1

Reply via email to