From patchwork Tue Jan 19 20:25:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 366701 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E3C74C433DB for ; Tue, 19 Jan 2021 20:27:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 724E223107 for ; Tue, 19 Jan 2021 20:27:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729667AbhASU1j (ORCPT ); Tue, 19 Jan 2021 15:27:39 -0500 Received: from mail.kernel.org ([198.145.29.99]:56982 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391761AbhASU0F (ORCPT ); Tue, 19 Jan 2021 15:26:05 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 57E1823138; Tue, 19 Jan 2021 20:25:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1611087924; bh=T9Ergzt8UttH+ZgH2jkWyJf/CzIXN9QAzLK5kPx9jPk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GSZCHNi5+o5MUUlr6e7T2zkZY80Eq168WJ/qTjU1ubMVQhZAkY5sGdVeveexzf6Kz HBbMi4x1Aux1J3bsFtnkw7hP5m2BciUllRKtCzJiDM3phKP4IPWujPW9ejNlQgc224 e8spmWwvopOz5pUACW4/ZBM/nKzvnESWkQsFl4XlBVJr3ckilU8n5xeQhmvsqOkUFl ru4os2PMlh/JqVl2PhORxicSx4BSAXWRAcJLmY/BlgZGcHzOnQsWoMcw7pyWeYzXVd Nyfu8B1TfVO+KJHpwlQDnJMye6wrYc4c/nebQSkuWqYFAh/U/5rhksmrr0hJZbkNY7 sBOOj03NqczoQ== From: Jakub Kicinski To: davem@davemloft.net Cc: netdev@vger.kernel.org, Jakub Kicinski Subject: [PATCH net-next v2 1/4] net: move net_set_todo inside rollback_registered() Date: Tue, 19 Jan 2021 12:25:18 -0800 Message-Id: <20210119202521.3108236-2-kuba@kernel.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210119202521.3108236-1-kuba@kernel.org> References: <20210119202521.3108236-1-kuba@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Commit 93ee31f14f6f ("[NET]: Fix free_netdev on register_netdev failure.") moved net_set_todo() outside of rollback_registered() so that rollback_registered() can be used in the failure path of register_netdevice() but without risking a double free. Since commit cf124db566e6 ("net: Fix inconsistent teardown and release of private netdev state."), however, we have a better way of handling that condition, since destructors don't call free_netdev() directly. After the change in commit c269a24ce057 ("net: make free_netdev() more lenient with unregistering devices") we can now move net_set_todo() back. Signed-off-by: Jakub Kicinski --- net/core/dev.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 6b90520a01b1..5f928b51c6b0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -9546,8 +9546,10 @@ static void rollback_registered_many(struct list_head *head) synchronize_net(); - list_for_each_entry(dev, head, unreg_list) + list_for_each_entry(dev, head, unreg_list) { dev_put(dev); + net_set_todo(dev); + } } static void rollback_registered(struct net_device *dev) @@ -10104,7 +10106,6 @@ int register_netdevice(struct net_device *dev) /* Expect explicit free_netdev() on failure */ dev->needs_free_netdev = false; rollback_registered(dev); - net_set_todo(dev); goto out; } /* @@ -10727,8 +10728,6 @@ void unregister_netdevice_queue(struct net_device *dev, struct list_head *head) list_move_tail(&dev->unreg_list, head); } else { rollback_registered(dev); - /* Finish processing unregister after unlock */ - net_set_todo(dev); } } EXPORT_SYMBOL(unregister_netdevice_queue); @@ -10742,12 +10741,8 @@ EXPORT_SYMBOL(unregister_netdevice_queue); */ void unregister_netdevice_many(struct list_head *head) { - struct net_device *dev; - if (!list_empty(head)) { rollback_registered_many(head); - list_for_each_entry(dev, head, unreg_list) - net_set_todo(dev); list_del(head); } } From patchwork Tue Jan 19 20:25:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 366698 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3140DC433E0 for ; Tue, 19 Jan 2021 20:34:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DB20F23119 for ; Tue, 19 Jan 2021 20:34:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2391943AbhASUeY (ORCPT ); Tue, 19 Jan 2021 15:34:24 -0500 Received: from mail.kernel.org ([198.145.29.99]:56992 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391787AbhASU0G (ORCPT ); Tue, 19 Jan 2021 15:26:06 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 0D53D2313C; Tue, 19 Jan 2021 20:25:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1611087925; bh=3/eW4H3tjjKxnfp2qh2frcEPs8tUd6lc34Qs1+xtguc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=U12wyRjNljW30Zwb6xWaXmls1kfd8FOl0z7jENUlm4vyeJRgPqlRdhIqFjjWokke7 QEu1/HbAW7IRTPxUndyDfzisvhsaQIzv6iu4QyXWbQO5vWt0Jm2yrtncAEeAWBD1WT 5z1+P9jssrGbmqpvJaVpWOZrJXpudsx6lOiMuYJLhcWllj43cypZjwYsAVvT9pXJSt X9oztAixmZstkMzad+7sn0JNL96H7ULwrj8FYFdUvVWPzSEmjgJ74eZjZBbiiTj086 D+/DNdJgOptgJDUBrL4MZBc/T1zDD3mUfbkuvOYA+0Qhn/Asdak/PXR3zLI5sAAxYg O/I2UudkrJlXQ== From: Jakub Kicinski To: davem@davemloft.net Cc: netdev@vger.kernel.org, Jakub Kicinski Subject: [PATCH net-next v2 3/4] net: move rollback_registered_many() Date: Tue, 19 Jan 2021 12:25:20 -0800 Message-Id: <20210119202521.3108236-4-kuba@kernel.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210119202521.3108236-1-kuba@kernel.org> References: <20210119202521.3108236-1-kuba@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Move rollback_registered_many() and add a temporary forward declaration to make merging the code into unregister_netdevice_many() easier to review. No functional changes. Signed-off-by: Jakub Kicinski --- net/core/dev.c | 188 +++++++++++++++++++++++++------------------------ 1 file changed, 95 insertions(+), 93 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 85e9d4b7ddf2..a7841d03c910 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -9459,99 +9459,6 @@ static void net_set_todo(struct net_device *dev) dev_net(dev)->dev_unreg_count++; } -static void rollback_registered_many(struct list_head *head) -{ - struct net_device *dev, *tmp; - LIST_HEAD(close_head); - - BUG_ON(dev_boot_phase); - ASSERT_RTNL(); - - list_for_each_entry_safe(dev, tmp, head, unreg_list) { - /* Some devices call without registering - * for initialization unwind. Remove those - * devices and proceed with the remaining. - */ - if (dev->reg_state == NETREG_UNINITIALIZED) { - pr_debug("unregister_netdevice: device %s/%p never was registered\n", - dev->name, dev); - - WARN_ON(1); - list_del(&dev->unreg_list); - continue; - } - dev->dismantle = true; - BUG_ON(dev->reg_state != NETREG_REGISTERED); - } - - /* If device is running, close it first. */ - list_for_each_entry(dev, head, unreg_list) - list_add_tail(&dev->close_list, &close_head); - dev_close_many(&close_head, true); - - list_for_each_entry(dev, head, unreg_list) { - /* And unlink it from device chain. */ - unlist_netdevice(dev); - - dev->reg_state = NETREG_UNREGISTERING; - } - flush_all_backlogs(); - - synchronize_net(); - - list_for_each_entry(dev, head, unreg_list) { - struct sk_buff *skb = NULL; - - /* Shutdown queueing discipline. */ - dev_shutdown(dev); - - dev_xdp_uninstall(dev); - - /* Notify protocols, that we are about to destroy - * this device. They should clean all the things. - */ - call_netdevice_notifiers(NETDEV_UNREGISTER, dev); - - if (!dev->rtnl_link_ops || - dev->rtnl_link_state == RTNL_LINK_INITIALIZED) - skb = rtmsg_ifinfo_build_skb(RTM_DELLINK, dev, ~0U, 0, - GFP_KERNEL, NULL, 0); - - /* - * Flush the unicast and multicast chains - */ - dev_uc_flush(dev); - dev_mc_flush(dev); - - netdev_name_node_alt_flush(dev); - netdev_name_node_free(dev->name_node); - - if (dev->netdev_ops->ndo_uninit) - dev->netdev_ops->ndo_uninit(dev); - - if (skb) - rtmsg_ifinfo_send(skb, dev, GFP_KERNEL); - - /* Notifier chain MUST detach us all upper devices. */ - WARN_ON(netdev_has_any_upper_dev(dev)); - WARN_ON(netdev_has_any_lower_dev(dev)); - - /* Remove entries from kobject tree */ - netdev_unregister_kobject(dev); -#ifdef CONFIG_XPS - /* Remove XPS queueing entries */ - netif_reset_xps_queues_gt(dev, 0); -#endif - } - - synchronize_net(); - - list_for_each_entry(dev, head, unreg_list) { - dev_put(dev); - net_set_todo(dev); - } -} - static netdev_features_t netdev_sync_upper_features(struct net_device *lower, struct net_device *upper, netdev_features_t features) { @@ -10698,6 +10605,8 @@ void synchronize_net(void) } EXPORT_SYMBOL(synchronize_net); +static void rollback_registered_many(struct list_head *head); + /** * unregister_netdevice_queue - remove device from the kernel * @dev: device @@ -10743,6 +10652,99 @@ void unregister_netdevice_many(struct list_head *head) } EXPORT_SYMBOL(unregister_netdevice_many); +static void rollback_registered_many(struct list_head *head) +{ + struct net_device *dev, *tmp; + LIST_HEAD(close_head); + + BUG_ON(dev_boot_phase); + ASSERT_RTNL(); + + list_for_each_entry_safe(dev, tmp, head, unreg_list) { + /* Some devices call without registering + * for initialization unwind. Remove those + * devices and proceed with the remaining. + */ + if (dev->reg_state == NETREG_UNINITIALIZED) { + pr_debug("unregister_netdevice: device %s/%p never was registered\n", + dev->name, dev); + + WARN_ON(1); + list_del(&dev->unreg_list); + continue; + } + dev->dismantle = true; + BUG_ON(dev->reg_state != NETREG_REGISTERED); + } + + /* If device is running, close it first. */ + list_for_each_entry(dev, head, unreg_list) + list_add_tail(&dev->close_list, &close_head); + dev_close_many(&close_head, true); + + list_for_each_entry(dev, head, unreg_list) { + /* And unlink it from device chain. */ + unlist_netdevice(dev); + + dev->reg_state = NETREG_UNREGISTERING; + } + flush_all_backlogs(); + + synchronize_net(); + + list_for_each_entry(dev, head, unreg_list) { + struct sk_buff *skb = NULL; + + /* Shutdown queueing discipline. */ + dev_shutdown(dev); + + dev_xdp_uninstall(dev); + + /* Notify protocols, that we are about to destroy + * this device. They should clean all the things. + */ + call_netdevice_notifiers(NETDEV_UNREGISTER, dev); + + if (!dev->rtnl_link_ops || + dev->rtnl_link_state == RTNL_LINK_INITIALIZED) + skb = rtmsg_ifinfo_build_skb(RTM_DELLINK, dev, ~0U, 0, + GFP_KERNEL, NULL, 0); + + /* + * Flush the unicast and multicast chains + */ + dev_uc_flush(dev); + dev_mc_flush(dev); + + netdev_name_node_alt_flush(dev); + netdev_name_node_free(dev->name_node); + + if (dev->netdev_ops->ndo_uninit) + dev->netdev_ops->ndo_uninit(dev); + + if (skb) + rtmsg_ifinfo_send(skb, dev, GFP_KERNEL); + + /* Notifier chain MUST detach us all upper devices. */ + WARN_ON(netdev_has_any_upper_dev(dev)); + WARN_ON(netdev_has_any_lower_dev(dev)); + + /* Remove entries from kobject tree */ + netdev_unregister_kobject(dev); +#ifdef CONFIG_XPS + /* Remove XPS queueing entries */ + netif_reset_xps_queues_gt(dev, 0); +#endif + } + + synchronize_net(); + + list_for_each_entry(dev, head, unreg_list) { + dev_put(dev); + net_set_todo(dev); + } +} + /** * unregister_netdev - remove device from the kernel * @dev: device From patchwork Tue Jan 19 20:25:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 366700 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6A21AC433E0 for ; Tue, 19 Jan 2021 20:29:00 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 18EFF23104 for ; Tue, 19 Jan 2021 20:29:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2391737AbhASU23 (ORCPT ); Tue, 19 Jan 2021 15:28:29 -0500 Received: from mail.kernel.org ([198.145.29.99]:56998 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391798AbhASU0G (ORCPT ); Tue, 19 Jan 2021 15:26:06 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 5810E23142; Tue, 19 Jan 2021 20:25:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1611087925; bh=mJ1AXD5yOyqGzpmFOoCAv9EAxBEeHkwGHfJvVMxBY6o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GhBq0vDSCgVqv9Lpp61ItEm9irJr1wNGfcm8len8/59IfvhAUFiGyTRkLZRkn/kRW O54AmxlrQFO4ft40yKNOcbgiec2MHrjY0r04hwodz/ah2GMlZiK8bEELTji4+bL4rt +mNnY4y9zKMInAqsLCWrvYVD1n0uQ+SOtRFAQeh/FkEy8/NkfXPq97WaUhoJHOvI6S QWkcdb42zJm2UQUUQkxRurVpxuRUWynaRspZSlFDsEtu/zUq0yl25dSErN1cvhd2L7 B+rH84OIy6m5BUuEV9fiVy8jf1FoVgUAmxVvjlg6vfCPnLFQGHgIECtFuZifzH7vON Q8qN9zkPLxnNQ== From: Jakub Kicinski To: davem@davemloft.net Cc: netdev@vger.kernel.org, Jakub Kicinski Subject: [PATCH net-next v2 4/4] net: inline rollback_registered_many() Date: Tue, 19 Jan 2021 12:25:21 -0800 Message-Id: <20210119202521.3108236-5-kuba@kernel.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210119202521.3108236-1-kuba@kernel.org> References: <20210119202521.3108236-1-kuba@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Similar to the change for rollback_registered() - rollback_registered_many() was a part of unregister_netdevice_many() minus the net_set_todo(), which is no longer needed. Functionally this patch moves the list_empty() check back after: BUG_ON(dev_boot_phase); ASSERT_RTNL(); but I can't find any reason why that would be an issue. Signed-off-by: Jakub Kicinski --- net/core/dev.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index a7841d03c910..dee6488f8a31 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5709,7 +5709,7 @@ static void flush_all_backlogs(void) } /* we can have in flight packet[s] on the cpus we are not flushing, - * synchronize_net() in rollback_registered_many() will take care of + * synchronize_net() in unregister_netdevice_many() will take care of * them */ for_each_cpu(cpu, &flush_cpus) @@ -10605,8 +10605,6 @@ void synchronize_net(void) } EXPORT_SYMBOL(synchronize_net); -static void rollback_registered_many(struct list_head *head); - /** * unregister_netdevice_queue - remove device from the kernel * @dev: device @@ -10630,8 +10628,7 @@ void unregister_netdevice_queue(struct net_device *dev, struct list_head *head) LIST_HEAD(single); list_add(&dev->unreg_list, &single); - rollback_registered_many(&single); - list_del(&single); + unregister_netdevice_many(&single); } } EXPORT_SYMBOL(unregister_netdevice_queue); @@ -10644,15 +10641,6 @@ EXPORT_SYMBOL(unregister_netdevice_queue); * we force a list_del() to make sure stack wont be corrupted later. */ void unregister_netdevice_many(struct list_head *head) -{ - if (!list_empty(head)) { - rollback_registered_many(head); - list_del(head); - } -} -EXPORT_SYMBOL(unregister_netdevice_many); - -static void rollback_registered_many(struct list_head *head) { struct net_device *dev, *tmp; LIST_HEAD(close_head); @@ -10660,6 +10648,9 @@ static void rollback_registered_many(struct list_head *head) BUG_ON(dev_boot_phase); ASSERT_RTNL(); + if (list_empty(head)) + return; + list_for_each_entry_safe(dev, tmp, head, unreg_list) { /* Some devices call without registering * for initialization unwind. Remove those @@ -10743,7 +10734,10 @@ static void rollback_registered_many(struct list_head *head) dev_put(dev); net_set_todo(dev); } + + list_del(head); } +EXPORT_SYMBOL(unregister_netdevice_many); /** * unregister_netdev - remove device from the kernel