diff options
author | Mike Snitzer <snitzer@redhat.com> | 2015-04-29 10:48:09 -0400 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2015-04-30 10:25:21 -0400 |
commit | aa6df8dd28c01d9a3d2cfcfe9dd0a4a334d1cd81 (patch) | |
tree | 80ee42fd298572758a252c8024e1dcc2e11f58a2 | |
parent | 3e6180f0c82b3790a9ec6d13d67aae359bf1ce84 (diff) |
dm: fix free_rq_clone() NULL pointer when requeueing unmapped request
Commit 022333427a ("dm: optimize dm_mq_queue_rq to _not_ use kthread if
using pure blk-mq") mistakenly removed free_rq_clone()'s clone->q check
before testing clone->q->mq_ops. It was an oversight to discontinue
that check for 1 of the 2 use-cases for free_rq_clone():
1) free_rq_clone() called when an unmapped original request is requeued
2) free_rq_clone() called in the request-based IO completion path
The clone->q check made sense for case #1 but not for #2. However, we
cannot just reinstate the check as it'd mask a serious bug in the IO
completion case #2 -- no in-flight request should have an uninitialized
request_queue (basic block layer refcounting _should_ ensure this).
The NULL pointer seen for case #1 is detailed here:
https://www.redhat.com/archives/dm-devel/2015-April/msg00160.html
Fix this free_rq_clone() NULL pointer by simply checking if the
mapped_device's type is DM_TYPE_MQ_REQUEST_BASED (clone's queue is
blk-mq) rather than checking clone->q->mq_ops. This avoids the need to
dereference clone->q, but a WARN_ON_ONCE is added to let us know if an
uninitialized clone request is being completed.
Reported-by: Bart Van Assche <bart.vanassche@sandisk.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
-rw-r--r-- | drivers/md/dm.c | 16 |
1 files changed, 12 insertions, 4 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 923496ba72a0..a930b72314ac 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -1082,18 +1082,26 @@ static void rq_completed(struct mapped_device *md, int rw, bool run_queue) | |||
1082 | dm_put(md); | 1082 | dm_put(md); |
1083 | } | 1083 | } |
1084 | 1084 | ||
1085 | static void free_rq_clone(struct request *clone) | 1085 | static void free_rq_clone(struct request *clone, bool must_be_mapped) |
1086 | { | 1086 | { |
1087 | struct dm_rq_target_io *tio = clone->end_io_data; | 1087 | struct dm_rq_target_io *tio = clone->end_io_data; |
1088 | struct mapped_device *md = tio->md; | 1088 | struct mapped_device *md = tio->md; |
1089 | 1089 | ||
1090 | WARN_ON_ONCE(must_be_mapped && !clone->q); | ||
1091 | |||
1090 | blk_rq_unprep_clone(clone); | 1092 | blk_rq_unprep_clone(clone); |
1091 | 1093 | ||
1092 | if (clone->q->mq_ops) | 1094 | if (md->type == DM_TYPE_MQ_REQUEST_BASED) |
1095 | /* stacked on blk-mq queue(s) */ | ||
1093 | tio->ti->type->release_clone_rq(clone); | 1096 | tio->ti->type->release_clone_rq(clone); |
1094 | else if (!md->queue->mq_ops) | 1097 | else if (!md->queue->mq_ops) |
1095 | /* request_fn queue stacked on request_fn queue(s) */ | 1098 | /* request_fn queue stacked on request_fn queue(s) */ |
1096 | free_clone_request(md, clone); | 1099 | free_clone_request(md, clone); |
1100 | /* | ||
1101 | * NOTE: for the blk-mq queue stacked on request_fn queue(s) case: | ||
1102 | * no need to call free_clone_request() because we leverage blk-mq by | ||
1103 | * allocating the clone at the end of the blk-mq pdu (see: clone_rq) | ||
1104 | */ | ||
1097 | 1105 | ||
1098 | if (!md->queue->mq_ops) | 1106 | if (!md->queue->mq_ops) |
1099 | free_rq_tio(tio); | 1107 | free_rq_tio(tio); |
@@ -1124,7 +1132,7 @@ static void dm_end_request(struct request *clone, int error) | |||
1124 | rq->sense_len = clone->sense_len; | 1132 | rq->sense_len = clone->sense_len; |
1125 | } | 1133 | } |
1126 | 1134 | ||
1127 | free_rq_clone(clone); | 1135 | free_rq_clone(clone, true); |
1128 | if (!rq->q->mq_ops) | 1136 | if (!rq->q->mq_ops) |
1129 | blk_end_request_all(rq, error); | 1137 | blk_end_request_all(rq, error); |
1130 | else | 1138 | else |
@@ -1143,7 +1151,7 @@ static void dm_unprep_request(struct request *rq) | |||
1143 | } | 1151 | } |
1144 | 1152 | ||
1145 | if (clone) | 1153 | if (clone) |
1146 | free_rq_clone(clone); | 1154 | free_rq_clone(clone, false); |
1147 | } | 1155 | } |
1148 | 1156 | ||
1149 | /* | 1157 | /* |