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