summaryrefslogtreecommitdiff
path: root/drivers/net/netconsole.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/netconsole.c')
-rw-r--r--drivers/net/netconsole.c155
1 files changed, 102 insertions, 53 deletions
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 3111e1648592..6e14ba5e06c8 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -53,6 +53,8 @@ static bool oops_only = false;
module_param(oops_only, bool, 0600);
MODULE_PARM_DESC(oops_only, "Only log oops messages");
+#define NETCONSOLE_PARAM_TARGET_PREFIX "cmdline"
+
#ifndef MODULE
static int __init option_setup(char *opt)
{
@@ -165,6 +167,10 @@ static void netconsole_target_put(struct netconsole_target *nt)
{
}
+static void populate_configfs_item(struct netconsole_target *nt,
+ int cmdline_count)
+{
+}
#endif /* CONFIG_NETCONSOLE_DYNAMIC */
/* Allocate and initialize with defaults.
@@ -192,58 +198,6 @@ static struct netconsole_target *alloc_and_init(void)
return nt;
}
-/* Allocate new target (from boot/module param) and setup netpoll for it */
-static struct netconsole_target *alloc_param_target(char *target_config)
-{
- struct netconsole_target *nt;
- int err;
-
- nt = alloc_and_init();
- if (!nt) {
- err = -ENOMEM;
- goto fail;
- }
-
- if (*target_config == '+') {
- nt->extended = true;
- target_config++;
- }
-
- if (*target_config == 'r') {
- if (!nt->extended) {
- pr_err("Netconsole configuration error. Release feature requires extended log message");
- err = -EINVAL;
- goto fail;
- }
- nt->release = true;
- target_config++;
- }
-
- /* Parse parameters and setup netpoll */
- err = netpoll_parse_options(&nt->np, target_config);
- if (err)
- goto fail;
-
- err = netpoll_setup(&nt->np);
- if (err)
- goto fail;
-
- nt->enabled = true;
-
- return nt;
-
-fail:
- kfree(nt);
- return ERR_PTR(err);
-}
-
-/* Cleanup netpoll for given target (from boot/module param) and free it */
-static void free_param_target(struct netconsole_target *nt)
-{
- netpoll_cleanup(&nt->np);
- kfree(nt);
-}
-
#ifdef CONFIG_NETCONSOLE_DYNAMIC
/*
@@ -675,6 +629,23 @@ static const struct config_item_type netconsole_target_type = {
.ct_owner = THIS_MODULE,
};
+static struct netconsole_target *find_cmdline_target(const char *name)
+{
+ struct netconsole_target *nt, *ret = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&target_list_lock, flags);
+ list_for_each_entry(nt, &target_list, list) {
+ if (!strcmp(nt->item.ci_name, name)) {
+ ret = nt;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&target_list_lock, flags);
+
+ return ret;
+}
+
/*
* Group operations and type for netconsole_subsys.
*/
@@ -685,6 +656,17 @@ static struct config_item *make_netconsole_target(struct config_group *group,
struct netconsole_target *nt;
unsigned long flags;
+ /* Checking if a target by this name was created at boot time. If so,
+ * attach a configfs entry to that target. This enables dynamic
+ * control.
+ */
+ if (!strncmp(name, NETCONSOLE_PARAM_TARGET_PREFIX,
+ strlen(NETCONSOLE_PARAM_TARGET_PREFIX))) {
+ nt = find_cmdline_target(name);
+ if (nt)
+ return &nt->item;
+ }
+
nt = alloc_and_init();
if (!nt)
return ERR_PTR(-ENOMEM);
@@ -740,6 +722,17 @@ static struct configfs_subsystem netconsole_subsys = {
},
};
+static void populate_configfs_item(struct netconsole_target *nt,
+ int cmdline_count)
+{
+ char target_name[16];
+
+ snprintf(target_name, sizeof(target_name), "%s%d",
+ NETCONSOLE_PARAM_TARGET_PREFIX, cmdline_count);
+ config_item_init_type_name(&nt->item, target_name,
+ &netconsole_target_type);
+}
+
#endif /* CONFIG_NETCONSOLE_DYNAMIC */
/* Handle network interface device notifications */
@@ -938,6 +931,60 @@ static void write_msg(struct console *con, const char *msg, unsigned int len)
spin_unlock_irqrestore(&target_list_lock, flags);
}
+/* Allocate new target (from boot/module param) and setup netpoll for it */
+static struct netconsole_target *alloc_param_target(char *target_config,
+ int cmdline_count)
+{
+ struct netconsole_target *nt;
+ int err;
+
+ nt = alloc_and_init();
+ if (!nt) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ if (*target_config == '+') {
+ nt->extended = true;
+ target_config++;
+ }
+
+ if (*target_config == 'r') {
+ if (!nt->extended) {
+ pr_err("Netconsole configuration error. Release feature requires extended log message");
+ err = -EINVAL;
+ goto fail;
+ }
+ nt->release = true;
+ target_config++;
+ }
+
+ /* Parse parameters and setup netpoll */
+ err = netpoll_parse_options(&nt->np, target_config);
+ if (err)
+ goto fail;
+
+ err = netpoll_setup(&nt->np);
+ if (err)
+ goto fail;
+
+ populate_configfs_item(nt, cmdline_count);
+ nt->enabled = true;
+
+ return nt;
+
+fail:
+ kfree(nt);
+ return ERR_PTR(err);
+}
+
+/* Cleanup netpoll for given target (from boot/module param) and free it */
+static void free_param_target(struct netconsole_target *nt)
+{
+ netpoll_cleanup(&nt->np);
+ kfree(nt);
+}
+
static struct console netconsole_ext = {
.name = "netcon_ext",
.flags = CON_ENABLED | CON_EXTENDED,
@@ -954,6 +1001,7 @@ static int __init init_netconsole(void)
{
int err;
struct netconsole_target *nt, *tmp;
+ unsigned int count = 0;
bool extended = false;
unsigned long flags;
char *target_config;
@@ -961,7 +1009,7 @@ static int __init init_netconsole(void)
if (strnlen(input, MAX_PARAM_LENGTH)) {
while ((target_config = strsep(&input, ";"))) {
- nt = alloc_param_target(target_config);
+ nt = alloc_param_target(target_config, count);
if (IS_ERR(nt)) {
err = PTR_ERR(nt);
goto fail;
@@ -977,6 +1025,7 @@ static int __init init_netconsole(void)
spin_lock_irqsave(&target_list_lock, flags);
list_add(&nt->list, &target_list);
spin_unlock_irqrestore(&target_list_lock, flags);
+ count++;
}
}