diff options
Diffstat (limited to 'drivers/md/dm.c')
-rw-r--r-- | drivers/md/dm.c | 25 |
1 files changed, 19 insertions, 6 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 724efc63904d..d7786e3514cd 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -614,8 +614,10 @@ static void dec_pending(struct dm_io *io, int error) if (!md->barrier_error && io_error != -EOPNOTSUPP) md->barrier_error = io_error; end_io_acct(io); + free_io(md, io); } else { end_io_acct(io); + free_io(md, io); if (io_error != DM_ENDIO_REQUEUE) { trace_block_bio_complete(md->queue, bio); @@ -623,8 +625,6 @@ static void dec_pending(struct dm_io *io, int error) bio_endio(bio, io_error); } } - - free_io(md, io); } } @@ -1487,10 +1487,15 @@ static int dm_prep_fn(struct request_queue *q, struct request *rq) return BLKPREP_OK; } -static void map_request(struct dm_target *ti, struct request *rq, - struct mapped_device *md) +/* + * Returns: + * 0 : the request has been processed (not requeued) + * !0 : the request has been requeued + */ +static int map_request(struct dm_target *ti, struct request *rq, + struct mapped_device *md) { - int r; + int r, requeued = 0; struct request *clone = rq->special; struct dm_rq_target_io *tio = clone->end_io_data; @@ -1516,6 +1521,7 @@ static void map_request(struct dm_target *ti, struct request *rq, case DM_MAPIO_REQUEUE: /* The target wants to requeue the I/O */ dm_requeue_unmapped_request(clone); + requeued = 1; break; default: if (r > 0) { @@ -1527,6 +1533,8 @@ static void map_request(struct dm_target *ti, struct request *rq, dm_kill_unmapped_request(clone, r); break; } + + return requeued; } /* @@ -1568,12 +1576,17 @@ static void dm_request_fn(struct request_queue *q) blk_start_request(rq); spin_unlock(q->queue_lock); - map_request(ti, rq, md); + if (map_request(ti, rq, md)) + goto requeued; + spin_lock_irq(q->queue_lock); } goto out; +requeued: + spin_lock_irq(q->queue_lock); + plug_and_out: if (!elv_queue_empty(q)) /* Some requests still remain, retry later */ |