Message ID | 72609f999d9451c13240acb8e4a4e54f8c62f542.camel@infradead.org |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:612c:2908:b0:403:3b70:6f57 with SMTP id ib8csp4464115vqb; Tue, 17 Oct 2023 16:47:34 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFajYVL+7j9LutSIESYDxYo1pU8ca534lZrOk3Wcm+XQRTyEcd62BFT66GxmC09FYgGpsej X-Received: by 2002:a17:902:d04c:b0:1b8:2ba0:c9a8 with SMTP id l12-20020a170902d04c00b001b82ba0c9a8mr3732716pll.2.1697586454094; Tue, 17 Oct 2023 16:47:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1697586454; cv=none; d=google.com; s=arc-20160816; b=l5bf2deJr1UdhyQoO1YZeaLpD/p0n/TPujklN7PJdsLun+6JYLjH6QiQ304fDclx7V eDuJWLF/ER3PgOO9YAghpWUQmC8cY7lvAdf4RhmGkfrEoeQ0/e+Zf+EIKe3VvA5iyzKU cXd6l75MAf4QSu0CU1QE/e8fPT8Mj0wFhJMb7KcskqDpO7PIbvu6H0+J1ppXJJd5blaJ TcVEPEhMxcrrDfCQb670kAbXumMzXy/ii8qgdZ1tvVT/pUVdu3E2QFFdiNtBwGw2zNUQ +wQDa8k9/qdFmKFYI8zq3YKFn3kvSZyGNFMV/IiIiIWf/+XD77KC+eZUVGJKvvl/gl/P Jx/A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:user-agent:date:cc:to:from:subject :message-id:dkim-signature; bh=UyDAj6MCb5OdE6yv5OJjKtOf1V/fjbGh/bOznPBpmTU=; fh=BgcY1D3DHguwwMlsBxugvTbQIXojhAHTsBgu36Mc6cA=; b=Ejld6Oy1HvvMB5MZXgoWjQIj/xRXn6V2GQAmtZyJ8xrahDZ/A2KGwTVi2LJaTn3SvF ZFZHZUHfDz16NTKDRdP5GfTQIZ5ze52J9iFJo4x086S600mzAqrqR3/P6XbOUwNat55E 4VYMl8ITndjTR2WMkEERtwSaQenlVTQXGNFRvqICu4yu3rExge3ZqrSBo1NtSv687QUi xNm3hvZnP9hSsu+kuN3Nfp0Gz18U1p8PkABFtXQNnWALMfzmLeu5bXhckhcKuNoorSYZ kD/z0EzmDQImtsibuGlx1vTtjj91r7nCm28mBKM6AlFt7WtVvPQwZsl+X3wW1prLOaGR U6Yg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@infradead.org header.s=casper.20170209 header.b=S2xRRGbv; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.38 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from fry.vger.email (fry.vger.email. [23.128.96.38]) by mx.google.com with ESMTPS id j12-20020a17090276cc00b001b8c4021be9si2794744plt.397.2023.10.17.16.47.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Oct 2023 16:47:33 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.38 as permitted sender) client-ip=23.128.96.38; Authentication-Results: mx.google.com; dkim=pass header.i=@infradead.org header.s=casper.20170209 header.b=S2xRRGbv; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.38 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by fry.vger.email (Postfix) with ESMTP id 8739780FCBE8; Tue, 17 Oct 2023 16:47:31 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at fry.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344338AbjJQXrO (ORCPT <rfc822;winker.wchi@gmail.com> + 22 others); Tue, 17 Oct 2023 19:47:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51770 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230219AbjJQXrN (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Tue, 17 Oct 2023 19:47:13 -0400 Received: from casper.infradead.org (casper.infradead.org [IPv6:2001:8b0:10b:1236::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 368C898; Tue, 17 Oct 2023 16:47:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=MIME-Version:Content-Type:Date:Cc:To: From:Subject:Message-ID:Sender:Reply-To:Content-Transfer-Encoding:Content-ID: Content-Description:In-Reply-To:References; bh=UyDAj6MCb5OdE6yv5OJjKtOf1V/fjbGh/bOznPBpmTU=; b=S2xRRGbvCIRDPTVLWsTxb6+4J0 rM0LeuRIgJXuilG8Ccms/UjP7yHbHHxrMqnETE9bL0CZcqXTSXG2ocAEu/bZ6ZTyCD8ME2bNF5Lcb r+kjjk3FaEh/aNifZIQvn/rvQmRekQ5rlbEC9lPHYmcYg9aLHQUn5svdmHJGdj7Zvo6ZnfmHy9JoT TCQ74hJ8BF6rqO9wmZSXlZ9HDJWicOMHu36/22lvtu+sKE94fIdQdAU8bhruK/uEfZ9JU6w5zbUF+ vLtHAnwvPyysMIgNpBIF2qbq4/OepGYDUXa+ZUD5jADp5HeQ5qEhWH/EGIyaBsWFS0v4fz0+C7IVc hpD6vRXQ==; Received: from [2001:8b0:10b:5:b9aa:f92b:5d4c:b38] (helo=u3832b3a9db3152.ant.amazon.com) by casper.infradead.org with esmtpsa (Exim 4.94.2 #2 (Red Hat Linux)) id 1qstm1-00FENl-21; Tue, 17 Oct 2023 23:46:53 +0000 Message-ID: <72609f999d9451c13240acb8e4a4e54f8c62f542.camel@infradead.org> Subject: [PATCH] hvc/xen: fix event channel handling for secondary consoles From: David Woodhouse <dwmw2@infradead.org> To: Juergen Gross <jgross@suse.com>, xen-devel <xen-devel@lists.xenproject.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Jiri Slaby <jirislaby@kernel.org>, Roger Pau Monne <roger.pau@citrix.com>, Stefano Stabellini <sstabellini@kernel.org>, Dawei Li <set_pte_at@outlook.com>, linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org, Paul Durrant <paul@xen.org> Date: Wed, 18 Oct 2023 00:46:52 +0100 Content-Type: multipart/signed; micalg="sha-256"; protocol="application/pkcs7-signature"; boundary="=-Mjqe1h5Eoof5Yi3p4u/3" User-Agent: Evolution 3.44.4-0ubuntu2 MIME-Version: 1.0 X-SRS-Rewrite: SMTP reverse-path rewritten from <dwmw2@infradead.org> by casper.infradead.org. See http://www.infradead.org/rpr.html X-Spam-Status: No, score=-0.8 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on fry.vger.email Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (fry.vger.email [0.0.0.0]); Tue, 17 Oct 2023 16:47:31 -0700 (PDT) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1780048413611889891 X-GMAIL-MSGID: 1780048413611889891 |
Series |
hvc/xen: fix event channel handling for secondary consoles
|
|
Commit Message
David Woodhouse
Oct. 17, 2023, 11:46 p.m. UTC
From: David Woodhouse <dwmw@amazon.co.uk> The xencons_connect_backend() function allocates a local interdomain event channel with xenbus_alloc_evtchn(), then calls bind_interdomain_evtchn_to_irq_lateeoi() to bind to that port# on the *remote* domain. That doesn't work very well: (qemu) device_add xen-console,id=con1,chardev=pty0 [ 44.323872] xenconsole console-1: 2 xenbus_dev_probe on device/console/1 [ 44.323995] xenconsole: probe of console-1 failed with error -2 Fix it to use bind_evtchn_to_irq_lateeoi(), which does the right thing by just binding that *local* event channel to an irq. The backend will do the interdomain binding. This didn't affect the primary console because the setup for that is special — the toolstack allocates the guest event channel and the guest discovers it with HVMOP_get_param. Once that's fixed, there's also a warning on hot-unplug because xencons_disconnect_backend() unconditionally calls free_irq() via unbind_from_irqhandler(): (qemu) device_del con1 [ 32.050919] ------------[ cut here ]------------ [ 32.050942] Trying to free already-free IRQ 33 [ 32.050990] WARNING: CPU: 0 PID: 51 at kernel/irq/manage.c:1895 __free_irq+0x1d4/0x330 Fix that by calling notifier_del_irq() first, which only calls free_irq() if the irq was requested in the first place. Then use evtchn_put() to release the irq and event channel. Avoid calling xenbus_free_evtchn() in the normal case, as evtchn_put() will do that too. The only time xenbus_free_evtchn() needs to be called is for the cleanup when bind_evtchn_to_irq_lateeoi() fails. Finally, fix the error path in xen_hvc_init() when there's no primary console. It should still register the frontend driver, as there may be secondary consoles. (Qemu can always add secondary consoles, but only the toolstack can add the primary because it's special.) Fixes: fe415186b4 ("xen/console: harden hvc_xen against event channel storms") Signed-off-by: David Woodhouse <dwmw@amazon.co.uk> Cc: stable@vger.kernel.org --- Untested on actual Xen. drivers/tty/hvc/hvc_xen.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
Comments
On 18.10.23 01:46, David Woodhouse wrote: > From: David Woodhouse <dwmw@amazon.co.uk> > > The xencons_connect_backend() function allocates a local interdomain > event channel with xenbus_alloc_evtchn(), then calls > bind_interdomain_evtchn_to_irq_lateeoi() to bind to that port# on the > *remote* domain. > > That doesn't work very well: > > (qemu) device_add xen-console,id=con1,chardev=pty0 > [ 44.323872] xenconsole console-1: 2 xenbus_dev_probe on device/console/1 > [ 44.323995] xenconsole: probe of console-1 failed with error -2 > > Fix it to use bind_evtchn_to_irq_lateeoi(), which does the right thing > by just binding that *local* event channel to an irq. The backend will > do the interdomain binding. > > This didn't affect the primary console because the setup for that is > special — the toolstack allocates the guest event channel and the guest > discovers it with HVMOP_get_param. > > Once that's fixed, there's also a warning on hot-unplug because > xencons_disconnect_backend() unconditionally calls free_irq() via > unbind_from_irqhandler(): > > (qemu) device_del con1 > [ 32.050919] ------------[ cut here ]------------ > [ 32.050942] Trying to free already-free IRQ 33 > [ 32.050990] WARNING: CPU: 0 PID: 51 at kernel/irq/manage.c:1895 __free_irq+0x1d4/0x330 > > Fix that by calling notifier_del_irq() first, which only calls > free_irq() if the irq was requested in the first place. Then use I don't think the "if the irq was requested in the first place" is the correct reasoning. I think the problem is that notifier_del_irq() will be called another time through the .notifier_del hook. Two calls of notifier_del_irq() are fine, but one call of it and another call of free_irq() via unbind_from_irqhandler() is a problem. > evtchn_put() to release the irq and event channel. Avoid calling > xenbus_free_evtchn() in the normal case, as evtchn_put() will do that > too. The only time xenbus_free_evtchn() needs to be called is for the > cleanup when bind_evtchn_to_irq_lateeoi() fails. > > Finally, fix the error path in xen_hvc_init() when there's no primary > console. It should still register the frontend driver, as there may be > secondary consoles. (Qemu can always add secondary consoles, but only > the toolstack can add the primary because it's special.) > > Fixes: fe415186b4 ("xen/console: harden hvc_xen against event channel storms") > Signed-off-by: David Woodhouse <dwmw@amazon.co.uk> > Cc: stable@vger.kernel.org With above fixed in the commit message: Reviewed-by: Juergen Gross <jgross@suse.com> Juergen
On Fri, 2023-10-20 at 10:51 +0200, Juergen Gross wrote: > > > (qemu) device_del con1 > > [ 32.050919] ------------[ cut here ]------------ > > [ 32.050942] Trying to free already-free IRQ 33 > > [ 32.050990] WARNING: CPU: 0 PID: 51 at kernel/irq/manage.c:1895 __free_irq+0x1d4/0x330 > > > > Fix that by calling notifier_del_irq() first, which only calls > > free_irq() if the irq was requested in the first place. Then use > > I don't think the "if the irq was requested in the first place" is the correct > reasoning. > > I think the problem is that notifier_del_irq() will be called another time > through the .notifier_del hook. Two calls of notifier_del_irq() are fine, but > one call of it and another call of free_irq() via unbind_from_irqhandler() is > a problem. Er... yes, the HVC tty device still exists, can still be open and in use by userspace during the time that xencons_disconnect_backend() is running. Why does xencons_disconnect_backend() do all the evtchn and gnttab teardown *first* and then only call hvc_remove() at the end. That seems weird. So if I do 'dd if=/dev/zero of=/dev/hvc1' while I remove the device from qemu... yep, that seems to have filled the ring after the evtchn was torn down, and it's waiting for ever in domU_write_console(). In fact, that isn't *even* because of the race within xencons_disconnect_backend(). In xencons_backend_changed() when the backend goes into state XenbusStateClos{ing,ed} for the disconnect, we just set the frontend state directly to XenbusStateClosed without even *calling* xencons_disconnect_backend(). So we were *told* of the impending unplug. We fail to actually stop using the device, but we tell the backend that it's OK to go away. Oops :) The incremental patch below makes it work if I unplug a console while writing /dev/zero to it. But I suspect instead of calling xencons_disconnect_backend() when the backend changes to XenbusStateClos{ing,ed}, it should actually *just* do the hvc_close() part? The evtchn and gnttab cleanup should wait until the backend has actually finished closing? And what locking is there around xencons_disconnect_backend() anyway? Do we rely on the fact that it can all only happen from the xenstore watch thread? diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index f0376612b267..0806078835f6 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -377,8 +377,10 @@ void xen_console_resume(void) #ifdef CONFIG_HVC_XEN_FRONTEND static void xencons_disconnect_backend(struct xencons_info *info) { + if (info->hvc != NULL) + hvc_remove(info->hvc); + info->hvc = NULL; if (info->irq > 0) { - notifier_del_irq(info->hvc, info->irq); evtchn_put(info->evtchn); info->irq = 0; info->evtchn = 0; @@ -390,9 +392,6 @@ static void xencons_disconnect_backend(struct xencons_info *info) if (info->gntref > 0) gnttab_free_grant_references(info->gntref); info->gntref = 0; - if (info->hvc != NULL) - hvc_remove(info->hvc); - info->hvc = NULL; } static void xencons_free(struct xencons_info *info) @@ -558,6 +557,7 @@ static void xencons_backend_changed(struct xenbus_device *dev, break; fallthrough; /* Missed the backend's CLOSING state */ case XenbusStateClosing: + xencons_disconnect_backend(dev_get_drvdata(&dev->dev)); xenbus_frontend_closed(dev); break; }
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 98764e740c07..f0376612b267 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -377,9 +377,13 @@ void xen_console_resume(void) #ifdef CONFIG_HVC_XEN_FRONTEND static void xencons_disconnect_backend(struct xencons_info *info) { - if (info->irq > 0) - unbind_from_irqhandler(info->irq, NULL); - info->irq = 0; + if (info->irq > 0) { + notifier_del_irq(info->hvc, info->irq); + evtchn_put(info->evtchn); + info->irq = 0; + info->evtchn = 0; + } + /* evtchn_put() will also close it so this is only an error path */ if (info->evtchn > 0) xenbus_free_evtchn(info->xbdev, info->evtchn); info->evtchn = 0; @@ -433,7 +437,7 @@ static int xencons_connect_backend(struct xenbus_device *dev, if (ret) return ret; info->evtchn = evtchn; - irq = bind_interdomain_evtchn_to_irq_lateeoi(dev, evtchn); + irq = bind_evtchn_to_irq_lateeoi(evtchn); if (irq < 0) return irq; info->irq = irq; @@ -597,7 +601,7 @@ static int __init xen_hvc_init(void) else r = xen_pv_console_init(); if (r < 0) - return r; + goto register_fe; info = vtermno_to_xencons(HVC_COOKIE); info->irq = bind_evtchn_to_irq_lateeoi(info->evtchn); @@ -616,12 +620,13 @@ static int __init xen_hvc_init(void) list_del(&info->list); spin_unlock_irqrestore(&xencons_lock, flags); if (info->irq) - unbind_from_irqhandler(info->irq, NULL); + evtchn_put(info->evtchn); kfree(info); return r; } r = 0; + register_fe: #ifdef CONFIG_HVC_XEN_FRONTEND r = xenbus_register_frontend(&xencons_driver); #endif