Received: by 2002:a25:8b12:0:0:0:0:0 with SMTP id i18csp423367ybl; Fri, 30 Aug 2019 01:44:38 -0700 (PDT) X-Google-Smtp-Source: APXvYqzx17IqHDFGgUhTT4d9HFDJTc+PPf+zYiSnFJ5ea9tc2ZPaas8m8gP2QqDncJxIVtUTHLJ8 X-Received: by 2002:a65:4546:: with SMTP id x6mr11864560pgr.266.1567154678658; Fri, 30 Aug 2019 01:44:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1567154678; cv=none; d=google.com; s=arc-20160816; b=qyMNbeTpPzIobkvBI7+b/W1ctbcYFwvQpsOcLWKtG1/kO94ETm1yR5Ozvwh6URvx/o SgTj6/PV9lZKasdh1Ekz3DqeljyQSpdga6KuHIGHg4yBVy673alOFbS9wIvOFkIAdsIA h0HDKqIj120Idn5c2EK96EjrEkfkYPbArjvRSu7VRQoyL4uLAqr2WSnx9x9MPX9buekf fh0HM5Ag763bAOOGfjYlkSLDthvusEV65I40QefG6QQqazC/LTAtQGqKZQrj1cf/tG6r RB7yVoAZcfCOesfzEc5DU45azdULypsxHkw1TsDlWttwSEdPw8LDC2Odb9HN/OCQ6Xy5 FgwA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from; bh=9CIEb3/nwguvTfKFXn3HhULf2vnH9bFyeMIya5b3cWI=; b=SYzPbl43gfMIbrEFxGkTxi5GpUKzWfCpjTU5dnqY23nr/jobM1OFOUfwKKHZ53O8AQ 6+J4gGPP60d2azz0FE+U91K5j/VMUxcpaQUvzJ/91kq0f9UdHQVGH6sPTiiySkfHpbkv Ue6UwpkmWBCTlPn8gZTw7G0+tbRRj8DSsTG3GtCxuIq44gLdNLBYJkz+P2Bfe0hcCP5o wnTEAJBLp/YJSN8sGMRSp2pPugKL1KU0qWG7mdfCYlS2ISC+SpHMGBb3kO1yF9bSalOH zsn/VGpis2EBpH3MJ3MF9vNakxc5bUVMwXdlqwfTwpx6RdPO960Z+42u+vMUzFDNcbk3 WV6A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=alibaba.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id n9si3993804pgq.240.2019.08.30.01.44.22; Fri, 30 Aug 2019 01:44:38 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=alibaba.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727741AbfH3Ilx (ORCPT + 99 others); Fri, 30 Aug 2019 04:41:53 -0400 Received: from out30-45.freemail.mail.aliyun.com ([115.124.30.45]:34271 "EHLO out30-45.freemail.mail.aliyun.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726200AbfH3Ilw (ORCPT ); Fri, 30 Aug 2019 04:41:52 -0400 X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R741e4;CH=green;DM=||false|;FP=0|-1|-1|-1|0|-1|-1|-1;HT=e01f04391;MF=luoben@linux.alibaba.com;NM=1;PH=DS;RN=6;SR=0;TI=SMTPD_---0TaqsQFe_1567154503; Received: from localhost(mailfrom:luoben@linux.alibaba.com fp:SMTPD_---0TaqsQFe_1567154503) by smtp.aliyun-inc.com(127.0.0.1); Fri, 30 Aug 2019 16:41:46 +0800 From: Ben Luo To: tglx@linutronix.de, alex.williamson@redhat.com Cc: linux-kernel@vger.kernel.org, tao.ma@linux.alibaba.com, gerry@linux.alibaba.com, nanhai.zou@linux.alibaba.com Subject: [PATCH v5 2/3] genirq: introduce irq_update_devid() Date: Fri, 30 Aug 2019 16:41:43 +0800 Message-Id: X-Mailer: git-send-email 1.8.3.1 In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Sometimes, only the dev_id field of irqaction needs to be changed. E.g. KVM VM with device passthru via VFIO may switch the interrupt injection path between KVM irqfd and userspace eventfd. These two paths share the same interrupt number and handler for the same msi vector of a device, only with different 'dev_id's referencing to different fds' contexts. Set interrupt affinity in this VM is a way to trigger the path switching. Currently, VFIO uses a free-then-request-irq way for the path switching. There is a time window between free_irq() and request_irq() where the target IRTE is invalid. So, in-flight interrupts (buffering in hardware layer and unfortunately cannot be synchronized in software) can cause DMAR faults and even worse, this VM may hang in waiting IO completion. By using irq_update_devid(), this issue can be avoided since IRTE will not be invalidated during the whole process. Signed-off-by: Ben Luo --- include/linux/interrupt.h | 3 ++ kernel/irq/manage.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 5b8328a..09b6a0f 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -172,6 +172,9 @@ struct irqaction { request_percpu_nmi(unsigned int irq, irq_handler_t handler, const char *devname, void __percpu *dev); +extern int __must_check +irq_update_devid(unsigned int irq, void *dev_id, void *new_dev_id); + extern const void *free_irq(unsigned int, void *); extern void free_percpu_irq(unsigned int, void __percpu *); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 10ec3e9..adb1980 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -2063,6 +2063,81 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, EXPORT_SYMBOL(request_threaded_irq); /** + * irq_update_devid - update irq dev_id to a new one + * + * @irq: Interrupt line to update + * @dev_id: A cookie to find the irqaction to update + * @new_dev_id: New cookie passed to the handler function + * + * Sometimes, only the cookie data need to be changed. Instead of + * free-then-request interrupt, only update dev_id of irqaction can + * not only gain some performance benefit, but also reduce the risk + * of losing interrupt. + * + * This function won't update dev_id until any executing interrupts + * for this IRQ have completed. This function must not be called + * from interrupt context. + * + * On failure, it returns a negative value. On success, + * it returns 0 + */ +int irq_update_devid(unsigned int irq, void *dev_id, void *new_dev_id) +{ + struct irq_desc *desc = irq_to_desc(irq); + struct irqaction *action, **action_ptr; + unsigned long flags; + + if (WARN(in_interrupt(), + "Trying to update IRQ %d (dev_id %p to %p) from IRQ context!\n", + irq, dev_id, new_dev_id)) + return -EPERM; + + if (!desc) + return -EINVAL; + + /* + * Ensure that an interrupt in flight on another CPU which uses the + * old 'dev_id' has completed because the caller can free the memory + * to which it points after this function returns. And also avoid to + * update 'dev_id' in the middle of a threaded interrupt process, it + * can lead to a twist that primary handler uses old 'dev_id' but new + * 'dev_id' is used by secondary handler. + */ + disable_irq(irq); + raw_spin_lock_irqsave(&desc->lock, flags); + + /* + * There can be multiple actions per IRQ descriptor, find the right + * one based on the dev_id: + */ + action_ptr = &desc->action; + for (;;) { + action = *action_ptr; + + if (!action) { + raw_spin_unlock_irqrestore(&desc->lock, flags); + enable_irq(irq); + WARN(1, + "Trying to update already-free IRQ %d (dev_id %p to %p)\n", + irq, dev_id, new_dev_id); + return -ENXIO; + } + + if (action->dev_id == dev_id) { + action->dev_id = new_dev_id; + break; + } + action_ptr = &action->next; + } + + raw_spin_unlock_irqrestore(&desc->lock, flags); + enable_irq(irq); + + return 0; +} +EXPORT_SYMBOL_GPL(irq_update_devid); + +/** * request_any_context_irq - allocate an interrupt line * @irq: Interrupt line to allocate * @handler: Function to be called when the IRQ occurs. -- 1.8.3.1