Received: by 2002:a25:8b12:0:0:0:0:0 with SMTP id i18csp1169390ybl; Thu, 22 Aug 2019 10:18:44 -0700 (PDT) X-Google-Smtp-Source: APXvYqydIT7F62/sACBkEJvYh4Tp79mzv3KP9LtrEDrI7/nnAs5wU5BL1/ob3g/IOisgotrJqh/z X-Received: by 2002:a17:902:7842:: with SMTP id e2mr9663861pln.49.1566494324385; Thu, 22 Aug 2019 10:18:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1566494324; cv=none; d=google.com; s=arc-20160816; b=Y6G01aYxuqXGzZ+iBFXhkJwYlKhcAZlCkmPBoAP6v2rCWck9ptOhKW0QDigBXW/cqo L+6OB8DTX56XsVhTapqesiRYoLP1AkdlTU6tApMy4CD9V76SWoFm9f0SaWFYAQNNP9y1 AQl8TWnUt2698HRmMySQ/xAx9J7frveTkOD4eKcqSfOa+76DOnve/sgqazlusL3K9Zno g6NlXlRwmnWHzPLp8e2AjkLITmLVCVQa/70lligMhcK3ASdN0r/qcuuB7v6VHxeKQcCl Dq+62wmnr6/bp2iUUoGRY/NGhai7e21Ij54e0VJZIlDaRQC5zBxLSQqzwkVPo8wFBZQk zQQQ== 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:references :in-reply-to:message-id:date:subject:cc:to:from; bh=9CIEb3/nwguvTfKFXn3HhULf2vnH9bFyeMIya5b3cWI=; b=XdO6KxE2BGy2k8Gmi62ypK3P33fjqyca9EjGPNfDttAA0SWdlHn/aIOkHEwtmUUVmX ZCidSbvsAjPcK5SDpFE1mltorkqunnmMu14T20AGcOku2enE0YvVW9+I053FWhDKfjD7 R9pF02Ba1FCQvWldmp6U9vBIKMvUWSPvaLBGjsmPU0Lx48kxwzAlYgw+WeEO0kKwY0zU txoEb5h1DOw6Q0+UZ65OxJeOXZXwomVg/sHatoRRnALFrO1kLB6zQnBiD7eYShgLXlkO syuX3evM88bQ6OiFRZMQn/cIw7si5m0N1Qj6TgvYTVxTWjNWsGf8qlg5MoQc/+z4xM/H OOpQ== 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 w7si16988054pgl.323.2019.08.22.10.18.28; Thu, 22 Aug 2019 10:18:44 -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 S2389229AbfHVPfL (ORCPT + 99 others); Thu, 22 Aug 2019 11:35:11 -0400 Received: from out30-45.freemail.mail.aliyun.com ([115.124.30.45]:53671 "EHLO out30-45.freemail.mail.aliyun.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731907AbfHVPfL (ORCPT ); Thu, 22 Aug 2019 11:35:11 -0400 X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R101e4;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=7;SR=0;TI=SMTPD_---0Ta8p3Z9_1566488099; Received: from localhost(mailfrom:luoben@linux.alibaba.com fp:SMTPD_---0Ta8p3Z9_1566488099) by smtp.aliyun-inc.com(127.0.0.1); Thu, 22 Aug 2019 23:35:05 +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, linyunsheng@huawei.com Subject: [PATCH v4 2/3] genirq: introduce irq_update_devid() Date: Thu, 22 Aug 2019 23:34:42 +0800 Message-Id: X-Mailer: git-send-email 1.8.3.1 In-Reply-To: References: 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