Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756171Ab0LQUxB (ORCPT ); Fri, 17 Dec 2010 15:53:01 -0500 Received: from charlotte.tuxdriver.com ([70.61.120.58]:60097 "EHLO smtp.tuxdriver.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755303Ab0LQUw6 (ORCPT ); Fri, 17 Dec 2010 15:52:58 -0500 Date: Fri, 17 Dec 2010 15:52:38 -0500 From: Neil Horman To: Mike Waychison Cc: simon.kagstrom@netinsight.net, davem@davemloft.net, Matt Mackall , adurbin@google.com, linux-kernel@vger.kernel.org, chavey@google.com, Greg KH , netdev@vger.kernel.org, =?iso-8859-1?Q?Am=E9rico?= Wang , akpm@linux-foundation.org, linux-api@vger.kernel.org Subject: Re: [PATCH v3 03/22] netconsole: Introduce 'enabled' state-machine Message-ID: <20101217205238.GA8642@hmsreliant.think-freely.org> References: <20101214212846.17022.64836.stgit@mike.mtv.corp.google.com> <20101214212909.17022.96801.stgit@mike.mtv.corp.google.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20101214212909.17022.96801.stgit@mike.mtv.corp.google.com> User-Agent: Mutt/1.5.20 (2009-08-17) X-Spam-Score: -4.4 (----) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8041 Lines: 200 On Tue, Dec 14, 2010 at 01:29:10PM -0800, Mike Waychison wrote: > Representing the internal state within netconsole isn't really a boolean > value, but rather a state machine with transitions. > > This patch introduces 4 states that the netconsole multi-target can > handle. These states are: > - NETPOLL_DISABLED: > The netpoll structure hasn't been setup. > - NETPOLL_SETTINGUP: > The netpoll structure is being setup, and only whoever set this > state can transition out of it. Must come from the NETPOLL_DISABLED > state. > - NETPOLL_ENABLED: > The netpoll structure has been setup and we are good to emit > packets. > - NETPOLL_CLEANING: > Somebody is queued to call netpoll_clean. Whoever does so must > transition out of this state. Must come from the NETPOLL_CLEANING > state. > > The SETTINGUP state specifically targets the window where > netpoll_setup() can take a while (for example, waiting on RTNL). > During this window, we want to exclude console messages from being > emitted to this netpoll target. We also want to exclude any subsequent > user thread that tries to simultaneously enable or disable the target. > > The CLEANING state will be used in a subsequent patch to safely defer > netpoll_cleanup to scheduled work in process context (to fix the > deadlock that will occur whenever NETDEV_UNREGISTER is seen). > > When introducing these new transition states, it no longer makes sense > to 'disable' the target if the interface is going down, only when it is > being removed completely (or deslaved). In fact, prior to this change, > we would leak a reference to the network device if an interface was > brought down, the target removed, and netconsole unloaded. > > Signed-off-by: Mike Waychison > Acked-by: Matt Mackall > --- > drivers/net/netconsole.c | 62 +++++++++++++++++++++++++++++----------------- > 1 files changed, 39 insertions(+), 23 deletions(-) > > diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c > index 6e16888..288a025 100644 > --- a/drivers/net/netconsole.c > +++ b/drivers/net/netconsole.c > @@ -71,16 +71,24 @@ static LIST_HEAD(target_list); > /* This needs to be a spinlock because write_msg() cannot sleep */ > static DEFINE_SPINLOCK(target_list_lock); > > +#define NETPOLL_DISABLED 0 > +#define NETPOLL_SETTINGUP 1 > +#define NETPOLL_ENABLED 2 > +#define NETPOLL_CLEANING 3 > + > /** > * struct netconsole_target - Represents a configured netconsole target. > * @list: Links this target into the target_list. > * @item: Links us into the configfs subsystem hierarchy. > - * @enabled: On / off knob to enable / disable target. > - * Visible from userspace (read-write). > - * We maintain a strict 1:1 correspondence between this and > - * whether the corresponding netpoll is active or inactive. > + * @np_state: Enabled / Disabled / SettingUp / Cleaning > + * Visible from userspace (read-write) as "enabled". > + * We maintain a state machine here of the valid states. Either a > + * target is enabled or disabled, but it may also be in a > + * transitional state whereby nobody is allowed to act on the > + * target other than whoever owns the transition. > + * > * Also, other parameters of a target may be modified at > - * runtime only when it is disabled (enabled == 0). > + * runtime only when it is disabled (np_state == NETPOLL_ENABLED). > * @np: The netpoll structure for this target. > * Contains the other userspace visible parameters: > * dev_name (read-write) > @@ -96,7 +104,7 @@ struct netconsole_target { > #ifdef CONFIG_NETCONSOLE_DYNAMIC > struct config_item item; > #endif > - int enabled; > + int np_state; > struct netpoll np; > }; > > @@ -189,7 +197,7 @@ static struct netconsole_target *alloc_param_target(char *target_config) > if (err) > goto fail; > > - nt->enabled = 1; > + nt->np_state = NETPOLL_ENABLED; > > return nt; > > @@ -275,7 +283,8 @@ static long strtol10_check_range(const char *cp, long min, long max) > > static ssize_t show_enabled(struct netconsole_target *nt, char *buf) > { > - return snprintf(buf, PAGE_SIZE, "%d\n", nt->enabled); > + return snprintf(buf, PAGE_SIZE, "%d\n", > + nt->np_state == NETPOLL_ENABLED); > } > > static ssize_t show_dev_name(struct netconsole_target *nt, char *buf) > @@ -337,9 +346,12 @@ static ssize_t store_enabled(struct netconsole_target *nt, > > if (enabled) { /* 1 */ > spin_lock_irqsave(&target_list_lock, flags); > - if (nt->enabled) > + if (nt->np_state != NETPOLL_DISABLED) > goto busy; > - spin_unlock_irqrestore(&target_list_lock, flags); > + else { > + nt->np_state = NETPOLL_SETTINGUP; > + spin_unlock_irqrestore(&target_list_lock, flags); > + } > > /* > * Skip netpoll_parse_options() -- all the attributes are > @@ -350,9 +362,9 @@ static ssize_t store_enabled(struct netconsole_target *nt, > err = netpoll_setup(&nt->np); > spin_lock_irqsave(&target_list_lock, flags); > if (err) > - nt->enabled = 0; > + nt->np_state = NETPOLL_DISABLED; > else > - nt->enabled = 1; > + nt->np_state = NETPOLL_ENABLED; > spin_unlock_irqrestore(&target_list_lock, flags); > if (err) > return err; > @@ -360,10 +372,17 @@ static ssize_t store_enabled(struct netconsole_target *nt, > printk(KERN_INFO "netconsole: network logging started\n"); > } else { /* 0 */ > spin_lock_irqsave(&target_list_lock, flags); > - nt->enabled = 0; > + if (nt->np_state == NETPOLL_ENABLED) > + nt->np_state = NETPOLL_CLEANING; > + else if (nt->np_state != NETPOLL_DISABLED) > + goto busy; > spin_unlock_irqrestore(&target_list_lock, flags); > > netpoll_cleanup(&nt->np); > + > + spin_lock_irqsave(&target_list_lock, flags); > + nt->np_state = NETPOLL_DISABLED; > + spin_unlock_irqrestore(&target_list_lock, flags); > } > > return strnlen(buf, count); > @@ -486,7 +505,7 @@ static ssize_t store_locked_##_name(struct netconsole_target *nt, \ > unsigned long flags; \ > ssize_t ret; \ > spin_lock_irqsave(&target_list_lock, flags); \ > - if (nt->enabled) { \ > + if (nt->np_state != NETPOLL_DISABLED) { \ > printk(KERN_ERR "netconsole: target (%s) is enabled, " \ > "disable to update parameters\n", \ > config_item_name(&nt->item)); \ > @@ -642,7 +661,7 @@ static void drop_netconsole_target(struct config_group *group, > * The target may have never been enabled, or was manually disabled > * before being removed so netpoll may have already been cleaned up. > */ > - if (nt->enabled) > + if (nt->np_state == NETPOLL_ENABLED) > netpoll_cleanup(&nt->np); > > config_item_put(&nt->item); > @@ -680,16 +699,17 @@ static int netconsole_netdev_event(struct notifier_block *this, > struct net_device *dev = ptr; > > if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER || > - event == NETDEV_BONDING_DESLAVE || event == NETDEV_GOING_DOWN)) > + event == NETDEV_BONDING_DESLAVE)) > goto done; > > spin_lock_irqsave(&target_list_lock, flags); > list_for_each_entry(nt, &target_list, list) { > - if (nt->np.dev == dev) { > + if (nt->np_state == NETPOLL_ENABLED && nt->np.dev == dev) { > switch (event) { > case NETDEV_CHANGENAME: > strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ); > break; > + case NETDEV_BONDING_DESLAVE: > case NETDEV_UNREGISTER: I don't follow what you're doing here. Previously NETDEV_BONDING_DESLAVE events simply caused the netconsole interface to get deactivated, and now we're doing a dev_put on the bonded interface bacause of the above move. Given that NETDEV_BONDING_DESLAVE events are generated when a slave leaves the bond, this doesn't seem right, or am I missing something Regards Neil -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/