xen/blkfront: read response from backend only once
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>
This commit is contained in:
parent
30dcc56bba
commit
71b66243f9
1 changed files with 18 additions and 17 deletions
|
@ -1496,7 +1496,7 @@ static bool blkif_completion(unsigned long *id,
|
||||||
static irqreturn_t blkif_interrupt(int irq, void *dev_id)
|
static irqreturn_t blkif_interrupt(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct request *req;
|
struct request *req;
|
||||||
struct blkif_response *bret;
|
struct blkif_response bret;
|
||||||
RING_IDX i, rp;
|
RING_IDX i, rp;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct blkfront_ring_info *rinfo = (struct blkfront_ring_info *)dev_id;
|
struct blkfront_ring_info *rinfo = (struct blkfront_ring_info *)dev_id;
|
||||||
|
@ -1513,8 +1513,9 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
|
||||||
for (i = rinfo->ring.rsp_cons; i != rp; i++) {
|
for (i = rinfo->ring.rsp_cons; i != rp; i++) {
|
||||||
unsigned long id;
|
unsigned long id;
|
||||||
|
|
||||||
bret = RING_GET_RESPONSE(&rinfo->ring, i);
|
RING_COPY_RESPONSE(&rinfo->ring, i, &bret);
|
||||||
id = bret->id;
|
id = bret.id;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The backend has messed up and given us an id that we would
|
* 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 -
|
* never have given to it (we stamp it up to BLK_RING_SIZE -
|
||||||
|
@ -1522,39 +1523,39 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
|
||||||
*/
|
*/
|
||||||
if (id >= BLK_RING_SIZE(info)) {
|
if (id >= BLK_RING_SIZE(info)) {
|
||||||
WARN(1, "%s: response to %s has incorrect id (%ld)\n",
|
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
|
/* We can't safely get the 'struct request' as
|
||||||
* the id is busted. */
|
* the id is busted. */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
req = rinfo->shadow[id].request;
|
req = rinfo->shadow[id].request;
|
||||||
|
|
||||||
if (bret->operation != BLKIF_OP_DISCARD) {
|
if (bret.operation != BLKIF_OP_DISCARD) {
|
||||||
/*
|
/*
|
||||||
* We may need to wait for an extra response if the
|
* We may need to wait for an extra response if the
|
||||||
* I/O request is split in 2
|
* I/O request is split in 2
|
||||||
*/
|
*/
|
||||||
if (!blkif_completion(&id, rinfo, bret))
|
if (!blkif_completion(&id, rinfo, &bret))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (add_id_to_freelist(rinfo, id)) {
|
if (add_id_to_freelist(rinfo, id)) {
|
||||||
WARN(1, "%s: response to %s (id %ld) couldn't be recycled!\n",
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bret->status == BLKIF_RSP_OKAY)
|
if (bret.status == BLKIF_RSP_OKAY)
|
||||||
blkif_req(req)->error = BLK_STS_OK;
|
blkif_req(req)->error = BLK_STS_OK;
|
||||||
else
|
else
|
||||||
blkif_req(req)->error = BLK_STS_IOERR;
|
blkif_req(req)->error = BLK_STS_IOERR;
|
||||||
|
|
||||||
switch (bret->operation) {
|
switch (bret.operation) {
|
||||||
case BLKIF_OP_DISCARD:
|
case BLKIF_OP_DISCARD:
|
||||||
if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
|
if (unlikely(bret.status == BLKIF_RSP_EOPNOTSUPP)) {
|
||||||
struct request_queue *rq = info->rq;
|
struct request_queue *rq = info->rq;
|
||||||
printk(KERN_WARNING "blkfront: %s: %s op failed\n",
|
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));
|
||||||
blkif_req(req)->error = BLK_STS_NOTSUPP;
|
blkif_req(req)->error = BLK_STS_NOTSUPP;
|
||||||
info->feature_discard = 0;
|
info->feature_discard = 0;
|
||||||
info->feature_secdiscard = 0;
|
info->feature_secdiscard = 0;
|
||||||
|
@ -1564,15 +1565,15 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
|
||||||
break;
|
break;
|
||||||
case BLKIF_OP_FLUSH_DISKCACHE:
|
case BLKIF_OP_FLUSH_DISKCACHE:
|
||||||
case BLKIF_OP_WRITE_BARRIER:
|
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",
|
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));
|
||||||
blkif_req(req)->error = BLK_STS_NOTSUPP;
|
blkif_req(req)->error = BLK_STS_NOTSUPP;
|
||||||
}
|
}
|
||||||
if (unlikely(bret->status == BLKIF_RSP_ERROR &&
|
if (unlikely(bret.status == BLKIF_RSP_ERROR &&
|
||||||
rinfo->shadow[id].req.u.rw.nr_segments == 0)) {
|
rinfo->shadow[id].req.u.rw.nr_segments == 0)) {
|
||||||
printk(KERN_WARNING "blkfront: %s: empty %s op failed\n",
|
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));
|
||||||
blkif_req(req)->error = BLK_STS_NOTSUPP;
|
blkif_req(req)->error = BLK_STS_NOTSUPP;
|
||||||
}
|
}
|
||||||
if (unlikely(blkif_req(req)->error)) {
|
if (unlikely(blkif_req(req)->error)) {
|
||||||
|
@ -1585,9 +1586,9 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
|
||||||
fallthrough;
|
fallthrough;
|
||||||
case BLKIF_OP_READ:
|
case BLKIF_OP_READ:
|
||||||
case BLKIF_OP_WRITE:
|
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 "
|
dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
|
||||||
"request: %x\n", bret->status);
|
"request: %x\n", bret.status);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Add table
Reference in a new issue