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