Received: by 2002:a05:6a10:a0d1:0:0:0:0 with SMTP id j17csp2024300pxa; Mon, 3 Aug 2020 05:40:37 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxDoKQlBmzDIj/UoKvf5UI7LXVAYw5Ddm/3jiaf/ITzVR/WRItJskMqj9tGCBKYKrAM4LSr X-Received: by 2002:a17:906:4c97:: with SMTP id q23mr3286735eju.11.1596458437559; Mon, 03 Aug 2020 05:40:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1596458437; cv=none; d=google.com; s=arc-20160816; b=K2t4sN8uFm+NJMw/Kgivd2AxEXIEw7V59v4uPoA1g3Tm2BXdNub+v5jO4GyMU/fUPj KYnPpKn/phalsPV01o9MmcmaxoJjoJr/n4xZDzn7WvIL/P/0eVpDSXtJUsPqjyDtc7ts Wh3hRuvn1OJZuwk0c4V5fKEztuHBUC10WceOgV1eOSxehoh19DMHZlmiPNKOsmsrXlEo F3BTyiZjzKiK8+o8dC4TAQqng1q/8YPcqNSM2dNxJH83hgxGRTjsIXrdA4gQsmtqESFj 2/p1UrokJH+oVrNkSYz5fcfmTs2LJsMnfG1nNRGxN4uarjdkNeufNafdGY5GdnHXieHh 404w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=x9qRlWY17LeEF/l/S7lUscI/xe+r1mZikApJpEywyT0=; b=ZnI74bWEIkfoduKxd9HT6N/eUCeUjQS2Wv6hcguU6TXEUAihT8Tf0XTPeSedWvaVHy dglTp8POW+iy2aNkCvuwcA31KI9WaF7ehAtGRjgBOReB6AHPpEpmLn6SwimpFhyYKeBM k9qwj5vlRJHKZVrx5FFhtW9y71JOdsJKQGEbgoeaBIMSdQUQsijLY+c7zGFJyTF7Mj7Z 4aJvisgzb7/R6qwTEMYcwgUZGadsIJ0TSeZjM7u2xM9BuWs/rjNKCl5y/y0bzYG7aR1f N915PrasYdqZDuk9bcM2YqKvh2XE+pJSKkS/2PbPXy8oFnAv/G4TGWOGEG/AXoxBSAhw 7HAA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=Ws2yKnk4; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id o2si5502776ejm.676.2020.08.03.05.40.15; Mon, 03 Aug 2020 05:40:37 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=Ws2yKnk4; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729203AbgHCMj6 (ORCPT + 99 others); Mon, 3 Aug 2020 08:39:58 -0400 Received: from mail.kernel.org ([198.145.29.99]:33028 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728366AbgHCMdM (ORCPT ); Mon, 3 Aug 2020 08:33:12 -0400 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id A1B382076B; Mon, 3 Aug 2020 12:33:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1596457990; bh=U+chRqPGR8rJrwHBA7q6Oj2Gm8e0BLsd3/ugWeyaAfw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ws2yKnk4wkhScCQKX14C1y7PiOu68M+O3ST5iXvjB45OPuiCLTTCjd30srMSTkhQY SEQhTmTiEcPh8bciYHEUInrawJWfr1ST7g2vp1MChO99c5XBrhg2WqeZuCTM2FcDwK ytURaAJLlj5/D4u8yLrTtL1O4571LmTltwwRCg9E= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Andrea Righi , "David S. Miller" , Sasha Levin Subject: [PATCH 4.19 54/56] xen-netfront: fix potential deadlock in xennet_remove() Date: Mon, 3 Aug 2020 14:20:09 +0200 Message-Id: <20200803121852.973030494@linuxfoundation.org> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200803121850.306734207@linuxfoundation.org> References: <20200803121850.306734207@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Andrea Righi [ Upstream commit c2c633106453611be07821f53dff9e93a9d1c3f0 ] There's a potential race in xennet_remove(); this is what the driver is doing upon unregistering a network device: 1. state = read bus state 2. if state is not "Closed": 3. request to set state to "Closing" 4. wait for state to be set to "Closing" 5. request to set state to "Closed" 6. wait for state to be set to "Closed" If the state changes to "Closed" immediately after step 1 we are stuck forever in step 4, because the state will never go back from "Closed" to "Closing". Make sure to check also for state == "Closed" in step 4 to prevent the deadlock. Also add a 5 sec timeout any time we wait for the bus state to change, to avoid getting stuck forever in wait_event(). Signed-off-by: Andrea Righi Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/xen-netfront.c | 64 +++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 6b4675a9494b2..c8e84276e6397 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -63,6 +63,8 @@ module_param_named(max_queues, xennet_max_queues, uint, 0644); MODULE_PARM_DESC(max_queues, "Maximum number of queues per virtual interface"); +#define XENNET_TIMEOUT (5 * HZ) + static const struct ethtool_ops xennet_ethtool_ops; struct netfront_cb { @@ -1337,12 +1339,15 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev) netif_carrier_off(netdev); - xenbus_switch_state(dev, XenbusStateInitialising); - wait_event(module_wq, - xenbus_read_driver_state(dev->otherend) != - XenbusStateClosed && - xenbus_read_driver_state(dev->otherend) != - XenbusStateUnknown); + do { + xenbus_switch_state(dev, XenbusStateInitialising); + err = wait_event_timeout(module_wq, + xenbus_read_driver_state(dev->otherend) != + XenbusStateClosed && + xenbus_read_driver_state(dev->otherend) != + XenbusStateUnknown, XENNET_TIMEOUT); + } while (!err); + return netdev; exit: @@ -2142,28 +2147,43 @@ static const struct attribute_group xennet_dev_group = { }; #endif /* CONFIG_SYSFS */ -static int xennet_remove(struct xenbus_device *dev) +static void xennet_bus_close(struct xenbus_device *dev) { - struct netfront_info *info = dev_get_drvdata(&dev->dev); - - dev_dbg(&dev->dev, "%s\n", dev->nodename); + int ret; - if (xenbus_read_driver_state(dev->otherend) != XenbusStateClosed) { + if (xenbus_read_driver_state(dev->otherend) == XenbusStateClosed) + return; + do { xenbus_switch_state(dev, XenbusStateClosing); - wait_event(module_wq, - xenbus_read_driver_state(dev->otherend) == - XenbusStateClosing || - xenbus_read_driver_state(dev->otherend) == - XenbusStateUnknown); + ret = wait_event_timeout(module_wq, + xenbus_read_driver_state(dev->otherend) == + XenbusStateClosing || + xenbus_read_driver_state(dev->otherend) == + XenbusStateClosed || + xenbus_read_driver_state(dev->otherend) == + XenbusStateUnknown, + XENNET_TIMEOUT); + } while (!ret); + + if (xenbus_read_driver_state(dev->otherend) == XenbusStateClosed) + return; + do { xenbus_switch_state(dev, XenbusStateClosed); - wait_event(module_wq, - xenbus_read_driver_state(dev->otherend) == - XenbusStateClosed || - xenbus_read_driver_state(dev->otherend) == - XenbusStateUnknown); - } + ret = wait_event_timeout(module_wq, + xenbus_read_driver_state(dev->otherend) == + XenbusStateClosed || + xenbus_read_driver_state(dev->otherend) == + XenbusStateUnknown, + XENNET_TIMEOUT); + } while (!ret); +} + +static int xennet_remove(struct xenbus_device *dev) +{ + struct netfront_info *info = dev_get_drvdata(&dev->dev); + xennet_bus_close(dev); xennet_disconnect_backend(info); if (info->netdev->reg_state == NETREG_REGISTERED) -- 2.25.1