mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Mike Waychison <mikew@google.com>
To: simon.kagstrom@netinsight.net, davem@davemloft.net,
	nhorman@tuxdriver.com, Matt Mackall <mpm@selenic.com>
Cc: adurbin@google.com, linux-kernel@vger.kernel.org,
	chavey@google.com, "Greg KH" <greg@kroah.com>,
	"Américo Wang" <xiyou.wangcong@gmail.com>,
	akpm@linux-foundation.org, linux-api@vger.kernel.org
Subject: [PATCH v2 03/23] netconsole: Introduce 'enabled' state-machine
Date: Mon, 08 Nov 2010 12:31:54 -0800	[thread overview]
Message-ID: <20101108203153.22479.54008.stgit@crlf.mtv.corp.google.com> (raw)
In-Reply-To: <20101108203120.22479.19708.stgit@crlf.mtv.corp.google.com>

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 <mikew@google.com>
---
 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:
 				/*
 				 * rtnl_lock already held
@@ -699,11 +719,6 @@ static int netconsole_netdev_event(struct notifier_block *this,
 					dev_put(nt->np.dev);
 					nt->np.dev = NULL;
 				}
-				/* Fall through */
-			case NETDEV_GOING_DOWN:
-			case NETDEV_BONDING_DESLAVE:
-				nt->enabled = 0;
-				break;
 			}
 		}
 	}
@@ -734,7 +749,8 @@ static void write_msg(struct console *con, const char *msg, unsigned int len)
 
 	spin_lock_irqsave(&target_list_lock, flags);
 	list_for_each_entry(nt, &target_list, list) {
-		if (nt->enabled && netif_running(nt->np.dev)) {
+		if (nt->np_state == NETPOLL_ENABLED
+		    && netif_running(nt->np.dev)) {
 			/*
 			 * We nest this inside the for-each-target loop above
 			 * so that we're able to get as much logging out to


  parent reply	other threads:[~2010-11-08 20:32 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-11-08 20:31 [PATCH v2 00/23] netoops support Mike Waychison
2010-11-08 20:31 ` [PATCH v2 01/23] netconsole: Remove unneeded reference counting Mike Waychison
2010-11-08 20:31 ` [PATCH v2 02/23] netconsole: Introduce locking over the netpoll fields Mike Waychison
2010-11-08 20:31 ` Mike Waychison [this message]
2010-11-08 20:32 ` [PATCH v2 04/23] netconsole: Call netpoll_cleanup() in process context Mike Waychison
2010-11-09 12:07   ` Neil Horman
2010-11-09 17:18     ` Mike Waychison
2010-11-09 19:33       ` Neil Horman
2010-11-08 20:32 ` [PATCH v2 05/23] netconsole: Wrap the list and locking in a structure Mike Waychison
2010-11-08 20:32 ` [PATCH v2 06/23] netconsole: Push configfs_subsystem into netpoll_targets Mike Waychison
2010-11-08 20:32 ` [PATCH v2 07/23] netconsole: Move netdev_notifier " Mike Waychison
2010-11-08 20:32 ` [PATCH v2 08/23] netconsole: Split out netpoll_targets init/exit Mike Waychison
2010-11-08 20:32 ` [PATCH v2 09/23] netconsole: Add pointer to netpoll_targets Mike Waychison
2010-11-08 20:32 ` [PATCH v2 10/23] netconsole: Rename netconsole_target -> netpoll_target Mike Waychison
2010-11-08 20:32 ` [PATCH v2 11/23] netconsole: Abstract away the subsystem name Mike Waychison
2010-11-08 20:32 ` [PATCH v2 12/23] netpoll: Introduce netpoll_target configs Mike Waychison
2010-11-09  3:30   ` Américo Wang
2010-11-09  4:27     ` Américo Wang
2010-11-09  8:34       ` Mike Waychison
2010-11-09  9:06         ` Américo Wang
2010-11-09  9:38           ` [RFC PATCH] configfs: make it not be a module any more Américo Wang
2010-11-09 14:20           ` [PATCH v2 12/23] netpoll: Introduce netpoll_target configs Greg KH
2010-11-09 17:24             ` Mike Waychison
2010-11-09 17:27               ` Greg KH
2010-11-08 20:32 ` [PATCH v2 13/23] netconsole: Move setting of default ports Mike Waychison
2010-11-08 20:32 ` [PATCH v2 14/23] netpoll: Move target code into netpoll_targets.c Mike Waychison
2010-11-08 20:33 ` [PATCH v2 15/23] Oops: Pass regs to oops_exit() Mike Waychison
2010-11-08 20:33 ` [PATCH v2 16/23] kmsg_dumper: Pass pt_regs along to dumpers Mike Waychison
2010-11-08 20:33 ` [PATCH v2 17/23] kmsg_dumper: Introduce a new 'SOFT' dump reason Mike Waychison
2010-11-09  5:49   ` KOSAKI Motohiro
2010-11-09  5:54     ` KOSAKI Motohiro
2010-11-08 20:33 ` [PATCH v2 18/23] sys-rq: Add option to soft dump Mike Waychison
2010-11-08 21:09   ` Randy Dunlap
2010-11-08 22:27     ` Mike Waychison
2010-11-08 22:31       ` Randy Dunlap
2010-11-08 20:33 ` [PATCH v2 19/23] netoops: add core functionality Mike Waychison
2010-11-08 20:33 ` [PATCH v2 20/23] netoops: Add x86 specific bits to packet headers Mike Waychison
2010-11-09 14:22   ` Neil Horman
2010-11-09 17:56     ` Mike Waychison
2010-11-08 20:33 ` [PATCH v2 21/23] netoops: Add user programmable fields to the netoops packet Mike Waychison
2010-11-08 20:33 ` [PATCH v2 22/23] netoops: Add one-shot mode Mike Waychison
2010-11-08 20:33 ` [PATCH v2 23/23] netoops: Add an interface to trigger various types of crashes Mike Waychison
2010-11-08 20:55 ` [PATCH v2 00/23] netoops support Matt Mackall
2010-11-08 21:20   ` David Miller
2010-11-08 21:43     ` Mike Waychison
2010-11-09  1:28 ` Andi Kleen
2010-11-09  4:25   ` Américo Wang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20101108203153.22479.54008.stgit@crlf.mtv.corp.google.com \
    --to=mikew@google.com \
    --cc=adurbin@google.com \
    --cc=akpm@linux-foundation.org \
    --cc=chavey@google.com \
    --cc=davem@davemloft.net \
    --cc=greg@kroah.com \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mpm@selenic.com \
    --cc=nhorman@tuxdriver.com \
    --cc=simon.kagstrom@netinsight.net \
    --cc=xiyou.wangcong@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome