From: Kiyoshi Ueda <k-ueda@xxxxxxxxxxxxx> This patch implements the pushback feature for the multipath target. The pushback request is used when: 1) there are no valid paths; 2) queue_if_no_path was set; 3) a suspend is being issued with the DMF_NOFLUSH_SUSPENDING flag. Otherwise bios are returned to applications with -EIO. To check whether queue_if_no_path is specified or not, you need to check both queue_if_no_path and saved_queue_if_no_path, because presuspend saves the original queue_if_no_path value to saved_queue_if_no_path. The check for 1 already exists in both map_io() and do_end_io(). So this patch adds __must_push_back() to check 2 and 3. Test results: See the test results in the preceding patch. Signed-off-by: Kiyoshi Ueda <k-ueda@xxxxxxxxxxxxx> Signed-off-by: Jun'ichi Nomura <j-nomura@xxxxxxxxxxxxx> Signed-off-by: Alasdair G Kergon <agk@xxxxxxxxxx> Cc: dm-devel@xxxxxxxxxx Index: linux-2.6.19-rc6/drivers/md/dm-mpath.c =================================================================== --- linux-2.6.19-rc6.orig/drivers/md/dm-mpath.c 2006-11-22 17:26:58.000000000 +0000 +++ linux-2.6.19-rc6/drivers/md/dm-mpath.c 2006-11-22 17:27:00.000000000 +0000 @@ -282,6 +282,23 @@ failed: m->current_pg = NULL; } +/* + * Check whether bios must be queued in the device-mapper core rather + * than here in the target. + * + * m->lock must be held on entry. + * + * If m->queue_if_no_path and m->saved_queue_if_no_path hold the + * same value then we are not between multipath_presuspend() + * and multipath_resume() calls and we have no need to check + * for the DMF_NOFLUSH_SUSPENDING flag. + */ +static int __must_push_back(struct multipath *m) +{ + return (m->queue_if_no_path != m->saved_queue_if_no_path && + dm_noflush_suspending(m->ti)); +} + static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio, unsigned was_queued) { @@ -311,10 +328,12 @@ static int map_io(struct multipath *m, s queue_work(kmultipathd, &m->process_queued_ios); pgpath = NULL; r = DM_MAPIO_SUBMITTED; - } else if (!pgpath) - r = -EIO; /* Failed */ - else + } else if (pgpath) bio->bi_bdev = pgpath->path.dev->bdev; + else if (__must_push_back(m)) + r = DM_MAPIO_REQUEUE; + else + r = -EIO; /* Failed */ mpio->pgpath = pgpath; @@ -374,6 +393,8 @@ static void dispatch_queued_ios(struct m bio_endio(bio, bio->bi_size, r); else if (r == DM_MAPIO_REMAPPED) generic_make_request(bio); + else if (r == DM_MAPIO_REQUEUE) + bio_endio(bio, bio->bi_size, -EIO); bio = next; } @@ -781,7 +802,7 @@ static int multipath_map(struct dm_targe map_context->ptr = mpio; bio->bi_rw |= (1 << BIO_RW_FAILFAST); r = map_io(m, bio, mpio, 0); - if (r < 0) + if (r < 0 || r == DM_MAPIO_REQUEUE) mempool_free(mpio, m->mpio_pool); return r; @@ -1005,7 +1026,10 @@ static int do_end_io(struct multipath *m spin_lock_irqsave(&m->lock, flags); if (!m->nr_valid_paths) { - if (!m->queue_if_no_path) { + if (__must_push_back(m)) { + spin_unlock_irqrestore(&m->lock, flags); + return DM_ENDIO_REQUEUE; + } else if (!m->queue_if_no_path) { spin_unlock_irqrestore(&m->lock, flags); return -EIO; } else { -- dm-devel mailing list dm-devel@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/dm-devel