1/* 2 * linux/drivers/net/netconsole.c 3 * 4 * Copyright (C) 2001 Ingo Molnar <mingo@redhat.com> 5 * 6 * This file contains the implementation of an IRQ-safe, crash-safe 7 * kernel console implementation that outputs kernel messages to the 8 * network. 9 * 10 * Modification history: 11 * 12 * 2001-09-17 started by Ingo Molnar. 13 * 2003-08-11 2.6 port by Matt Mackall 14 * simplified options 15 * generic card hooks 16 * works non-modular 17 * 2003-09-07 rewritten with netpoll api 18 */ 19 20/**************************************************************** 21 * This program is free software; you can redistribute it and/or modify 22 * it under the terms of the GNU General Public License as published by 23 * the Free Software Foundation; either version 2, or (at your option) 24 * any later version. 25 * 26 * This program is distributed in the hope that it will be useful, 27 * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 * GNU General Public License for more details. 30 * 31 * You should have received a copy of the GNU General Public License 32 * along with this program; if not, write to the Free Software 33 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 34 * 35 ****************************************************************/ 36 37#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 38 39#include <linux/mm.h> 40#include <linux/init.h> 41#include <linux/module.h> 42#include <linux/slab.h> 43#include <linux/console.h> 44#include <linux/moduleparam.h> 45#include <linux/kernel.h> 46#include <linux/string.h> 47#include <linux/netpoll.h> 48#include <linux/inet.h> 49#include <linux/configfs.h> 50#include <linux/etherdevice.h> 51 52MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>"); 53MODULE_DESCRIPTION("Console driver for network interfaces"); 54MODULE_LICENSE("GPL"); 55 56#define MAX_PARAM_LENGTH 256 57#define MAX_PRINT_CHUNK 1000 58 59static char config[MAX_PARAM_LENGTH]; 60module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0); 61MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]"); 62 63static bool oops_only = false; 64module_param(oops_only, bool, 0600); 65MODULE_PARM_DESC(oops_only, "Only log oops messages"); 66 67#ifndef MODULE 68static int __init option_setup(char *opt) 69{ 70 strlcpy(config, opt, MAX_PARAM_LENGTH); 71 return 1; 72} 73__setup("netconsole=", option_setup); 74#endif /* MODULE */ 75 76/* Linked list of all configured targets */ 77static LIST_HEAD(target_list); 78 79/* This needs to be a spinlock because write_msg() cannot sleep */ 80static DEFINE_SPINLOCK(target_list_lock); 81 82/** 83 * struct netconsole_target - Represents a configured netconsole target. 84 * @list: Links this target into the target_list. 85 * @item: Links us into the configfs subsystem hierarchy. 86 * @enabled: On / off knob to enable / disable target. 87 * Visible from userspace (read-write). 88 * We maintain a strict 1:1 correspondence between this and 89 * whether the corresponding netpoll is active or inactive. 90 * Also, other parameters of a target may be modified at 91 * runtime only when it is disabled (enabled == 0). 92 * @np: The netpoll structure for this target. 93 * Contains the other userspace visible parameters: 94 * dev_name (read-write) 95 * local_port (read-write) 96 * remote_port (read-write) 97 * local_ip (read-write) 98 * remote_ip (read-write) 99 * local_mac (read-only) 100 * remote_mac (read-write) 101 */ 102struct netconsole_target { 103 struct list_head list; 104#ifdef CONFIG_NETCONSOLE_DYNAMIC 105 struct config_item item; 106#endif 107 int enabled; 108 struct mutex mutex; 109 struct netpoll np; 110}; 111 112#ifdef CONFIG_NETCONSOLE_DYNAMIC 113 114static struct configfs_subsystem netconsole_subsys; 115 116static int __init dynamic_netconsole_init(void) 117{ 118 config_group_init(&netconsole_subsys.su_group); 119 mutex_init(&netconsole_subsys.su_mutex); 120 return configfs_register_subsystem(&netconsole_subsys); 121} 122 123static void __exit dynamic_netconsole_exit(void) 124{ 125 configfs_unregister_subsystem(&netconsole_subsys); 126} 127 128/* 129 * Targets that were created by parsing the boot/module option string 130 * do not exist in the configfs hierarchy (and have NULL names) and will 131 * never go away, so make these a no-op for them. 132 */ 133static void netconsole_target_get(struct netconsole_target *nt) 134{ 135 if (config_item_name(&nt->item)) 136 config_item_get(&nt->item); 137} 138 139static void netconsole_target_put(struct netconsole_target *nt) 140{ 141 if (config_item_name(&nt->item)) 142 config_item_put(&nt->item); 143} 144 145#else /* !CONFIG_NETCONSOLE_DYNAMIC */ 146 147static int __init dynamic_netconsole_init(void) 148{ 149 return 0; 150} 151 152static void __exit dynamic_netconsole_exit(void) 153{ 154} 155 156/* 157 * No danger of targets going away from under us when dynamic 158 * reconfigurability is off. 159 */ 160static void netconsole_target_get(struct netconsole_target *nt) 161{ 162} 163 164static void netconsole_target_put(struct netconsole_target *nt) 165{ 166} 167 168#endif /* CONFIG_NETCONSOLE_DYNAMIC */ 169 170/* Allocate new target (from boot/module param) and setup netpoll for it */ 171static struct netconsole_target *alloc_param_target(char *target_config) 172{ 173 int err = -ENOMEM; 174 struct netconsole_target *nt; 175 176 /* 177 * Allocate and initialize with defaults. 178 * Note that these targets get their config_item fields zeroed-out. 179 */ 180 nt = kzalloc(sizeof(*nt), GFP_KERNEL); 181 if (!nt) 182 goto fail; 183 184 nt->np.name = "netconsole"; 185 strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); 186 nt->np.local_port = 6665; 187 nt->np.remote_port = 6666; 188 mutex_init(&nt->mutex); 189 eth_broadcast_addr(nt->np.remote_mac); 190 191 /* Parse parameters and setup netpoll */ 192 err = netpoll_parse_options(&nt->np, target_config); 193 if (err) 194 goto fail; 195 196 err = netpoll_setup(&nt->np); 197 if (err) 198 goto fail; 199 200 nt->enabled = 1; 201 202 return nt; 203 204fail: 205 kfree(nt); 206 return ERR_PTR(err); 207} 208 209/* Cleanup netpoll for given target (from boot/module param) and free it */ 210static void free_param_target(struct netconsole_target *nt) 211{ 212 netpoll_cleanup(&nt->np); 213 kfree(nt); 214} 215 216#ifdef CONFIG_NETCONSOLE_DYNAMIC 217 218/* 219 * Our subsystem hierarchy is: 220 * 221 * /sys/kernel/config/netconsole/ 222 * | 223 * <target>/ 224 * | enabled 225 * | dev_name 226 * | local_port 227 * | remote_port 228 * | local_ip 229 * | remote_ip 230 * | local_mac 231 * | remote_mac 232 * | 233 * <target>/... 234 */ 235 236struct netconsole_target_attr { 237 struct configfs_attribute attr; 238 ssize_t (*show)(struct netconsole_target *nt, 239 char *buf); 240 ssize_t (*store)(struct netconsole_target *nt, 241 const char *buf, 242 size_t count); 243}; 244 245static struct netconsole_target *to_target(struct config_item *item) 246{ 247 return item ? 248 container_of(item, struct netconsole_target, item) : 249 NULL; 250} 251 252/* 253 * Attribute operations for netconsole_target. 254 */ 255 256static ssize_t show_enabled(struct netconsole_target *nt, char *buf) 257{ 258 return snprintf(buf, PAGE_SIZE, "%d\n", nt->enabled); 259} 260 261static ssize_t show_dev_name(struct netconsole_target *nt, char *buf) 262{ 263 return snprintf(buf, PAGE_SIZE, "%s\n", nt->np.dev_name); 264} 265 266static ssize_t show_local_port(struct netconsole_target *nt, char *buf) 267{ 268 return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.local_port); 269} 270 271static ssize_t show_remote_port(struct netconsole_target *nt, char *buf) 272{ 273 return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.remote_port); 274} 275 276static ssize_t show_local_ip(struct netconsole_target *nt, char *buf) 277{ 278 if (nt->np.ipv6) 279 return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6); 280 else 281 return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip); 282} 283 284static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf) 285{ 286 if (nt->np.ipv6) 287 return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6); 288 else 289 return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip); 290} 291 292static ssize_t show_local_mac(struct netconsole_target *nt, char *buf) 293{ 294 struct net_device *dev = nt->np.dev; 295 static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 296 297 return snprintf(buf, PAGE_SIZE, "%pM\n", dev ? dev->dev_addr : bcast); 298} 299 300static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf) 301{ 302 return snprintf(buf, PAGE_SIZE, "%pM\n", nt->np.remote_mac); 303} 304 305/* 306 * This one is special -- targets created through the configfs interface 307 * are not enabled (and the corresponding netpoll activated) by default. 308 * The user is expected to set the desired parameters first (which 309 * would enable him to dynamically add new netpoll targets for new 310 * network interfaces as and when they come up). 311 */ 312static ssize_t store_enabled(struct netconsole_target *nt, 313 const char *buf, 314 size_t count) 315{ 316 unsigned long flags; 317 int enabled; 318 int err; 319 320 err = kstrtoint(buf, 10, &enabled); 321 if (err < 0) 322 return err; 323 if (enabled < 0 || enabled > 1) 324 return -EINVAL; 325 if (enabled == nt->enabled) { 326 pr_info("network logging has already %s\n", 327 nt->enabled ? "started" : "stopped"); 328 return -EINVAL; 329 } 330 331 if (enabled) { /* 1 */ 332 /* 333 * Skip netpoll_parse_options() -- all the attributes are 334 * already configured via configfs. Just print them out. 335 */ 336 netpoll_print_options(&nt->np); 337 338 err = netpoll_setup(&nt->np); 339 if (err) 340 return err; 341 342 pr_info("netconsole: network logging started\n"); 343 } else { /* 0 */ 344 /* We need to disable the netconsole before cleaning it up 345 * otherwise we might end up in write_msg() with 346 * nt->np.dev == NULL and nt->enabled == 1 347 */ 348 spin_lock_irqsave(&target_list_lock, flags); 349 nt->enabled = 0; 350 spin_unlock_irqrestore(&target_list_lock, flags); 351 netpoll_cleanup(&nt->np); 352 } 353 354 nt->enabled = enabled; 355 356 return strnlen(buf, count); 357} 358 359static ssize_t store_dev_name(struct netconsole_target *nt, 360 const char *buf, 361 size_t count) 362{ 363 size_t len; 364 365 if (nt->enabled) { 366 pr_err("target (%s) is enabled, disable to update parameters\n", 367 config_item_name(&nt->item)); 368 return -EINVAL; 369 } 370 371 strlcpy(nt->np.dev_name, buf, IFNAMSIZ); 372 373 /* Get rid of possible trailing newline from echo(1) */ 374 len = strnlen(nt->np.dev_name, IFNAMSIZ); 375 if (nt->np.dev_name[len - 1] == '\n') 376 nt->np.dev_name[len - 1] = '\0'; 377 378 return strnlen(buf, count); 379} 380 381static ssize_t store_local_port(struct netconsole_target *nt, 382 const char *buf, 383 size_t count) 384{ 385 int rv; 386 387 if (nt->enabled) { 388 pr_err("target (%s) is enabled, disable to update parameters\n", 389 config_item_name(&nt->item)); 390 return -EINVAL; 391 } 392 393 rv = kstrtou16(buf, 10, &nt->np.local_port); 394 if (rv < 0) 395 return rv; 396 return strnlen(buf, count); 397} 398 399static ssize_t store_remote_port(struct netconsole_target *nt, 400 const char *buf, 401 size_t count) 402{ 403 int rv; 404 405 if (nt->enabled) { 406 pr_err("target (%s) is enabled, disable to update parameters\n", 407 config_item_name(&nt->item)); 408 return -EINVAL; 409 } 410 411 rv = kstrtou16(buf, 10, &nt->np.remote_port); 412 if (rv < 0) 413 return rv; 414 return strnlen(buf, count); 415} 416 417static ssize_t store_local_ip(struct netconsole_target *nt, 418 const char *buf, 419 size_t count) 420{ 421 if (nt->enabled) { 422 pr_err("target (%s) is enabled, disable to update parameters\n", 423 config_item_name(&nt->item)); 424 return -EINVAL; 425 } 426 427 if (strnchr(buf, count, ':')) { 428 const char *end; 429 if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) { 430 if (*end && *end != '\n') { 431 pr_err("invalid IPv6 address at: <%c>\n", *end); 432 return -EINVAL; 433 } 434 nt->np.ipv6 = true; 435 } else 436 return -EINVAL; 437 } else { 438 if (!nt->np.ipv6) { 439 nt->np.local_ip.ip = in_aton(buf); 440 } else 441 return -EINVAL; 442 } 443 444 return strnlen(buf, count); 445} 446 447static ssize_t store_remote_ip(struct netconsole_target *nt, 448 const char *buf, 449 size_t count) 450{ 451 if (nt->enabled) { 452 pr_err("target (%s) is enabled, disable to update parameters\n", 453 config_item_name(&nt->item)); 454 return -EINVAL; 455 } 456 457 if (strnchr(buf, count, ':')) { 458 const char *end; 459 if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) { 460 if (*end && *end != '\n') { 461 pr_err("invalid IPv6 address at: <%c>\n", *end); 462 return -EINVAL; 463 } 464 nt->np.ipv6 = true; 465 } else 466 return -EINVAL; 467 } else { 468 if (!nt->np.ipv6) { 469 nt->np.remote_ip.ip = in_aton(buf); 470 } else 471 return -EINVAL; 472 } 473 474 return strnlen(buf, count); 475} 476 477static ssize_t store_remote_mac(struct netconsole_target *nt, 478 const char *buf, 479 size_t count) 480{ 481 u8 remote_mac[ETH_ALEN]; 482 483 if (nt->enabled) { 484 pr_err("target (%s) is enabled, disable to update parameters\n", 485 config_item_name(&nt->item)); 486 return -EINVAL; 487 } 488 489 if (!mac_pton(buf, remote_mac)) 490 return -EINVAL; 491 if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n') 492 return -EINVAL; 493 memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); 494 495 return strnlen(buf, count); 496} 497 498/* 499 * Attribute definitions for netconsole_target. 500 */ 501 502#define NETCONSOLE_TARGET_ATTR_RO(_name) \ 503static struct netconsole_target_attr netconsole_target_##_name = \ 504 __CONFIGFS_ATTR(_name, S_IRUGO, show_##_name, NULL) 505 506#define NETCONSOLE_TARGET_ATTR_RW(_name) \ 507static struct netconsole_target_attr netconsole_target_##_name = \ 508 __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name) 509 510NETCONSOLE_TARGET_ATTR_RW(enabled); 511NETCONSOLE_TARGET_ATTR_RW(dev_name); 512NETCONSOLE_TARGET_ATTR_RW(local_port); 513NETCONSOLE_TARGET_ATTR_RW(remote_port); 514NETCONSOLE_TARGET_ATTR_RW(local_ip); 515NETCONSOLE_TARGET_ATTR_RW(remote_ip); 516NETCONSOLE_TARGET_ATTR_RO(local_mac); 517NETCONSOLE_TARGET_ATTR_RW(remote_mac); 518 519static struct configfs_attribute *netconsole_target_attrs[] = { 520 &netconsole_target_enabled.attr, 521 &netconsole_target_dev_name.attr, 522 &netconsole_target_local_port.attr, 523 &netconsole_target_remote_port.attr, 524 &netconsole_target_local_ip.attr, 525 &netconsole_target_remote_ip.attr, 526 &netconsole_target_local_mac.attr, 527 &netconsole_target_remote_mac.attr, 528 NULL, 529}; 530 531/* 532 * Item operations and type for netconsole_target. 533 */ 534 535static void netconsole_target_release(struct config_item *item) 536{ 537 kfree(to_target(item)); 538} 539 540static ssize_t netconsole_target_attr_show(struct config_item *item, 541 struct configfs_attribute *attr, 542 char *buf) 543{ 544 ssize_t ret = -EINVAL; 545 struct netconsole_target *nt = to_target(item); 546 struct netconsole_target_attr *na = 547 container_of(attr, struct netconsole_target_attr, attr); 548 549 if (na->show) 550 ret = na->show(nt, buf); 551 552 return ret; 553} 554 555static ssize_t netconsole_target_attr_store(struct config_item *item, 556 struct configfs_attribute *attr, 557 const char *buf, 558 size_t count) 559{ 560 ssize_t ret = -EINVAL; 561 struct netconsole_target *nt = to_target(item); 562 struct netconsole_target_attr *na = 563 container_of(attr, struct netconsole_target_attr, attr); 564 565 mutex_lock(&nt->mutex); 566 if (na->store) 567 ret = na->store(nt, buf, count); 568 mutex_unlock(&nt->mutex); 569 570 return ret; 571} 572 573static struct configfs_item_operations netconsole_target_item_ops = { 574 .release = netconsole_target_release, 575 .show_attribute = netconsole_target_attr_show, 576 .store_attribute = netconsole_target_attr_store, 577}; 578 579static struct config_item_type netconsole_target_type = { 580 .ct_attrs = netconsole_target_attrs, 581 .ct_item_ops = &netconsole_target_item_ops, 582 .ct_owner = THIS_MODULE, 583}; 584 585/* 586 * Group operations and type for netconsole_subsys. 587 */ 588 589static struct config_item *make_netconsole_target(struct config_group *group, 590 const char *name) 591{ 592 unsigned long flags; 593 struct netconsole_target *nt; 594 595 /* 596 * Allocate and initialize with defaults. 597 * Target is disabled at creation (enabled == 0). 598 */ 599 nt = kzalloc(sizeof(*nt), GFP_KERNEL); 600 if (!nt) 601 return ERR_PTR(-ENOMEM); 602 603 nt->np.name = "netconsole"; 604 strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); 605 nt->np.local_port = 6665; 606 nt->np.remote_port = 6666; 607 mutex_init(&nt->mutex); 608 eth_broadcast_addr(nt->np.remote_mac); 609 610 /* Initialize the config_item member */ 611 config_item_init_type_name(&nt->item, name, &netconsole_target_type); 612 613 /* Adding, but it is disabled */ 614 spin_lock_irqsave(&target_list_lock, flags); 615 list_add(&nt->list, &target_list); 616 spin_unlock_irqrestore(&target_list_lock, flags); 617 618 return &nt->item; 619} 620 621static void drop_netconsole_target(struct config_group *group, 622 struct config_item *item) 623{ 624 unsigned long flags; 625 struct netconsole_target *nt = to_target(item); 626 627 spin_lock_irqsave(&target_list_lock, flags); 628 list_del(&nt->list); 629 spin_unlock_irqrestore(&target_list_lock, flags); 630 631 /* 632 * The target may have never been enabled, or was manually disabled 633 * before being removed so netpoll may have already been cleaned up. 634 */ 635 if (nt->enabled) 636 netpoll_cleanup(&nt->np); 637 638 config_item_put(&nt->item); 639} 640 641static struct configfs_group_operations netconsole_subsys_group_ops = { 642 .make_item = make_netconsole_target, 643 .drop_item = drop_netconsole_target, 644}; 645 646static struct config_item_type netconsole_subsys_type = { 647 .ct_group_ops = &netconsole_subsys_group_ops, 648 .ct_owner = THIS_MODULE, 649}; 650 651/* The netconsole configfs subsystem */ 652static struct configfs_subsystem netconsole_subsys = { 653 .su_group = { 654 .cg_item = { 655 .ci_namebuf = "netconsole", 656 .ci_type = &netconsole_subsys_type, 657 }, 658 }, 659}; 660 661#endif /* CONFIG_NETCONSOLE_DYNAMIC */ 662 663/* Handle network interface device notifications */ 664static int netconsole_netdev_event(struct notifier_block *this, 665 unsigned long event, void *ptr) 666{ 667 unsigned long flags; 668 struct netconsole_target *nt; 669 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 670 bool stopped = false; 671 672 if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER || 673 event == NETDEV_RELEASE || event == NETDEV_JOIN)) 674 goto done; 675 676 spin_lock_irqsave(&target_list_lock, flags); 677restart: 678 list_for_each_entry(nt, &target_list, list) { 679 netconsole_target_get(nt); 680 if (nt->np.dev == dev) { 681 switch (event) { 682 case NETDEV_CHANGENAME: 683 strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ); 684 break; 685 case NETDEV_RELEASE: 686 case NETDEV_JOIN: 687 case NETDEV_UNREGISTER: 688 /* rtnl_lock already held 689 * we might sleep in __netpoll_cleanup() 690 */ 691 spin_unlock_irqrestore(&target_list_lock, flags); 692 693 __netpoll_cleanup(&nt->np); 694 695 spin_lock_irqsave(&target_list_lock, flags); 696 dev_put(nt->np.dev); 697 nt->np.dev = NULL; 698 nt->enabled = 0; 699 stopped = true; 700 netconsole_target_put(nt); 701 goto restart; 702 } 703 } 704 netconsole_target_put(nt); 705 } 706 spin_unlock_irqrestore(&target_list_lock, flags); 707 if (stopped) { 708 const char *msg = "had an event"; 709 switch (event) { 710 case NETDEV_UNREGISTER: 711 msg = "unregistered"; 712 break; 713 case NETDEV_RELEASE: 714 msg = "released slaves"; 715 break; 716 case NETDEV_JOIN: 717 msg = "is joining a master device"; 718 break; 719 } 720 pr_info("network logging stopped on interface %s as it %s\n", 721 dev->name, msg); 722 } 723 724done: 725 return NOTIFY_DONE; 726} 727 728static struct notifier_block netconsole_netdev_notifier = { 729 .notifier_call = netconsole_netdev_event, 730}; 731 732static void write_msg(struct console *con, const char *msg, unsigned int len) 733{ 734 int frag, left; 735 unsigned long flags; 736 struct netconsole_target *nt; 737 const char *tmp; 738 739 if (oops_only && !oops_in_progress) 740 return; 741 /* Avoid taking lock and disabling interrupts unnecessarily */ 742 if (list_empty(&target_list)) 743 return; 744 745 spin_lock_irqsave(&target_list_lock, flags); 746 list_for_each_entry(nt, &target_list, list) { 747 netconsole_target_get(nt); 748 if (nt->enabled && netif_running(nt->np.dev)) { 749 /* 750 * We nest this inside the for-each-target loop above 751 * so that we're able to get as much logging out to 752 * at least one target if we die inside here, instead 753 * of unnecessarily keeping all targets in lock-step. 754 */ 755 tmp = msg; 756 for (left = len; left;) { 757 frag = min(left, MAX_PRINT_CHUNK); 758 netpoll_send_udp(&nt->np, tmp, frag); 759 tmp += frag; 760 left -= frag; 761 } 762 } 763 netconsole_target_put(nt); 764 } 765 spin_unlock_irqrestore(&target_list_lock, flags); 766} 767 768static struct console netconsole = { 769 .name = "netcon", 770 .flags = CON_ENABLED, 771 .write = write_msg, 772}; 773 774static int __init init_netconsole(void) 775{ 776 int err; 777 struct netconsole_target *nt, *tmp; 778 unsigned long flags; 779 char *target_config; 780 char *input = config; 781 782 if (strnlen(input, MAX_PARAM_LENGTH)) { 783 while ((target_config = strsep(&input, ";"))) { 784 nt = alloc_param_target(target_config); 785 if (IS_ERR(nt)) { 786 err = PTR_ERR(nt); 787 goto fail; 788 } 789 /* Dump existing printks when we register */ 790 netconsole.flags |= CON_PRINTBUFFER; 791 792 spin_lock_irqsave(&target_list_lock, flags); 793 list_add(&nt->list, &target_list); 794 spin_unlock_irqrestore(&target_list_lock, flags); 795 } 796 } 797 798 err = register_netdevice_notifier(&netconsole_netdev_notifier); 799 if (err) 800 goto fail; 801 802 err = dynamic_netconsole_init(); 803 if (err) 804 goto undonotifier; 805 806 register_console(&netconsole); 807 pr_info("network logging started\n"); 808 809 return err; 810 811undonotifier: 812 unregister_netdevice_notifier(&netconsole_netdev_notifier); 813 814fail: 815 pr_err("cleaning up\n"); 816 817 /* 818 * Remove all targets and destroy them (only targets created 819 * from the boot/module option exist here). Skipping the list 820 * lock is safe here, and netpoll_cleanup() will sleep. 821 */ 822 list_for_each_entry_safe(nt, tmp, &target_list, list) { 823 list_del(&nt->list); 824 free_param_target(nt); 825 } 826 827 return err; 828} 829 830static void __exit cleanup_netconsole(void) 831{ 832 struct netconsole_target *nt, *tmp; 833 834 unregister_console(&netconsole); 835 dynamic_netconsole_exit(); 836 unregister_netdevice_notifier(&netconsole_netdev_notifier); 837 838 /* 839 * Targets created via configfs pin references on our module 840 * and would first be rmdir(2)'ed from userspace. We reach 841 * here only when they are already destroyed, and only those 842 * created from the boot/module option are left, so remove and 843 * destroy them. Skipping the list lock is safe here, and 844 * netpoll_cleanup() will sleep. 845 */ 846 list_for_each_entry_safe(nt, tmp, &target_list, list) { 847 list_del(&nt->list); 848 free_param_target(nt); 849 } 850} 851 852/* 853 * Use late_initcall to ensure netconsole is 854 * initialized after network device driver if built-in. 855 * 856 * late_initcall() and module_init() are identical if built as module. 857 */ 858late_initcall(init_netconsole); 859module_exit(cleanup_netconsole); 860