]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
dm mpath: fix missing call of path selector type->end_io
authorYufen Yu <yuyufen@huawei.com>
Wed, 24 Apr 2019 15:19:05 +0000 (23:19 +0800)
committerKhalid Elmously <khalid.elmously@canonical.com>
Thu, 26 Sep 2019 04:34:52 +0000 (00:34 -0400)
BugLink: https://bugs.launchpad.net/bugs/1844558
[ Upstream commit 5de719e3d01b4abe0de0d7b857148a880ff2a90b ]

After commit 396eaf21ee17 ("blk-mq: improve DM's blk-mq IO merging via
blk_insert_cloned_request feedback"), map_request() will requeue the tio
when issued clone request return BLK_STS_RESOURCE or BLK_STS_DEV_RESOURCE.

Thus, if device driver status is error, a tio may be requeued multiple
times until the return value is not DM_MAPIO_REQUEUE.  That means
type->start_io may be called multiple times, while type->end_io is only
called when IO complete.

In fact, even without commit 396eaf21ee17, setup_clone() failure can
also cause tio requeue and associated missed call to type->end_io.

The service-time path selector selects path based on in_flight_size,
which is increased by st_start_io() and decreased by st_end_io().
Missed calls to st_end_io() can lead to in_flight_size count error and
will cause the selector to make the wrong choice.  In addition,
queue-length path selector will also be affected.

To fix the problem, call type->end_io in ->release_clone_rq before tio
requeue.  map_info is passed to ->release_clone_rq() for map_request()
error path that result in requeue.

Fixes: 396eaf21ee17 ("blk-mq: improve DM's blk-mq IO merging via blk_insert_cloned_request feedback")
Cc: stable@vger.kernl.org
Signed-off-by: Yufen Yu <yuyufen@huawei.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
drivers/md/dm-mpath.c
drivers/md/dm-rq.c
drivers/md/dm-target.c
include/linux/device-mapper.h

index a3223c8fbaacc290c8457b49a20ea2a5f10419f4..bafcf53f47a99651cb2105838b4edd3596932afe 100644 (file)
@@ -561,8 +561,23 @@ static int multipath_clone_and_map(struct dm_target *ti, struct request *rq,
        return DM_MAPIO_REMAPPED;
 }
 
-static void multipath_release_clone(struct request *clone)
+static void multipath_release_clone(struct request *clone,
+                                   union map_info *map_context)
 {
+       if (unlikely(map_context)) {
+               /*
+                * non-NULL map_context means caller is still map
+                * method; must undo multipath_clone_and_map()
+                */
+               struct dm_mpath_io *mpio = get_mpio(map_context);
+               struct pgpath *pgpath = mpio->pgpath;
+
+               if (pgpath && pgpath->pg->ps.type->end_io)
+                       pgpath->pg->ps.type->end_io(&pgpath->pg->ps,
+                                                   &pgpath->path,
+                                                   mpio->nr_bytes);
+       }
+
        blk_put_request(clone);
 }
 
index 9d32f25489c27ad1fc743d387e19f8fa5a67cf25..6f3c88b26d558a35f2bcc0d6d984cd2c6c7053ad 100644 (file)
@@ -219,7 +219,7 @@ static void dm_end_request(struct request *clone, blk_status_t error)
        struct request *rq = tio->orig;
 
        blk_rq_unprep_clone(clone);
-       tio->ti->type->release_clone_rq(clone);
+       tio->ti->type->release_clone_rq(clone, NULL);
 
        rq_end_stats(md, rq);
        if (!rq->q->mq_ops)
@@ -270,7 +270,7 @@ static void dm_requeue_original_request(struct dm_rq_target_io *tio, bool delay_
        rq_end_stats(md, rq);
        if (tio->clone) {
                blk_rq_unprep_clone(tio->clone);
-               tio->ti->type->release_clone_rq(tio->clone);
+               tio->ti->type->release_clone_rq(tio->clone, NULL);
        }
 
        if (!rq->q->mq_ops)
@@ -485,7 +485,7 @@ static int map_request(struct dm_rq_target_io *tio)
        case DM_MAPIO_REMAPPED:
                if (setup_clone(clone, rq, tio, GFP_ATOMIC)) {
                        /* -ENOMEM */
-                       ti->type->release_clone_rq(clone);
+                       ti->type->release_clone_rq(clone, &tio->info);
                        return DM_MAPIO_REQUEUE;
                }
 
index c0d7e60820c45d5c3bcfcf1ebaa0bfed1e530448..89eaf2ff499f518290bec46ee8a7aa2943617455 100644 (file)
@@ -138,7 +138,8 @@ static int io_err_clone_and_map_rq(struct dm_target *ti, struct request *rq,
        return DM_MAPIO_KILL;
 }
 
-static void io_err_release_clone_rq(struct request *clone)
+static void io_err_release_clone_rq(struct request *clone,
+                                   union map_info *map_context)
 {
 }
 
index 91a063a1f3b3719844e1c46e28546a86b2f048a6..de839f619e5a506b751eb656f8e25c06061e6648 100644 (file)
@@ -61,7 +61,8 @@ typedef int (*dm_clone_and_map_request_fn) (struct dm_target *ti,
                                            struct request *rq,
                                            union map_info *map_context,
                                            struct request **clone);
-typedef void (*dm_release_clone_request_fn) (struct request *clone);
+typedef void (*dm_release_clone_request_fn) (struct request *clone,
+                                            union map_info *map_context);
 
 /*
  * Returns: