Commit 4a5bb973 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-linus-5.10b-rc1b-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip

Pull more xen updates from Juergen Gross:

 - A single patch to fix the Xen security issue XSA-331 (malicious
   guests can DoS dom0 by triggering NULL-pointer dereferences or access
   to stale data).

 - A larger series to fix the Xen security issue XSA-332 (malicious
   guests can DoS dom0 by sending events at high frequency leading to
   dom0's vcpus being busy in IRQ handling for elongated times).

* tag 'for-linus-5.10b-rc1b-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  xen/events: block rogue events for some time
  xen/events: defer eoi in case of excessive number of events
  xen/events: use a common cpu hotplug hook for event channels
  xen/events: switch user event channels to lateeoi model
  xen/pciback: use lateeoi irq binding
  xen/pvcallsback: use lateeoi irq binding
  xen/scsiback: use lateeoi irq binding
  xen/netback: use lateeoi irq binding
  xen/blkback: use lateeoi irq binding
  xen/events: add a new "late EOI" evtchn framework
  xen/events: fix race in evtchn_fifo_unmask()
  xen/events: add a proper barrier to 2-level uevent unmasking
  xen/events: avoid removing an event channel while handling it
parents 709ebe6d 5f7f7740
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -5970,6 +5970,14 @@
			improve timer resolution at the expense of processing
			more timer interrupts.

	xen.event_eoi_delay=	[XEN]
			How long to delay EOI handling in case of event
			storms (jiffies). Default is 10.

	xen.event_loop_timeout=	[XEN]
			After which time (jiffies) the event handling loop
			should start to delay EOI handling. Default is 2.

	nopv=		[X86,XEN,KVM,HYPER_V,VMWARE]
			Disables the PV optimizations forcing the guest to run
			as generic guest with no PV drivers. Currently support
+17 −5
Original line number Diff line number Diff line
@@ -201,7 +201,7 @@ static inline void shrink_free_pagepool(struct xen_blkif_ring *ring, int num)

#define vaddr(page) ((unsigned long)pfn_to_kaddr(page_to_pfn(page)))

static int do_block_io_op(struct xen_blkif_ring *ring);
static int do_block_io_op(struct xen_blkif_ring *ring, unsigned int *eoi_flags);
static int dispatch_rw_block_io(struct xen_blkif_ring *ring,
				struct blkif_request *req,
				struct pending_req *pending_req);
@@ -612,6 +612,8 @@ int xen_blkif_schedule(void *arg)
	struct xen_vbd *vbd = &blkif->vbd;
	unsigned long timeout;
	int ret;
	bool do_eoi;
	unsigned int eoi_flags = XEN_EOI_FLAG_SPURIOUS;

	set_freezable();
	while (!kthread_should_stop()) {
@@ -636,16 +638,23 @@ int xen_blkif_schedule(void *arg)
		if (timeout == 0)
			goto purge_gnt_list;

		do_eoi = ring->waiting_reqs;

		ring->waiting_reqs = 0;
		smp_mb(); /* clear flag *before* checking for work */

		ret = do_block_io_op(ring);
		ret = do_block_io_op(ring, &eoi_flags);
		if (ret > 0)
			ring->waiting_reqs = 1;
		if (ret == -EACCES)
			wait_event_interruptible(ring->shutdown_wq,
						 kthread_should_stop());

		if (do_eoi && !ring->waiting_reqs) {
			xen_irq_lateeoi(ring->irq, eoi_flags);
			eoi_flags |= XEN_EOI_FLAG_SPURIOUS;
		}

purge_gnt_list:
		if (blkif->vbd.feature_gnt_persistent &&
		    time_after(jiffies, ring->next_lru)) {
@@ -1121,7 +1130,7 @@ static void end_block_io_op(struct bio *bio)
 * and transmute  it to the block API to hand it over to the proper block disk.
 */
static int
__do_block_io_op(struct xen_blkif_ring *ring)
__do_block_io_op(struct xen_blkif_ring *ring, unsigned int *eoi_flags)
{
	union blkif_back_rings *blk_rings = &ring->blk_rings;
	struct blkif_request req;
@@ -1144,6 +1153,9 @@ __do_block_io_op(struct xen_blkif_ring *ring)
		if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc))
			break;

		/* We've seen a request, so clear spurious eoi flag. */
		*eoi_flags &= ~XEN_EOI_FLAG_SPURIOUS;

		if (kthread_should_stop()) {
			more_to_do = 1;
			break;
@@ -1202,13 +1214,13 @@ done:
}

static int
do_block_io_op(struct xen_blkif_ring *ring)
do_block_io_op(struct xen_blkif_ring *ring, unsigned int *eoi_flags)
{
	union blkif_back_rings *blk_rings = &ring->blk_rings;
	int more_to_do;

	do {
		more_to_do = __do_block_io_op(ring);
		more_to_do = __do_block_io_op(ring, eoi_flags);
		if (more_to_do)
			break;

+2 −3
Original line number Diff line number Diff line
@@ -246,9 +246,8 @@ static int xen_blkif_map(struct xen_blkif_ring *ring, grant_ref_t *gref,
	if (req_prod - rsp_prod > size)
		goto fail;

	err = bind_interdomain_evtchn_to_irqhandler(blkif->domid, evtchn,
						    xen_blkif_be_int, 0,
						    "blkif-backend", ring);
	err = bind_interdomain_evtchn_to_irqhandler_lateeoi(blkif->domid,
			evtchn, xen_blkif_be_int, 0, "blkif-backend", ring);
	if (err < 0)
		goto fail;
	ring->irq = err;
+15 −0
Original line number Diff line number Diff line
@@ -140,6 +140,20 @@ struct xenvif_queue { /* Per-queue data for xenvif */
	char name[QUEUE_NAME_SIZE]; /* DEVNAME-qN */
	struct xenvif *vif; /* Parent VIF */

	/*
	 * TX/RX common EOI handling.
	 * When feature-split-event-channels = 0, interrupt handler sets
	 * NETBK_COMMON_EOI, otherwise NETBK_RX_EOI and NETBK_TX_EOI are set
	 * by the RX and TX interrupt handlers.
	 * RX and TX handler threads will issue an EOI when either
	 * NETBK_COMMON_EOI or their specific bits (NETBK_RX_EOI or
	 * NETBK_TX_EOI) are set and they will reset those bits.
	 */
	atomic_t eoi_pending;
#define NETBK_RX_EOI		0x01
#define NETBK_TX_EOI		0x02
#define NETBK_COMMON_EOI	0x04

	/* Use NAPI for guest TX */
	struct napi_struct napi;
	/* When feature-split-event-channels = 0, tx_irq = rx_irq. */
@@ -378,6 +392,7 @@ int xenvif_dealloc_kthread(void *data);

irqreturn_t xenvif_ctrl_irq_fn(int irq, void *data);

bool xenvif_have_rx_work(struct xenvif_queue *queue, bool test_kthread);
void xenvif_rx_action(struct xenvif_queue *queue);
void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb);

+52 −9
Original line number Diff line number Diff line
@@ -77,12 +77,28 @@ int xenvif_schedulable(struct xenvif *vif)
		!vif->disabled;
}

static bool xenvif_handle_tx_interrupt(struct xenvif_queue *queue)
{
	bool rc;

	rc = RING_HAS_UNCONSUMED_REQUESTS(&queue->tx);
	if (rc)
		napi_schedule(&queue->napi);
	return rc;
}

static irqreturn_t xenvif_tx_interrupt(int irq, void *dev_id)
{
	struct xenvif_queue *queue = dev_id;
	int old;

	if (RING_HAS_UNCONSUMED_REQUESTS(&queue->tx))
		napi_schedule(&queue->napi);
	old = atomic_fetch_or(NETBK_TX_EOI, &queue->eoi_pending);
	WARN(old & NETBK_TX_EOI, "Interrupt while EOI pending\n");

	if (!xenvif_handle_tx_interrupt(queue)) {
		atomic_andnot(NETBK_TX_EOI, &queue->eoi_pending);
		xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS);
	}

	return IRQ_HANDLED;
}
@@ -116,19 +132,46 @@ static int xenvif_poll(struct napi_struct *napi, int budget)
	return work_done;
}

static bool xenvif_handle_rx_interrupt(struct xenvif_queue *queue)
{
	bool rc;

	rc = xenvif_have_rx_work(queue, false);
	if (rc)
		xenvif_kick_thread(queue);
	return rc;
}

static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id)
{
	struct xenvif_queue *queue = dev_id;
	int old;

	xenvif_kick_thread(queue);
	old = atomic_fetch_or(NETBK_RX_EOI, &queue->eoi_pending);
	WARN(old & NETBK_RX_EOI, "Interrupt while EOI pending\n");

	if (!xenvif_handle_rx_interrupt(queue)) {
		atomic_andnot(NETBK_RX_EOI, &queue->eoi_pending);
		xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS);
	}

	return IRQ_HANDLED;
}

irqreturn_t xenvif_interrupt(int irq, void *dev_id)
{
	xenvif_tx_interrupt(irq, dev_id);
	xenvif_rx_interrupt(irq, dev_id);
	struct xenvif_queue *queue = dev_id;
	int old;

	old = atomic_fetch_or(NETBK_COMMON_EOI, &queue->eoi_pending);
	WARN(old, "Interrupt while EOI pending\n");

	/* Use bitwise or as we need to call both functions. */
	if ((!xenvif_handle_tx_interrupt(queue) |
	     !xenvif_handle_rx_interrupt(queue))) {
		atomic_andnot(NETBK_COMMON_EOI, &queue->eoi_pending);
		xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS);
	}

	return IRQ_HANDLED;
}
@@ -605,7 +648,7 @@ int xenvif_connect_ctrl(struct xenvif *vif, grant_ref_t ring_ref,
	if (req_prod - rsp_prod > RING_SIZE(&vif->ctrl))
		goto err_unmap;

	err = bind_interdomain_evtchn_to_irq(vif->domid, evtchn);
	err = bind_interdomain_evtchn_to_irq_lateeoi(vif->domid, evtchn);
	if (err < 0)
		goto err_unmap;

@@ -709,7 +752,7 @@ int xenvif_connect_data(struct xenvif_queue *queue,

	if (tx_evtchn == rx_evtchn) {
		/* feature-split-event-channels == 0 */
		err = bind_interdomain_evtchn_to_irqhandler(
		err = bind_interdomain_evtchn_to_irqhandler_lateeoi(
			queue->vif->domid, tx_evtchn, xenvif_interrupt, 0,
			queue->name, queue);
		if (err < 0)
@@ -720,7 +763,7 @@ int xenvif_connect_data(struct xenvif_queue *queue,
		/* feature-split-event-channels == 1 */
		snprintf(queue->tx_irq_name, sizeof(queue->tx_irq_name),
			 "%s-tx", queue->name);
		err = bind_interdomain_evtchn_to_irqhandler(
		err = bind_interdomain_evtchn_to_irqhandler_lateeoi(
			queue->vif->domid, tx_evtchn, xenvif_tx_interrupt, 0,
			queue->tx_irq_name, queue);
		if (err < 0)
@@ -730,7 +773,7 @@ int xenvif_connect_data(struct xenvif_queue *queue,

		snprintf(queue->rx_irq_name, sizeof(queue->rx_irq_name),
			 "%s-rx", queue->name);
		err = bind_interdomain_evtchn_to_irqhandler(
		err = bind_interdomain_evtchn_to_irqhandler_lateeoi(
			queue->vif->domid, rx_evtchn, xenvif_rx_interrupt, 0,
			queue->rx_irq_name, queue);
		if (err < 0)
Loading