Commit 86991b6e authored by Juergen Gross's avatar Juergen Gross

xen/scsiback: use lateeoi irq binding

In order to reduce the chance for the system becoming unresponsive due
to event storms triggered by a misbehaving scsifront use the lateeoi
irq binding for scsiback and unmask the event channel only just before
leaving the event handling function.

In case of a ring protocol error don't issue an EOI in order to avoid
the possibility to use that for producing an event storm. This at once
will result in no further call of scsiback_irq_fn(), so the ring_error
struct member can be dropped and scsiback_do_cmd_fn() can signal the
protocol error via a negative return value.

This is part of XSA-332.

Cc: stable@vger.kernel.org
Reported-by: default avatarJulien Grall <julien@xen.org>
Signed-off-by: default avatarJuergen Gross <jgross@suse.com>
Reviewed-by: default avatarJan Beulich <jbeulich@suse.com>
Reviewed-by: default avatarWei Liu <wl@xen.org>
parent 23025393
...@@ -91,7 +91,6 @@ struct vscsibk_info { ...@@ -91,7 +91,6 @@ struct vscsibk_info {
unsigned int irq; unsigned int irq;
struct vscsiif_back_ring ring; struct vscsiif_back_ring ring;
int ring_error;
spinlock_t ring_lock; spinlock_t ring_lock;
atomic_t nr_unreplied_reqs; atomic_t nr_unreplied_reqs;
...@@ -722,7 +721,8 @@ static struct vscsibk_pend *prepare_pending_reqs(struct vscsibk_info *info, ...@@ -722,7 +721,8 @@ static struct vscsibk_pend *prepare_pending_reqs(struct vscsibk_info *info,
return pending_req; return pending_req;
} }
static int scsiback_do_cmd_fn(struct vscsibk_info *info) static int scsiback_do_cmd_fn(struct vscsibk_info *info,
unsigned int *eoi_flags)
{ {
struct vscsiif_back_ring *ring = &info->ring; struct vscsiif_back_ring *ring = &info->ring;
struct vscsiif_request ring_req; struct vscsiif_request ring_req;
...@@ -739,11 +739,12 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info) ...@@ -739,11 +739,12 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
rc = ring->rsp_prod_pvt; rc = ring->rsp_prod_pvt;
pr_warn("Dom%d provided bogus ring requests (%#x - %#x = %u). Halting ring processing\n", pr_warn("Dom%d provided bogus ring requests (%#x - %#x = %u). Halting ring processing\n",
info->domid, rp, rc, rp - rc); info->domid, rp, rc, rp - rc);
info->ring_error = 1; return -EINVAL;
return 0;
} }
while ((rc != rp)) { while ((rc != rp)) {
*eoi_flags &= ~XEN_EOI_FLAG_SPURIOUS;
if (RING_REQUEST_CONS_OVERFLOW(ring, rc)) if (RING_REQUEST_CONS_OVERFLOW(ring, rc))
break; break;
...@@ -802,13 +803,16 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info) ...@@ -802,13 +803,16 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
static irqreturn_t scsiback_irq_fn(int irq, void *dev_id) static irqreturn_t scsiback_irq_fn(int irq, void *dev_id)
{ {
struct vscsibk_info *info = dev_id; struct vscsibk_info *info = dev_id;
int rc;
unsigned int eoi_flags = XEN_EOI_FLAG_SPURIOUS;
if (info->ring_error) while ((rc = scsiback_do_cmd_fn(info, &eoi_flags)) > 0)
return IRQ_HANDLED;
while (scsiback_do_cmd_fn(info))
cond_resched(); cond_resched();
/* In case of a ring error we keep the event channel masked. */
if (!rc)
xen_irq_lateeoi(irq, eoi_flags);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -829,7 +833,7 @@ static int scsiback_init_sring(struct vscsibk_info *info, grant_ref_t ring_ref, ...@@ -829,7 +833,7 @@ static int scsiback_init_sring(struct vscsibk_info *info, grant_ref_t ring_ref,
sring = (struct vscsiif_sring *)area; sring = (struct vscsiif_sring *)area;
BACK_RING_INIT(&info->ring, sring, PAGE_SIZE); BACK_RING_INIT(&info->ring, sring, PAGE_SIZE);
err = bind_interdomain_evtchn_to_irq(info->domid, evtchn); err = bind_interdomain_evtchn_to_irq_lateeoi(info->domid, evtchn);
if (err < 0) if (err < 0)
goto unmap_page; goto unmap_page;
...@@ -1253,7 +1257,6 @@ static int scsiback_probe(struct xenbus_device *dev, ...@@ -1253,7 +1257,6 @@ static int scsiback_probe(struct xenbus_device *dev,
info->domid = dev->otherend_id; info->domid = dev->otherend_id;
spin_lock_init(&info->ring_lock); spin_lock_init(&info->ring_lock);
info->ring_error = 0;
atomic_set(&info->nr_unreplied_reqs, 0); atomic_set(&info->nr_unreplied_reqs, 0);
init_waitqueue_head(&info->waiting_to_free); init_waitqueue_head(&info->waiting_to_free);
info->dev = dev; info->dev = dev;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment