11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/drivers/net/netconsole.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001 Ingo Molnar <mingo@redhat.com> 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This file contains the implementation of an IRQ-safe, crash-safe 71da177e4SLinus Torvalds * kernel console implementation that outputs kernel messages to the 81da177e4SLinus Torvalds * network. 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * Modification history: 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * 2001-09-17 started by Ingo Molnar. 131da177e4SLinus Torvalds * 2003-08-11 2.6 port by Matt Mackall 141da177e4SLinus Torvalds * simplified options 151da177e4SLinus Torvalds * generic card hooks 161da177e4SLinus Torvalds * works non-modular 171da177e4SLinus Torvalds * 2003-09-07 rewritten with netpoll api 181da177e4SLinus Torvalds */ 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds /**************************************************************** 211da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 221da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 231da177e4SLinus Torvalds * the Free Software Foundation; either version 2, or (at your option) 241da177e4SLinus Torvalds * any later version. 251da177e4SLinus Torvalds * 261da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 271da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 281da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 291da177e4SLinus Torvalds * GNU General Public License for more details. 301da177e4SLinus Torvalds * 311da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 321da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 331da177e4SLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 341da177e4SLinus Torvalds * 351da177e4SLinus Torvalds ****************************************************************/ 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds #include <linux/mm.h> 381da177e4SLinus Torvalds #include <linux/init.h> 391da177e4SLinus Torvalds #include <linux/module.h> 405a0e3ad6STejun Heo #include <linux/slab.h> 411da177e4SLinus Torvalds #include <linux/console.h> 421da177e4SLinus Torvalds #include <linux/moduleparam.h> 434cd5773aSAndy Shevchenko #include <linux/kernel.h> 441da177e4SLinus Torvalds #include <linux/string.h> 451da177e4SLinus Torvalds #include <linux/netpoll.h> 460bcc1816SSatyam Sharma #include <linux/inet.h> 470bcc1816SSatyam Sharma #include <linux/configfs.h> 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>"); 501da177e4SLinus Torvalds MODULE_DESCRIPTION("Console driver for network interfaces"); 511da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 521da177e4SLinus Torvalds 53d39badf0SSatyam Sharma #define MAX_PARAM_LENGTH 256 54d39badf0SSatyam Sharma #define MAX_PRINT_CHUNK 1000 55d39badf0SSatyam Sharma 56d39badf0SSatyam Sharma static char config[MAX_PARAM_LENGTH]; 57d39badf0SSatyam Sharma module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0); 5861a2d07dSNiels de Vos MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]"); 591da177e4SLinus Torvalds 60c1a60851SAmerigo Wang static bool oops_only = false; 61c1a60851SAmerigo Wang module_param(oops_only, bool, 0600); 62c1a60851SAmerigo Wang MODULE_PARM_DESC(oops_only, "Only log oops messages"); 63c1a60851SAmerigo Wang 64d2b60881SSatyam Sharma #ifndef MODULE 65d2b60881SSatyam Sharma static int __init option_setup(char *opt) 66d2b60881SSatyam Sharma { 67d2b60881SSatyam Sharma strlcpy(config, opt, MAX_PARAM_LENGTH); 68d2b60881SSatyam Sharma return 1; 69d2b60881SSatyam Sharma } 70d2b60881SSatyam Sharma __setup("netconsole=", option_setup); 71d2b60881SSatyam Sharma #endif /* MODULE */ 72d2b60881SSatyam Sharma 73b5427c27SSatyam Sharma /* Linked list of all configured targets */ 74b5427c27SSatyam Sharma static LIST_HEAD(target_list); 75b5427c27SSatyam Sharma 76b5427c27SSatyam Sharma /* This needs to be a spinlock because write_msg() cannot sleep */ 77b5427c27SSatyam Sharma static DEFINE_SPINLOCK(target_list_lock); 78b5427c27SSatyam Sharma 79df180e36SSatyam Sharma /** 80df180e36SSatyam Sharma * struct netconsole_target - Represents a configured netconsole target. 81b5427c27SSatyam Sharma * @list: Links this target into the target_list. 820bcc1816SSatyam Sharma * @item: Links us into the configfs subsystem hierarchy. 830bcc1816SSatyam Sharma * @enabled: On / off knob to enable / disable target. 840bcc1816SSatyam Sharma * Visible from userspace (read-write). 850bcc1816SSatyam Sharma * We maintain a strict 1:1 correspondence between this and 860bcc1816SSatyam Sharma * whether the corresponding netpoll is active or inactive. 870bcc1816SSatyam Sharma * Also, other parameters of a target may be modified at 880bcc1816SSatyam Sharma * runtime only when it is disabled (enabled == 0). 89df180e36SSatyam Sharma * @np: The netpoll structure for this target. 900bcc1816SSatyam Sharma * Contains the other userspace visible parameters: 910bcc1816SSatyam Sharma * dev_name (read-write) 920bcc1816SSatyam Sharma * local_port (read-write) 930bcc1816SSatyam Sharma * remote_port (read-write) 940bcc1816SSatyam Sharma * local_ip (read-write) 950bcc1816SSatyam Sharma * remote_ip (read-write) 960bcc1816SSatyam Sharma * local_mac (read-only) 970bcc1816SSatyam Sharma * remote_mac (read-write) 98df180e36SSatyam Sharma */ 99df180e36SSatyam Sharma struct netconsole_target { 100b5427c27SSatyam Sharma struct list_head list; 1010bcc1816SSatyam Sharma #ifdef CONFIG_NETCONSOLE_DYNAMIC 1020bcc1816SSatyam Sharma struct config_item item; 1030bcc1816SSatyam Sharma #endif 1040bcc1816SSatyam Sharma int enabled; 1057a163bfbSDan Aloni struct mutex mutex; 106df180e36SSatyam Sharma struct netpoll np; 107df180e36SSatyam Sharma }; 108df180e36SSatyam Sharma 1090bcc1816SSatyam Sharma #ifdef CONFIG_NETCONSOLE_DYNAMIC 1100bcc1816SSatyam Sharma 1110bcc1816SSatyam Sharma static struct configfs_subsystem netconsole_subsys; 1120bcc1816SSatyam Sharma 1130bcc1816SSatyam Sharma static int __init dynamic_netconsole_init(void) 1140bcc1816SSatyam Sharma { 1150bcc1816SSatyam Sharma config_group_init(&netconsole_subsys.su_group); 1160bcc1816SSatyam Sharma mutex_init(&netconsole_subsys.su_mutex); 1170bcc1816SSatyam Sharma return configfs_register_subsystem(&netconsole_subsys); 1180bcc1816SSatyam Sharma } 1190bcc1816SSatyam Sharma 1200bcc1816SSatyam Sharma static void __exit dynamic_netconsole_exit(void) 1210bcc1816SSatyam Sharma { 1220bcc1816SSatyam Sharma configfs_unregister_subsystem(&netconsole_subsys); 1230bcc1816SSatyam Sharma } 1240bcc1816SSatyam Sharma 1250bcc1816SSatyam Sharma /* 1260bcc1816SSatyam Sharma * Targets that were created by parsing the boot/module option string 1270bcc1816SSatyam Sharma * do not exist in the configfs hierarchy (and have NULL names) and will 1280bcc1816SSatyam Sharma * never go away, so make these a no-op for them. 1290bcc1816SSatyam Sharma */ 1300bcc1816SSatyam Sharma static void netconsole_target_get(struct netconsole_target *nt) 1310bcc1816SSatyam Sharma { 1320bcc1816SSatyam Sharma if (config_item_name(&nt->item)) 1330bcc1816SSatyam Sharma config_item_get(&nt->item); 1340bcc1816SSatyam Sharma } 1350bcc1816SSatyam Sharma 1360bcc1816SSatyam Sharma static void netconsole_target_put(struct netconsole_target *nt) 1370bcc1816SSatyam Sharma { 1380bcc1816SSatyam Sharma if (config_item_name(&nt->item)) 1390bcc1816SSatyam Sharma config_item_put(&nt->item); 1400bcc1816SSatyam Sharma } 1410bcc1816SSatyam Sharma 1420bcc1816SSatyam Sharma #else /* !CONFIG_NETCONSOLE_DYNAMIC */ 1430bcc1816SSatyam Sharma 1440bcc1816SSatyam Sharma static int __init dynamic_netconsole_init(void) 1450bcc1816SSatyam Sharma { 1460bcc1816SSatyam Sharma return 0; 1470bcc1816SSatyam Sharma } 1480bcc1816SSatyam Sharma 1490bcc1816SSatyam Sharma static void __exit dynamic_netconsole_exit(void) 1500bcc1816SSatyam Sharma { 1510bcc1816SSatyam Sharma } 1520bcc1816SSatyam Sharma 1530bcc1816SSatyam Sharma /* 1540bcc1816SSatyam Sharma * No danger of targets going away from under us when dynamic 1550bcc1816SSatyam Sharma * reconfigurability is off. 1560bcc1816SSatyam Sharma */ 1570bcc1816SSatyam Sharma static void netconsole_target_get(struct netconsole_target *nt) 1580bcc1816SSatyam Sharma { 1590bcc1816SSatyam Sharma } 1600bcc1816SSatyam Sharma 1610bcc1816SSatyam Sharma static void netconsole_target_put(struct netconsole_target *nt) 1620bcc1816SSatyam Sharma { 1630bcc1816SSatyam Sharma } 1640bcc1816SSatyam Sharma 1650bcc1816SSatyam Sharma #endif /* CONFIG_NETCONSOLE_DYNAMIC */ 1660bcc1816SSatyam Sharma 1670bcc1816SSatyam Sharma /* Allocate new target (from boot/module param) and setup netpoll for it */ 1680bcc1816SSatyam Sharma static struct netconsole_target *alloc_param_target(char *target_config) 169b5427c27SSatyam Sharma { 170b5427c27SSatyam Sharma int err = -ENOMEM; 171b5427c27SSatyam Sharma struct netconsole_target *nt; 172b5427c27SSatyam Sharma 1730bcc1816SSatyam Sharma /* 1740bcc1816SSatyam Sharma * Allocate and initialize with defaults. 1750bcc1816SSatyam Sharma * Note that these targets get their config_item fields zeroed-out. 1760bcc1816SSatyam Sharma */ 177b5427c27SSatyam Sharma nt = kzalloc(sizeof(*nt), GFP_KERNEL); 178e404decbSJoe Perches if (!nt) 179b5427c27SSatyam Sharma goto fail; 180b5427c27SSatyam Sharma 181b5427c27SSatyam Sharma nt->np.name = "netconsole"; 182b5427c27SSatyam Sharma strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); 183b5427c27SSatyam Sharma nt->np.local_port = 6665; 184b5427c27SSatyam Sharma nt->np.remote_port = 6666; 1857a163bfbSDan Aloni mutex_init(&nt->mutex); 186b5427c27SSatyam Sharma memset(nt->np.remote_mac, 0xff, ETH_ALEN); 187b5427c27SSatyam Sharma 188b5427c27SSatyam Sharma /* Parse parameters and setup netpoll */ 189b5427c27SSatyam Sharma err = netpoll_parse_options(&nt->np, target_config); 190b5427c27SSatyam Sharma if (err) 191b5427c27SSatyam Sharma goto fail; 192b5427c27SSatyam Sharma 193b5427c27SSatyam Sharma err = netpoll_setup(&nt->np); 194b5427c27SSatyam Sharma if (err) 195b5427c27SSatyam Sharma goto fail; 196b5427c27SSatyam Sharma 1970bcc1816SSatyam Sharma nt->enabled = 1; 1980bcc1816SSatyam Sharma 199b5427c27SSatyam Sharma return nt; 200b5427c27SSatyam Sharma 201b5427c27SSatyam Sharma fail: 202b5427c27SSatyam Sharma kfree(nt); 203b5427c27SSatyam Sharma return ERR_PTR(err); 204b5427c27SSatyam Sharma } 205b5427c27SSatyam Sharma 2060bcc1816SSatyam Sharma /* Cleanup netpoll for given target (from boot/module param) and free it */ 2070bcc1816SSatyam Sharma static void free_param_target(struct netconsole_target *nt) 208b5427c27SSatyam Sharma { 209b5427c27SSatyam Sharma netpoll_cleanup(&nt->np); 210b5427c27SSatyam Sharma kfree(nt); 211b5427c27SSatyam Sharma } 2121da177e4SLinus Torvalds 2130bcc1816SSatyam Sharma #ifdef CONFIG_NETCONSOLE_DYNAMIC 2140bcc1816SSatyam Sharma 2150bcc1816SSatyam Sharma /* 2160bcc1816SSatyam Sharma * Our subsystem hierarchy is: 2170bcc1816SSatyam Sharma * 2180bcc1816SSatyam Sharma * /sys/kernel/config/netconsole/ 2190bcc1816SSatyam Sharma * | 2200bcc1816SSatyam Sharma * <target>/ 2210bcc1816SSatyam Sharma * | enabled 2220bcc1816SSatyam Sharma * | dev_name 2230bcc1816SSatyam Sharma * | local_port 2240bcc1816SSatyam Sharma * | remote_port 2250bcc1816SSatyam Sharma * | local_ip 2260bcc1816SSatyam Sharma * | remote_ip 2270bcc1816SSatyam Sharma * | local_mac 2280bcc1816SSatyam Sharma * | remote_mac 2290bcc1816SSatyam Sharma * | 2300bcc1816SSatyam Sharma * <target>/... 2310bcc1816SSatyam Sharma */ 2320bcc1816SSatyam Sharma 2330bcc1816SSatyam Sharma struct netconsole_target_attr { 2340bcc1816SSatyam Sharma struct configfs_attribute attr; 2350bcc1816SSatyam Sharma ssize_t (*show)(struct netconsole_target *nt, 2360bcc1816SSatyam Sharma char *buf); 2370bcc1816SSatyam Sharma ssize_t (*store)(struct netconsole_target *nt, 2380bcc1816SSatyam Sharma const char *buf, 2390bcc1816SSatyam Sharma size_t count); 2400bcc1816SSatyam Sharma }; 2410bcc1816SSatyam Sharma 2420bcc1816SSatyam Sharma static struct netconsole_target *to_target(struct config_item *item) 2430bcc1816SSatyam Sharma { 2440bcc1816SSatyam Sharma return item ? 2450bcc1816SSatyam Sharma container_of(item, struct netconsole_target, item) : 2460bcc1816SSatyam Sharma NULL; 2470bcc1816SSatyam Sharma } 2480bcc1816SSatyam Sharma 2490bcc1816SSatyam Sharma /* 2500bcc1816SSatyam Sharma * Attribute operations for netconsole_target. 2510bcc1816SSatyam Sharma */ 2520bcc1816SSatyam Sharma 2530bcc1816SSatyam Sharma static ssize_t show_enabled(struct netconsole_target *nt, char *buf) 2540bcc1816SSatyam Sharma { 2550bcc1816SSatyam Sharma return snprintf(buf, PAGE_SIZE, "%d\n", nt->enabled); 2560bcc1816SSatyam Sharma } 2570bcc1816SSatyam Sharma 2580bcc1816SSatyam Sharma static ssize_t show_dev_name(struct netconsole_target *nt, char *buf) 2590bcc1816SSatyam Sharma { 2600bcc1816SSatyam Sharma return snprintf(buf, PAGE_SIZE, "%s\n", nt->np.dev_name); 2610bcc1816SSatyam Sharma } 2620bcc1816SSatyam Sharma 2630bcc1816SSatyam Sharma static ssize_t show_local_port(struct netconsole_target *nt, char *buf) 2640bcc1816SSatyam Sharma { 2650bcc1816SSatyam Sharma return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.local_port); 2660bcc1816SSatyam Sharma } 2670bcc1816SSatyam Sharma 2680bcc1816SSatyam Sharma static ssize_t show_remote_port(struct netconsole_target *nt, char *buf) 2690bcc1816SSatyam Sharma { 2700bcc1816SSatyam Sharma return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.remote_port); 2710bcc1816SSatyam Sharma } 2720bcc1816SSatyam Sharma 2730bcc1816SSatyam Sharma static ssize_t show_local_ip(struct netconsole_target *nt, char *buf) 2740bcc1816SSatyam Sharma { 275b3d936f3SCong Wang if (nt->np.ipv6) 276b3d936f3SCong Wang return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6); 277b3d936f3SCong Wang else 278e7557af5SHarvey Harrison return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip); 2790bcc1816SSatyam Sharma } 2800bcc1816SSatyam Sharma 2810bcc1816SSatyam Sharma static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf) 2820bcc1816SSatyam Sharma { 283b3d936f3SCong Wang if (nt->np.ipv6) 284b3d936f3SCong Wang return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6); 285b3d936f3SCong Wang else 286e7557af5SHarvey Harrison return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip); 2870bcc1816SSatyam Sharma } 2880bcc1816SSatyam Sharma 2890bcc1816SSatyam Sharma static ssize_t show_local_mac(struct netconsole_target *nt, char *buf) 2900bcc1816SSatyam Sharma { 29109538641SStephen Hemminger struct net_device *dev = nt->np.dev; 292e174961cSJohannes Berg static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 29309538641SStephen Hemminger 294e174961cSJohannes Berg return snprintf(buf, PAGE_SIZE, "%pM\n", dev ? dev->dev_addr : bcast); 2950bcc1816SSatyam Sharma } 2960bcc1816SSatyam Sharma 2970bcc1816SSatyam Sharma static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf) 2980bcc1816SSatyam Sharma { 299e174961cSJohannes Berg return snprintf(buf, PAGE_SIZE, "%pM\n", nt->np.remote_mac); 3000bcc1816SSatyam Sharma } 3010bcc1816SSatyam Sharma 3020bcc1816SSatyam Sharma /* 3030bcc1816SSatyam Sharma * This one is special -- targets created through the configfs interface 3040bcc1816SSatyam Sharma * are not enabled (and the corresponding netpoll activated) by default. 3050bcc1816SSatyam Sharma * The user is expected to set the desired parameters first (which 3060bcc1816SSatyam Sharma * would enable him to dynamically add new netpoll targets for new 3070bcc1816SSatyam Sharma * network interfaces as and when they come up). 3080bcc1816SSatyam Sharma */ 3090bcc1816SSatyam Sharma static ssize_t store_enabled(struct netconsole_target *nt, 3100bcc1816SSatyam Sharma const char *buf, 3110bcc1816SSatyam Sharma size_t count) 3120bcc1816SSatyam Sharma { 31399f823f9SAlexey Dobriyan int enabled; 3140bcc1816SSatyam Sharma int err; 3150bcc1816SSatyam Sharma 31699f823f9SAlexey Dobriyan err = kstrtoint(buf, 10, &enabled); 31799f823f9SAlexey Dobriyan if (err < 0) 31899f823f9SAlexey Dobriyan return err; 31999f823f9SAlexey Dobriyan if (enabled < 0 || enabled > 1) 32099f823f9SAlexey Dobriyan return -EINVAL; 321d5123480SGao feng if (enabled == nt->enabled) { 322d5123480SGao feng printk(KERN_INFO "netconsole: network logging has already %s\n", 323d5123480SGao feng nt->enabled ? "started" : "stopped"); 324d5123480SGao feng return -EINVAL; 325d5123480SGao feng } 3260bcc1816SSatyam Sharma 3277a163bfbSDan Aloni mutex_lock(&nt->mutex); 3280bcc1816SSatyam Sharma if (enabled) { /* 1 */ 3290bcc1816SSatyam Sharma 3300bcc1816SSatyam Sharma /* 3310bcc1816SSatyam Sharma * Skip netpoll_parse_options() -- all the attributes are 3320bcc1816SSatyam Sharma * already configured via configfs. Just print them out. 3330bcc1816SSatyam Sharma */ 3340bcc1816SSatyam Sharma netpoll_print_options(&nt->np); 3350bcc1816SSatyam Sharma 3360bcc1816SSatyam Sharma err = netpoll_setup(&nt->np); 3377a163bfbSDan Aloni if (err) { 3387a163bfbSDan Aloni mutex_unlock(&nt->mutex); 3390bcc1816SSatyam Sharma return err; 3407a163bfbSDan Aloni } 3410bcc1816SSatyam Sharma 3420bcc1816SSatyam Sharma printk(KERN_INFO "netconsole: network logging started\n"); 3430bcc1816SSatyam Sharma 3440bcc1816SSatyam Sharma } else { /* 0 */ 3450bcc1816SSatyam Sharma netpoll_cleanup(&nt->np); 3460bcc1816SSatyam Sharma } 3470bcc1816SSatyam Sharma 3480bcc1816SSatyam Sharma nt->enabled = enabled; 3497a163bfbSDan Aloni mutex_unlock(&nt->mutex); 3500bcc1816SSatyam Sharma 3510bcc1816SSatyam Sharma return strnlen(buf, count); 3520bcc1816SSatyam Sharma } 3530bcc1816SSatyam Sharma 3540bcc1816SSatyam Sharma static ssize_t store_dev_name(struct netconsole_target *nt, 3550bcc1816SSatyam Sharma const char *buf, 3560bcc1816SSatyam Sharma size_t count) 3570bcc1816SSatyam Sharma { 3580bcc1816SSatyam Sharma size_t len; 3590bcc1816SSatyam Sharma 3600bcc1816SSatyam Sharma if (nt->enabled) { 3610bcc1816SSatyam Sharma printk(KERN_ERR "netconsole: target (%s) is enabled, " 3620bcc1816SSatyam Sharma "disable to update parameters\n", 3630bcc1816SSatyam Sharma config_item_name(&nt->item)); 3640bcc1816SSatyam Sharma return -EINVAL; 3650bcc1816SSatyam Sharma } 3660bcc1816SSatyam Sharma 3670bcc1816SSatyam Sharma strlcpy(nt->np.dev_name, buf, IFNAMSIZ); 3680bcc1816SSatyam Sharma 3690bcc1816SSatyam Sharma /* Get rid of possible trailing newline from echo(1) */ 3700bcc1816SSatyam Sharma len = strnlen(nt->np.dev_name, IFNAMSIZ); 3710bcc1816SSatyam Sharma if (nt->np.dev_name[len - 1] == '\n') 3720bcc1816SSatyam Sharma nt->np.dev_name[len - 1] = '\0'; 3730bcc1816SSatyam Sharma 3740bcc1816SSatyam Sharma return strnlen(buf, count); 3750bcc1816SSatyam Sharma } 3760bcc1816SSatyam Sharma 3770bcc1816SSatyam Sharma static ssize_t store_local_port(struct netconsole_target *nt, 3780bcc1816SSatyam Sharma const char *buf, 3790bcc1816SSatyam Sharma size_t count) 3800bcc1816SSatyam Sharma { 38199f823f9SAlexey Dobriyan int rv; 3820bcc1816SSatyam Sharma 3830bcc1816SSatyam Sharma if (nt->enabled) { 3840bcc1816SSatyam Sharma printk(KERN_ERR "netconsole: target (%s) is enabled, " 3850bcc1816SSatyam Sharma "disable to update parameters\n", 3860bcc1816SSatyam Sharma config_item_name(&nt->item)); 3870bcc1816SSatyam Sharma return -EINVAL; 3880bcc1816SSatyam Sharma } 3890bcc1816SSatyam Sharma 39099f823f9SAlexey Dobriyan rv = kstrtou16(buf, 10, &nt->np.local_port); 39199f823f9SAlexey Dobriyan if (rv < 0) 39299f823f9SAlexey Dobriyan return rv; 3930bcc1816SSatyam Sharma return strnlen(buf, count); 3940bcc1816SSatyam Sharma } 3950bcc1816SSatyam Sharma 3960bcc1816SSatyam Sharma static ssize_t store_remote_port(struct netconsole_target *nt, 3970bcc1816SSatyam Sharma const char *buf, 3980bcc1816SSatyam Sharma size_t count) 3990bcc1816SSatyam Sharma { 40099f823f9SAlexey Dobriyan int rv; 4010bcc1816SSatyam Sharma 4020bcc1816SSatyam Sharma if (nt->enabled) { 4030bcc1816SSatyam Sharma printk(KERN_ERR "netconsole: target (%s) is enabled, " 4040bcc1816SSatyam Sharma "disable to update parameters\n", 4050bcc1816SSatyam Sharma config_item_name(&nt->item)); 4060bcc1816SSatyam Sharma return -EINVAL; 4070bcc1816SSatyam Sharma } 4080bcc1816SSatyam Sharma 40999f823f9SAlexey Dobriyan rv = kstrtou16(buf, 10, &nt->np.remote_port); 41099f823f9SAlexey Dobriyan if (rv < 0) 41199f823f9SAlexey Dobriyan return rv; 4120bcc1816SSatyam Sharma return strnlen(buf, count); 4130bcc1816SSatyam Sharma } 4140bcc1816SSatyam Sharma 4150bcc1816SSatyam Sharma static ssize_t store_local_ip(struct netconsole_target *nt, 4160bcc1816SSatyam Sharma const char *buf, 4170bcc1816SSatyam Sharma size_t count) 4180bcc1816SSatyam Sharma { 4190bcc1816SSatyam Sharma if (nt->enabled) { 4200bcc1816SSatyam Sharma printk(KERN_ERR "netconsole: target (%s) is enabled, " 4210bcc1816SSatyam Sharma "disable to update parameters\n", 4220bcc1816SSatyam Sharma config_item_name(&nt->item)); 4230bcc1816SSatyam Sharma return -EINVAL; 4240bcc1816SSatyam Sharma } 4250bcc1816SSatyam Sharma 426b3d936f3SCong Wang if (strnchr(buf, count, ':')) { 427b3d936f3SCong Wang const char *end; 428b3d936f3SCong Wang if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) { 429b3d936f3SCong Wang if (*end && *end != '\n') { 430b3d936f3SCong Wang printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end); 431b3d936f3SCong Wang return -EINVAL; 432b3d936f3SCong Wang } 433b3d936f3SCong Wang nt->np.ipv6 = true; 434b3d936f3SCong Wang } else 435b3d936f3SCong Wang return -EINVAL; 436b3d936f3SCong Wang } else { 437b3d936f3SCong Wang if (!nt->np.ipv6) { 438b7394d24SCong Wang nt->np.local_ip.ip = in_aton(buf); 439b3d936f3SCong Wang } else 440b3d936f3SCong Wang return -EINVAL; 441b3d936f3SCong Wang } 4420bcc1816SSatyam Sharma 4430bcc1816SSatyam Sharma return strnlen(buf, count); 4440bcc1816SSatyam Sharma } 4450bcc1816SSatyam Sharma 4460bcc1816SSatyam Sharma static ssize_t store_remote_ip(struct netconsole_target *nt, 4470bcc1816SSatyam Sharma const char *buf, 4480bcc1816SSatyam Sharma size_t count) 4490bcc1816SSatyam Sharma { 4500bcc1816SSatyam Sharma if (nt->enabled) { 4510bcc1816SSatyam Sharma printk(KERN_ERR "netconsole: target (%s) is enabled, " 4520bcc1816SSatyam Sharma "disable to update parameters\n", 4530bcc1816SSatyam Sharma config_item_name(&nt->item)); 4540bcc1816SSatyam Sharma return -EINVAL; 4550bcc1816SSatyam Sharma } 4560bcc1816SSatyam Sharma 457b3d936f3SCong Wang if (strnchr(buf, count, ':')) { 458b3d936f3SCong Wang const char *end; 459b3d936f3SCong Wang if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) { 460b3d936f3SCong Wang if (*end && *end != '\n') { 461b3d936f3SCong Wang printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end); 462b3d936f3SCong Wang return -EINVAL; 463b3d936f3SCong Wang } 464b3d936f3SCong Wang nt->np.ipv6 = true; 465b3d936f3SCong Wang } else 466b3d936f3SCong Wang return -EINVAL; 467b3d936f3SCong Wang } else { 468b3d936f3SCong Wang if (!nt->np.ipv6) { 469b7394d24SCong Wang nt->np.remote_ip.ip = in_aton(buf); 470b3d936f3SCong Wang } else 471b3d936f3SCong Wang return -EINVAL; 472b3d936f3SCong Wang } 4730bcc1816SSatyam Sharma 4740bcc1816SSatyam Sharma return strnlen(buf, count); 4750bcc1816SSatyam Sharma } 4760bcc1816SSatyam Sharma 4770bcc1816SSatyam Sharma static ssize_t store_remote_mac(struct netconsole_target *nt, 4780bcc1816SSatyam Sharma const char *buf, 4790bcc1816SSatyam Sharma size_t count) 4800bcc1816SSatyam Sharma { 4810bcc1816SSatyam Sharma u8 remote_mac[ETH_ALEN]; 4820bcc1816SSatyam Sharma 4830bcc1816SSatyam Sharma if (nt->enabled) { 4840bcc1816SSatyam Sharma printk(KERN_ERR "netconsole: target (%s) is enabled, " 4850bcc1816SSatyam Sharma "disable to update parameters\n", 4860bcc1816SSatyam Sharma config_item_name(&nt->item)); 4870bcc1816SSatyam Sharma return -EINVAL; 4880bcc1816SSatyam Sharma } 4890bcc1816SSatyam Sharma 4904940fc88SAlexey Dobriyan if (!mac_pton(buf, remote_mac)) 4914940fc88SAlexey Dobriyan return -EINVAL; 4924940fc88SAlexey Dobriyan if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n') 4934940fc88SAlexey Dobriyan return -EINVAL; 4940bcc1816SSatyam Sharma memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); 4950bcc1816SSatyam Sharma 4960bcc1816SSatyam Sharma return strnlen(buf, count); 4970bcc1816SSatyam Sharma } 4980bcc1816SSatyam Sharma 4990bcc1816SSatyam Sharma /* 5000bcc1816SSatyam Sharma * Attribute definitions for netconsole_target. 5010bcc1816SSatyam Sharma */ 5020bcc1816SSatyam Sharma 5030bcc1816SSatyam Sharma #define NETCONSOLE_TARGET_ATTR_RO(_name) \ 5040bcc1816SSatyam Sharma static struct netconsole_target_attr netconsole_target_##_name = \ 5050bcc1816SSatyam Sharma __CONFIGFS_ATTR(_name, S_IRUGO, show_##_name, NULL) 5060bcc1816SSatyam Sharma 5070bcc1816SSatyam Sharma #define NETCONSOLE_TARGET_ATTR_RW(_name) \ 5080bcc1816SSatyam Sharma static struct netconsole_target_attr netconsole_target_##_name = \ 5090bcc1816SSatyam Sharma __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name) 5100bcc1816SSatyam Sharma 5110bcc1816SSatyam Sharma NETCONSOLE_TARGET_ATTR_RW(enabled); 5120bcc1816SSatyam Sharma NETCONSOLE_TARGET_ATTR_RW(dev_name); 5130bcc1816SSatyam Sharma NETCONSOLE_TARGET_ATTR_RW(local_port); 5140bcc1816SSatyam Sharma NETCONSOLE_TARGET_ATTR_RW(remote_port); 5150bcc1816SSatyam Sharma NETCONSOLE_TARGET_ATTR_RW(local_ip); 5160bcc1816SSatyam Sharma NETCONSOLE_TARGET_ATTR_RW(remote_ip); 5170bcc1816SSatyam Sharma NETCONSOLE_TARGET_ATTR_RO(local_mac); 5180bcc1816SSatyam Sharma NETCONSOLE_TARGET_ATTR_RW(remote_mac); 5190bcc1816SSatyam Sharma 5200bcc1816SSatyam Sharma static struct configfs_attribute *netconsole_target_attrs[] = { 5210bcc1816SSatyam Sharma &netconsole_target_enabled.attr, 5220bcc1816SSatyam Sharma &netconsole_target_dev_name.attr, 5230bcc1816SSatyam Sharma &netconsole_target_local_port.attr, 5240bcc1816SSatyam Sharma &netconsole_target_remote_port.attr, 5250bcc1816SSatyam Sharma &netconsole_target_local_ip.attr, 5260bcc1816SSatyam Sharma &netconsole_target_remote_ip.attr, 5270bcc1816SSatyam Sharma &netconsole_target_local_mac.attr, 5280bcc1816SSatyam Sharma &netconsole_target_remote_mac.attr, 5290bcc1816SSatyam Sharma NULL, 5300bcc1816SSatyam Sharma }; 5310bcc1816SSatyam Sharma 5320bcc1816SSatyam Sharma /* 5330bcc1816SSatyam Sharma * Item operations and type for netconsole_target. 5340bcc1816SSatyam Sharma */ 5350bcc1816SSatyam Sharma 5360bcc1816SSatyam Sharma static void netconsole_target_release(struct config_item *item) 5370bcc1816SSatyam Sharma { 5380bcc1816SSatyam Sharma kfree(to_target(item)); 5390bcc1816SSatyam Sharma } 5400bcc1816SSatyam Sharma 5410bcc1816SSatyam Sharma static ssize_t netconsole_target_attr_show(struct config_item *item, 5420bcc1816SSatyam Sharma struct configfs_attribute *attr, 5430bcc1816SSatyam Sharma char *buf) 5440bcc1816SSatyam Sharma { 5450bcc1816SSatyam Sharma ssize_t ret = -EINVAL; 5460bcc1816SSatyam Sharma struct netconsole_target *nt = to_target(item); 5470bcc1816SSatyam Sharma struct netconsole_target_attr *na = 5480bcc1816SSatyam Sharma container_of(attr, struct netconsole_target_attr, attr); 5490bcc1816SSatyam Sharma 5500bcc1816SSatyam Sharma if (na->show) 5510bcc1816SSatyam Sharma ret = na->show(nt, buf); 5520bcc1816SSatyam Sharma 5530bcc1816SSatyam Sharma return ret; 5540bcc1816SSatyam Sharma } 5550bcc1816SSatyam Sharma 5560bcc1816SSatyam Sharma static ssize_t netconsole_target_attr_store(struct config_item *item, 5570bcc1816SSatyam Sharma struct configfs_attribute *attr, 5580bcc1816SSatyam Sharma const char *buf, 5590bcc1816SSatyam Sharma size_t count) 5600bcc1816SSatyam Sharma { 5610bcc1816SSatyam Sharma ssize_t ret = -EINVAL; 5620bcc1816SSatyam Sharma struct netconsole_target *nt = to_target(item); 5630bcc1816SSatyam Sharma struct netconsole_target_attr *na = 5640bcc1816SSatyam Sharma container_of(attr, struct netconsole_target_attr, attr); 5650bcc1816SSatyam Sharma 5660bcc1816SSatyam Sharma if (na->store) 5670bcc1816SSatyam Sharma ret = na->store(nt, buf, count); 5680bcc1816SSatyam Sharma 5690bcc1816SSatyam Sharma return ret; 5700bcc1816SSatyam Sharma } 5710bcc1816SSatyam Sharma 5720bcc1816SSatyam Sharma static struct configfs_item_operations netconsole_target_item_ops = { 5730bcc1816SSatyam Sharma .release = netconsole_target_release, 5740bcc1816SSatyam Sharma .show_attribute = netconsole_target_attr_show, 5750bcc1816SSatyam Sharma .store_attribute = netconsole_target_attr_store, 5760bcc1816SSatyam Sharma }; 5770bcc1816SSatyam Sharma 5780bcc1816SSatyam Sharma static struct config_item_type netconsole_target_type = { 5790bcc1816SSatyam Sharma .ct_attrs = netconsole_target_attrs, 5800bcc1816SSatyam Sharma .ct_item_ops = &netconsole_target_item_ops, 5810bcc1816SSatyam Sharma .ct_owner = THIS_MODULE, 5820bcc1816SSatyam Sharma }; 5830bcc1816SSatyam Sharma 5840bcc1816SSatyam Sharma /* 5850bcc1816SSatyam Sharma * Group operations and type for netconsole_subsys. 5860bcc1816SSatyam Sharma */ 5870bcc1816SSatyam Sharma 588f89ab861SJoel Becker static struct config_item *make_netconsole_target(struct config_group *group, 589f89ab861SJoel Becker const char *name) 5900bcc1816SSatyam Sharma { 5910bcc1816SSatyam Sharma unsigned long flags; 5920bcc1816SSatyam Sharma struct netconsole_target *nt; 5930bcc1816SSatyam Sharma 5940bcc1816SSatyam Sharma /* 5950bcc1816SSatyam Sharma * Allocate and initialize with defaults. 5960bcc1816SSatyam Sharma * Target is disabled at creation (enabled == 0). 5970bcc1816SSatyam Sharma */ 5980bcc1816SSatyam Sharma nt = kzalloc(sizeof(*nt), GFP_KERNEL); 599e404decbSJoe Perches if (!nt) 600a6795e9eSJoel Becker return ERR_PTR(-ENOMEM); 6010bcc1816SSatyam Sharma 6020bcc1816SSatyam Sharma nt->np.name = "netconsole"; 6030bcc1816SSatyam Sharma strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); 6040bcc1816SSatyam Sharma nt->np.local_port = 6665; 6050bcc1816SSatyam Sharma nt->np.remote_port = 6666; 6067a163bfbSDan Aloni mutex_init(&nt->mutex); 6070bcc1816SSatyam Sharma memset(nt->np.remote_mac, 0xff, ETH_ALEN); 6080bcc1816SSatyam Sharma 6090bcc1816SSatyam Sharma /* Initialize the config_item member */ 6100bcc1816SSatyam Sharma config_item_init_type_name(&nt->item, name, &netconsole_target_type); 6110bcc1816SSatyam Sharma 6120bcc1816SSatyam Sharma /* Adding, but it is disabled */ 6130bcc1816SSatyam Sharma spin_lock_irqsave(&target_list_lock, flags); 6140bcc1816SSatyam Sharma list_add(&nt->list, &target_list); 6150bcc1816SSatyam Sharma spin_unlock_irqrestore(&target_list_lock, flags); 6160bcc1816SSatyam Sharma 617f89ab861SJoel Becker return &nt->item; 6180bcc1816SSatyam Sharma } 6190bcc1816SSatyam Sharma 6200bcc1816SSatyam Sharma static void drop_netconsole_target(struct config_group *group, 6210bcc1816SSatyam Sharma struct config_item *item) 6220bcc1816SSatyam Sharma { 6230bcc1816SSatyam Sharma unsigned long flags; 6240bcc1816SSatyam Sharma struct netconsole_target *nt = to_target(item); 6250bcc1816SSatyam Sharma 6260bcc1816SSatyam Sharma spin_lock_irqsave(&target_list_lock, flags); 6270bcc1816SSatyam Sharma list_del(&nt->list); 6280bcc1816SSatyam Sharma spin_unlock_irqrestore(&target_list_lock, flags); 6290bcc1816SSatyam Sharma 6300bcc1816SSatyam Sharma /* 6310bcc1816SSatyam Sharma * The target may have never been enabled, or was manually disabled 6320bcc1816SSatyam Sharma * before being removed so netpoll may have already been cleaned up. 6330bcc1816SSatyam Sharma */ 6340bcc1816SSatyam Sharma if (nt->enabled) 6350bcc1816SSatyam Sharma netpoll_cleanup(&nt->np); 6360bcc1816SSatyam Sharma 6370bcc1816SSatyam Sharma config_item_put(&nt->item); 6380bcc1816SSatyam Sharma } 6390bcc1816SSatyam Sharma 6400bcc1816SSatyam Sharma static struct configfs_group_operations netconsole_subsys_group_ops = { 6410bcc1816SSatyam Sharma .make_item = make_netconsole_target, 6420bcc1816SSatyam Sharma .drop_item = drop_netconsole_target, 6430bcc1816SSatyam Sharma }; 6440bcc1816SSatyam Sharma 6450bcc1816SSatyam Sharma static struct config_item_type netconsole_subsys_type = { 6460bcc1816SSatyam Sharma .ct_group_ops = &netconsole_subsys_group_ops, 6470bcc1816SSatyam Sharma .ct_owner = THIS_MODULE, 6480bcc1816SSatyam Sharma }; 6490bcc1816SSatyam Sharma 6500bcc1816SSatyam Sharma /* The netconsole configfs subsystem */ 6510bcc1816SSatyam Sharma static struct configfs_subsystem netconsole_subsys = { 6520bcc1816SSatyam Sharma .su_group = { 6530bcc1816SSatyam Sharma .cg_item = { 6540bcc1816SSatyam Sharma .ci_namebuf = "netconsole", 6550bcc1816SSatyam Sharma .ci_type = &netconsole_subsys_type, 6560bcc1816SSatyam Sharma }, 6570bcc1816SSatyam Sharma }, 6580bcc1816SSatyam Sharma }; 6590bcc1816SSatyam Sharma 6600bcc1816SSatyam Sharma #endif /* CONFIG_NETCONSOLE_DYNAMIC */ 6610bcc1816SSatyam Sharma 66217951f34SSatyam Sharma /* Handle network interface device notifications */ 66317951f34SSatyam Sharma static int netconsole_netdev_event(struct notifier_block *this, 664351638e7SJiri Pirko unsigned long event, void *ptr) 66517951f34SSatyam Sharma { 666b5427c27SSatyam Sharma unsigned long flags; 667b5427c27SSatyam Sharma struct netconsole_target *nt; 668351638e7SJiri Pirko struct net_device *dev = netdev_notifier_info_to_dev(ptr); 669141dfba3SFerenc Wagner bool stopped = false; 67017951f34SSatyam Sharma 6710e34e931SWANG Cong if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER || 672daf9209bSAmerigo Wang event == NETDEV_RELEASE || event == NETDEV_JOIN)) 673b5427c27SSatyam Sharma goto done; 674b5427c27SSatyam Sharma 675b5427c27SSatyam Sharma spin_lock_irqsave(&target_list_lock, flags); 6763f315befSVeaceslav Falico restart: 677b5427c27SSatyam Sharma list_for_each_entry(nt, &target_list, list) { 6780bcc1816SSatyam Sharma netconsole_target_get(nt); 67917951f34SSatyam Sharma if (nt->np.dev == dev) { 68017951f34SSatyam Sharma switch (event) { 68117951f34SSatyam Sharma case NETDEV_CHANGENAME: 68217951f34SSatyam Sharma strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ); 68317951f34SSatyam Sharma break; 684daf9209bSAmerigo Wang case NETDEV_RELEASE: 6858d8fc29dSAmerigo Wang case NETDEV_JOIN: 6862382b15bSBruno Prémont case NETDEV_UNREGISTER: 687c71380ffSNikolay Aleksandrov /* rtnl_lock already held 6883f315befSVeaceslav Falico * we might sleep in __netpoll_cleanup() 6893b410a31SNeil Horman */ 6903f315befSVeaceslav Falico spin_unlock_irqrestore(&target_list_lock, flags); 6917a163bfbSDan Aloni 6923b410a31SNeil Horman __netpoll_cleanup(&nt->np); 6937a163bfbSDan Aloni 6943f315befSVeaceslav Falico spin_lock_irqsave(&target_list_lock, flags); 6953b410a31SNeil Horman dev_put(nt->np.dev); 6963b410a31SNeil Horman nt->np.dev = NULL; 6972382b15bSBruno Prémont nt->enabled = 0; 698141dfba3SFerenc Wagner stopped = true; 6993f315befSVeaceslav Falico netconsole_target_put(nt); 7003f315befSVeaceslav Falico goto restart; 70117951f34SSatyam Sharma } 70217951f34SSatyam Sharma } 7030bcc1816SSatyam Sharma netconsole_target_put(nt); 704b5427c27SSatyam Sharma } 705b5427c27SSatyam Sharma spin_unlock_irqrestore(&target_list_lock, flags); 7068d8fc29dSAmerigo Wang if (stopped) { 70738cfb907SFerenc Wagner printk(KERN_INFO "netconsole: network logging stopped on " 7088d8fc29dSAmerigo Wang "interface %s as it ", dev->name); 7098d8fc29dSAmerigo Wang switch (event) { 7108d8fc29dSAmerigo Wang case NETDEV_UNREGISTER: 7118d8fc29dSAmerigo Wang printk(KERN_CONT "unregistered\n"); 7128d8fc29dSAmerigo Wang break; 713daf9209bSAmerigo Wang case NETDEV_RELEASE: 7148d8fc29dSAmerigo Wang printk(KERN_CONT "released slaves\n"); 7158d8fc29dSAmerigo Wang break; 7168d8fc29dSAmerigo Wang case NETDEV_JOIN: 7178d8fc29dSAmerigo Wang printk(KERN_CONT "is joining a master device\n"); 7188d8fc29dSAmerigo Wang break; 7198d8fc29dSAmerigo Wang } 7208d8fc29dSAmerigo Wang } 72117951f34SSatyam Sharma 722b5427c27SSatyam Sharma done: 72317951f34SSatyam Sharma return NOTIFY_DONE; 72417951f34SSatyam Sharma } 72517951f34SSatyam Sharma 72617951f34SSatyam Sharma static struct notifier_block netconsole_netdev_notifier = { 72717951f34SSatyam Sharma .notifier_call = netconsole_netdev_event, 72817951f34SSatyam Sharma }; 72917951f34SSatyam Sharma 7301da177e4SLinus Torvalds static void write_msg(struct console *con, const char *msg, unsigned int len) 7311da177e4SLinus Torvalds { 7321da177e4SLinus Torvalds int frag, left; 7331da177e4SLinus Torvalds unsigned long flags; 734b5427c27SSatyam Sharma struct netconsole_target *nt; 735b5427c27SSatyam Sharma const char *tmp; 7361da177e4SLinus Torvalds 737c1a60851SAmerigo Wang if (oops_only && !oops_in_progress) 738c1a60851SAmerigo Wang return; 739b5427c27SSatyam Sharma /* Avoid taking lock and disabling interrupts unnecessarily */ 740b5427c27SSatyam Sharma if (list_empty(&target_list)) 741b5427c27SSatyam Sharma return; 742b5427c27SSatyam Sharma 743b5427c27SSatyam Sharma spin_lock_irqsave(&target_list_lock, flags); 744b5427c27SSatyam Sharma list_for_each_entry(nt, &target_list, list) { 7450bcc1816SSatyam Sharma netconsole_target_get(nt); 7460bcc1816SSatyam Sharma if (nt->enabled && netif_running(nt->np.dev)) { 747b5427c27SSatyam Sharma /* 748b5427c27SSatyam Sharma * We nest this inside the for-each-target loop above 749b5427c27SSatyam Sharma * so that we're able to get as much logging out to 750b5427c27SSatyam Sharma * at least one target if we die inside here, instead 751b5427c27SSatyam Sharma * of unnecessarily keeping all targets in lock-step. 752b5427c27SSatyam Sharma */ 753b5427c27SSatyam Sharma tmp = msg; 7541da177e4SLinus Torvalds for (left = len; left;) { 7551da177e4SLinus Torvalds frag = min(left, MAX_PRINT_CHUNK); 756b5427c27SSatyam Sharma netpoll_send_udp(&nt->np, tmp, frag); 757b5427c27SSatyam Sharma tmp += frag; 7581da177e4SLinus Torvalds left -= frag; 7591da177e4SLinus Torvalds } 7601da177e4SLinus Torvalds } 7610bcc1816SSatyam Sharma netconsole_target_put(nt); 7620cc120beSSatyam Sharma } 763b5427c27SSatyam Sharma spin_unlock_irqrestore(&target_list_lock, flags); 764b5427c27SSatyam Sharma } 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds static struct console netconsole = { 767d938ab44SRandy Dunlap .name = "netcon", 7680517deedSMichael Ellerman .flags = CON_ENABLED, 769d39badf0SSatyam Sharma .write = write_msg, 7701da177e4SLinus Torvalds }; 7711da177e4SLinus Torvalds 772d39badf0SSatyam Sharma static int __init init_netconsole(void) 7731da177e4SLinus Torvalds { 7740bcc1816SSatyam Sharma int err; 775b5427c27SSatyam Sharma struct netconsole_target *nt, *tmp; 776b5427c27SSatyam Sharma unsigned long flags; 777b5427c27SSatyam Sharma char *target_config; 778b5427c27SSatyam Sharma char *input = config; 779b41848b6SStephen Hemminger 7800bcc1816SSatyam Sharma if (strnlen(input, MAX_PARAM_LENGTH)) { 781b5427c27SSatyam Sharma while ((target_config = strsep(&input, ";"))) { 7820bcc1816SSatyam Sharma nt = alloc_param_target(target_config); 783b5427c27SSatyam Sharma if (IS_ERR(nt)) { 784b5427c27SSatyam Sharma err = PTR_ERR(nt); 785b5427c27SSatyam Sharma goto fail; 786b5427c27SSatyam Sharma } 7870517deedSMichael Ellerman /* Dump existing printks when we register */ 7880517deedSMichael Ellerman netconsole.flags |= CON_PRINTBUFFER; 7890517deedSMichael Ellerman 790b5427c27SSatyam Sharma spin_lock_irqsave(&target_list_lock, flags); 791b5427c27SSatyam Sharma list_add(&nt->list, &target_list); 792b5427c27SSatyam Sharma spin_unlock_irqrestore(&target_list_lock, flags); 793b5427c27SSatyam Sharma } 7940bcc1816SSatyam Sharma } 7951da177e4SLinus Torvalds 79617951f34SSatyam Sharma err = register_netdevice_notifier(&netconsole_netdev_notifier); 79717951f34SSatyam Sharma if (err) 798b5427c27SSatyam Sharma goto fail; 79917951f34SSatyam Sharma 8000bcc1816SSatyam Sharma err = dynamic_netconsole_init(); 8010bcc1816SSatyam Sharma if (err) 8020bcc1816SSatyam Sharma goto undonotifier; 8030bcc1816SSatyam Sharma 8041da177e4SLinus Torvalds register_console(&netconsole); 8051da177e4SLinus Torvalds printk(KERN_INFO "netconsole: network logging started\n"); 806d39badf0SSatyam Sharma 807d39badf0SSatyam Sharma return err; 808b5427c27SSatyam Sharma 8090bcc1816SSatyam Sharma undonotifier: 8100bcc1816SSatyam Sharma unregister_netdevice_notifier(&netconsole_netdev_notifier); 8110bcc1816SSatyam Sharma 812b5427c27SSatyam Sharma fail: 813b5427c27SSatyam Sharma printk(KERN_ERR "netconsole: cleaning up\n"); 814b5427c27SSatyam Sharma 815b5427c27SSatyam Sharma /* 8160bcc1816SSatyam Sharma * Remove all targets and destroy them (only targets created 8170bcc1816SSatyam Sharma * from the boot/module option exist here). Skipping the list 818b5427c27SSatyam Sharma * lock is safe here, and netpoll_cleanup() will sleep. 819b5427c27SSatyam Sharma */ 820b5427c27SSatyam Sharma list_for_each_entry_safe(nt, tmp, &target_list, list) { 821b5427c27SSatyam Sharma list_del(&nt->list); 8220bcc1816SSatyam Sharma free_param_target(nt); 823b5427c27SSatyam Sharma } 824b5427c27SSatyam Sharma 825b5427c27SSatyam Sharma return err; 8261da177e4SLinus Torvalds } 8271da177e4SLinus Torvalds 828d39badf0SSatyam Sharma static void __exit cleanup_netconsole(void) 8291da177e4SLinus Torvalds { 830b5427c27SSatyam Sharma struct netconsole_target *nt, *tmp; 831df180e36SSatyam Sharma 8321da177e4SLinus Torvalds unregister_console(&netconsole); 8330bcc1816SSatyam Sharma dynamic_netconsole_exit(); 83417951f34SSatyam Sharma unregister_netdevice_notifier(&netconsole_netdev_notifier); 835b5427c27SSatyam Sharma 836b5427c27SSatyam Sharma /* 8370bcc1816SSatyam Sharma * Targets created via configfs pin references on our module 8380bcc1816SSatyam Sharma * and would first be rmdir(2)'ed from userspace. We reach 8390bcc1816SSatyam Sharma * here only when they are already destroyed, and only those 8400bcc1816SSatyam Sharma * created from the boot/module option are left, so remove and 8410bcc1816SSatyam Sharma * destroy them. Skipping the list lock is safe here, and 8420bcc1816SSatyam Sharma * netpoll_cleanup() will sleep. 843b5427c27SSatyam Sharma */ 844b5427c27SSatyam Sharma list_for_each_entry_safe(nt, tmp, &target_list, list) { 845b5427c27SSatyam Sharma list_del(&nt->list); 8460bcc1816SSatyam Sharma free_param_target(nt); 847b5427c27SSatyam Sharma } 8481da177e4SLinus Torvalds } 8491da177e4SLinus Torvalds 85097c7de05SLin Ming /* 85197c7de05SLin Ming * Use late_initcall to ensure netconsole is 85297c7de05SLin Ming * initialized after network device driver if built-in. 85397c7de05SLin Ming * 85497c7de05SLin Ming * late_initcall() and module_init() are identical if built as module. 85597c7de05SLin Ming */ 85697c7de05SLin Ming late_initcall(init_netconsole); 8571da177e4SLinus Torvalds module_exit(cleanup_netconsole); 858