diff options
author | Christoph Hellwig <hch@lst.de> | 2015-09-27 15:01:50 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2015-10-01 04:10:55 -0400 |
commit | f4829a9b7a61e159367350008a608b062c4f6840 (patch) | |
tree | a2f488a95324e0c0b558273f48b18413ab2fa221 /drivers/block/xen-blkfront.c | |
parent | 60de074ba1e8f327db19bc33d8530131ac01695d (diff) |
blk-mq: fix racy updates of rq->errors
blk_mq_complete_request may be a no-op if the request has already
been completed by others means (e.g. a timeout or cancellation), but
currently drivers have to set rq->errors before calling
blk_mq_complete_request, which might leave us with the wrong error value.
Add an error parameter to blk_mq_complete_request so that we can
defer setting rq->errors until we known we won the race to complete the
request.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Sagi Grimberg <sagig@mellanox.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/block/xen-blkfront.c')
-rw-r--r-- | drivers/block/xen-blkfront.c | 19 |
1 files changed, 10 insertions, 9 deletions
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 0823a96902f8..611170896b8c 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c | |||
@@ -1142,6 +1142,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) | |||
1142 | RING_IDX i, rp; | 1142 | RING_IDX i, rp; |
1143 | unsigned long flags; | 1143 | unsigned long flags; |
1144 | struct blkfront_info *info = (struct blkfront_info *)dev_id; | 1144 | struct blkfront_info *info = (struct blkfront_info *)dev_id; |
1145 | int error; | ||
1145 | 1146 | ||
1146 | spin_lock_irqsave(&info->io_lock, flags); | 1147 | spin_lock_irqsave(&info->io_lock, flags); |
1147 | 1148 | ||
@@ -1182,37 +1183,37 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) | |||
1182 | continue; | 1183 | continue; |
1183 | } | 1184 | } |
1184 | 1185 | ||
1185 | req->errors = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO; | 1186 | error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO; |
1186 | switch (bret->operation) { | 1187 | switch (bret->operation) { |
1187 | case BLKIF_OP_DISCARD: | 1188 | case BLKIF_OP_DISCARD: |
1188 | if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { | 1189 | if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { |
1189 | struct request_queue *rq = info->rq; | 1190 | struct request_queue *rq = info->rq; |
1190 | printk(KERN_WARNING "blkfront: %s: %s op failed\n", | 1191 | printk(KERN_WARNING "blkfront: %s: %s op failed\n", |
1191 | info->gd->disk_name, op_name(bret->operation)); | 1192 | info->gd->disk_name, op_name(bret->operation)); |
1192 | req->errors = -EOPNOTSUPP; | 1193 | error = -EOPNOTSUPP; |
1193 | info->feature_discard = 0; | 1194 | info->feature_discard = 0; |
1194 | info->feature_secdiscard = 0; | 1195 | info->feature_secdiscard = 0; |
1195 | queue_flag_clear(QUEUE_FLAG_DISCARD, rq); | 1196 | queue_flag_clear(QUEUE_FLAG_DISCARD, rq); |
1196 | queue_flag_clear(QUEUE_FLAG_SECDISCARD, rq); | 1197 | queue_flag_clear(QUEUE_FLAG_SECDISCARD, rq); |
1197 | } | 1198 | } |
1198 | blk_mq_complete_request(req); | 1199 | blk_mq_complete_request(req, error); |
1199 | break; | 1200 | break; |
1200 | case BLKIF_OP_FLUSH_DISKCACHE: | 1201 | case BLKIF_OP_FLUSH_DISKCACHE: |
1201 | case BLKIF_OP_WRITE_BARRIER: | 1202 | case BLKIF_OP_WRITE_BARRIER: |
1202 | if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { | 1203 | if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { |
1203 | printk(KERN_WARNING "blkfront: %s: %s op failed\n", | 1204 | printk(KERN_WARNING "blkfront: %s: %s op failed\n", |
1204 | info->gd->disk_name, op_name(bret->operation)); | 1205 | info->gd->disk_name, op_name(bret->operation)); |
1205 | req->errors = -EOPNOTSUPP; | 1206 | error = -EOPNOTSUPP; |
1206 | } | 1207 | } |
1207 | if (unlikely(bret->status == BLKIF_RSP_ERROR && | 1208 | if (unlikely(bret->status == BLKIF_RSP_ERROR && |
1208 | info->shadow[id].req.u.rw.nr_segments == 0)) { | 1209 | info->shadow[id].req.u.rw.nr_segments == 0)) { |
1209 | printk(KERN_WARNING "blkfront: %s: empty %s op failed\n", | 1210 | printk(KERN_WARNING "blkfront: %s: empty %s op failed\n", |
1210 | info->gd->disk_name, op_name(bret->operation)); | 1211 | info->gd->disk_name, op_name(bret->operation)); |
1211 | req->errors = -EOPNOTSUPP; | 1212 | error = -EOPNOTSUPP; |
1212 | } | 1213 | } |
1213 | if (unlikely(req->errors)) { | 1214 | if (unlikely(error)) { |
1214 | if (req->errors == -EOPNOTSUPP) | 1215 | if (error == -EOPNOTSUPP) |
1215 | req->errors = 0; | 1216 | error = 0; |
1216 | info->feature_flush = 0; | 1217 | info->feature_flush = 0; |
1217 | xlvbd_flush(info); | 1218 | xlvbd_flush(info); |
1218 | } | 1219 | } |
@@ -1223,7 +1224,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) | |||
1223 | dev_dbg(&info->xbdev->dev, "Bad return from blkdev data " | 1224 | dev_dbg(&info->xbdev->dev, "Bad return from blkdev data " |
1224 | "request: %x\n", bret->status); | 1225 | "request: %x\n", bret->status); |
1225 | 1226 | ||
1226 | blk_mq_complete_request(req); | 1227 | blk_mq_complete_request(req, error); |
1227 | break; | 1228 | break; |
1228 | default: | 1229 | default: |
1229 | BUG(); | 1230 | BUG(); |