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