| From foo@baz Mon Nov 29 07:12:46 PM CET 2021 |
| From: Juergen Gross <jgross@suse.com> |
| Date: Mon, 29 Nov 2021 13:46:12 +0100 |
| Subject: xen/blkfront: read response from backend only once |
| |
| From: Juergen Gross <jgross@suse.com> |
| |
| commit 71b66243f9898d0e54296b4e7035fb33cdcb0707 upstream. |
| |
| In order to avoid problems in case the backend is modifying a response |
| on the ring page while the frontend has already seen it, just read the |
| response into a local buffer in one go and then operate on that buffer |
| only. |
| |
| Signed-off-by: Juergen Gross <jgross@suse.com> |
| Reviewed-by: Jan Beulich <jbeulich@suse.com> |
| Acked-by: Roger Pau Monné <roger.pau@citrix.com> |
| Link: https://lore.kernel.org/r/20210730103854.12681-2-jgross@suse.com |
| Signed-off-by: Juergen Gross <jgross@suse.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/block/xen-blkfront.c | 35 ++++++++++++++++++----------------- |
| 1 file changed, 18 insertions(+), 17 deletions(-) |
| |
| --- a/drivers/block/xen-blkfront.c |
| +++ b/drivers/block/xen-blkfront.c |
| @@ -1296,7 +1296,7 @@ static void blkif_completion(struct blk_ |
| static irqreturn_t blkif_interrupt(int irq, void *dev_id) |
| { |
| struct request *req; |
| - struct blkif_response *bret; |
| + struct blkif_response bret; |
| RING_IDX i, rp; |
| unsigned long flags; |
| struct blkfront_info *info = (struct blkfront_info *)dev_id; |
| @@ -1316,8 +1316,9 @@ static irqreturn_t blkif_interrupt(int i |
| for (i = info->ring.rsp_cons; i != rp; i++) { |
| unsigned long id; |
| |
| - bret = RING_GET_RESPONSE(&info->ring, i); |
| - id = bret->id; |
| + RING_COPY_RESPONSE(&info->ring, i, &bret); |
| + id = bret.id; |
| + |
| /* |
| * The backend has messed up and given us an id that we would |
| * never have given to it (we stamp it up to BLK_RING_SIZE - |
| @@ -1325,29 +1326,29 @@ static irqreturn_t blkif_interrupt(int i |
| */ |
| if (id >= BLK_RING_SIZE(info)) { |
| WARN(1, "%s: response to %s has incorrect id (%ld)\n", |
| - info->gd->disk_name, op_name(bret->operation), id); |
| + info->gd->disk_name, op_name(bret.operation), id); |
| /* We can't safely get the 'struct request' as |
| * the id is busted. */ |
| continue; |
| } |
| req = info->shadow[id].request; |
| |
| - if (bret->operation != BLKIF_OP_DISCARD) |
| - blkif_completion(&info->shadow[id], info, bret); |
| + if (bret.operation != BLKIF_OP_DISCARD) |
| + blkif_completion(&info->shadow[id], info, &bret); |
| |
| if (add_id_to_freelist(info, id)) { |
| WARN(1, "%s: response to %s (id %ld) couldn't be recycled!\n", |
| - info->gd->disk_name, op_name(bret->operation), id); |
| + info->gd->disk_name, op_name(bret.operation), id); |
| continue; |
| } |
| |
| - error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO; |
| - switch (bret->operation) { |
| + error = (bret.status == BLKIF_RSP_OKAY) ? 0 : -EIO; |
| + switch (bret.operation) { |
| case BLKIF_OP_DISCARD: |
| - if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { |
| + if (unlikely(bret.status == BLKIF_RSP_EOPNOTSUPP)) { |
| struct request_queue *rq = info->rq; |
| printk(KERN_WARNING "blkfront: %s: %s op failed\n", |
| - info->gd->disk_name, op_name(bret->operation)); |
| + info->gd->disk_name, op_name(bret.operation)); |
| error = -EOPNOTSUPP; |
| info->feature_discard = 0; |
| info->feature_secdiscard = 0; |
| @@ -1358,15 +1359,15 @@ static irqreturn_t blkif_interrupt(int i |
| break; |
| case BLKIF_OP_FLUSH_DISKCACHE: |
| case BLKIF_OP_WRITE_BARRIER: |
| - if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { |
| + if (unlikely(bret.status == BLKIF_RSP_EOPNOTSUPP)) { |
| printk(KERN_WARNING "blkfront: %s: %s op failed\n", |
| - info->gd->disk_name, op_name(bret->operation)); |
| + info->gd->disk_name, op_name(bret.operation)); |
| error = -EOPNOTSUPP; |
| } |
| - if (unlikely(bret->status == BLKIF_RSP_ERROR && |
| + if (unlikely(bret.status == BLKIF_RSP_ERROR && |
| info->shadow[id].req.u.rw.nr_segments == 0)) { |
| printk(KERN_WARNING "blkfront: %s: empty %s op failed\n", |
| - info->gd->disk_name, op_name(bret->operation)); |
| + info->gd->disk_name, op_name(bret.operation)); |
| error = -EOPNOTSUPP; |
| } |
| if (unlikely(error)) { |
| @@ -1378,9 +1379,9 @@ static irqreturn_t blkif_interrupt(int i |
| /* fall through */ |
| case BLKIF_OP_READ: |
| case BLKIF_OP_WRITE: |
| - if (unlikely(bret->status != BLKIF_RSP_OKAY)) |
| + if (unlikely(bret.status != BLKIF_RSP_OKAY)) |
| dev_dbg(&info->xbdev->dev, "Bad return from blkdev data " |
| - "request: %x\n", bret->status); |
| + "request: %x\n", bret.status); |
| |
| blk_mq_complete_request(req, error); |
| break; |