diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-26 12:52:05 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-26 12:52:05 -0400 |
| commit | 47a469421d792dcb91a1e73319d26134241953d2 (patch) | |
| tree | 6a388381a434ebe87fed2fbb10a53ced7a7ce8b5 /drivers/net | |
| parent | c13c81006314ad76c2b31824960a900385601b8b (diff) | |
| parent | 51229b495340bd7a02ce3622d1966829b67054ea (diff) | |
Merge branch 'akpm' (patches from Andrew)
Merge second patchbomb from Andrew Morton:
- most of the rest of MM
- lots of misc things
- procfs updates
- printk feature work
- updates to get_maintainer, MAINTAINERS, checkpatch
- lib/ updates
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (96 commits)
exit,stats: /* obey this comment */
coredump: add __printf attribute to cn_*printf functions
coredump: use from_kuid/kgid when formatting corename
fs/reiserfs: remove unneeded cast
NILFS2: support NFSv2 export
fs/befs/btree.c: remove unneeded initializations
fs/minix: remove unneeded cast
init/do_mounts.c: add create_dev() failure log
kasan: remove duplicate definition of the macro KASAN_FREE_PAGE
fs/efs: femove unneeded cast
checkpatch: emit "NOTE: <types>" message only once after multiple files
checkpatch: emit an error when there's a diff in a changelog
checkpatch: validate MODULE_LICENSE content
checkpatch: add multi-line handling for PREFER_ETHER_ADDR_COPY
checkpatch: suggest using eth_zero_addr() and eth_broadcast_addr()
checkpatch: fix processing of MEMSET issues
checkpatch: suggest using ether_addr_equal*()
checkpatch: avoid NOT_UNIFIED_DIFF errors on cover-letter.patch files
checkpatch: remove local from codespell path
checkpatch: add --showfile to allow input via pipe to show filenames
...
Diffstat (limited to 'drivers/net')
| -rw-r--r-- | drivers/net/netconsole.c | 169 |
1 files changed, 151 insertions, 18 deletions
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 15731d1db918..97f3acd44798 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c | |||
| @@ -79,6 +79,12 @@ static LIST_HEAD(target_list); | |||
| 79 | /* This needs to be a spinlock because write_msg() cannot sleep */ | 79 | /* This needs to be a spinlock because write_msg() cannot sleep */ |
| 80 | static DEFINE_SPINLOCK(target_list_lock); | 80 | static DEFINE_SPINLOCK(target_list_lock); |
| 81 | 81 | ||
| 82 | /* | ||
| 83 | * Console driver for extended netconsoles. Registered on the first use to | ||
| 84 | * avoid unnecessarily enabling ext message formatting. | ||
| 85 | */ | ||
| 86 | static struct console netconsole_ext; | ||
| 87 | |||
| 82 | /** | 88 | /** |
| 83 | * struct netconsole_target - Represents a configured netconsole target. | 89 | * struct netconsole_target - Represents a configured netconsole target. |
| 84 | * @list: Links this target into the target_list. | 90 | * @list: Links this target into the target_list. |
| @@ -104,14 +110,15 @@ struct netconsole_target { | |||
| 104 | #ifdef CONFIG_NETCONSOLE_DYNAMIC | 110 | #ifdef CONFIG_NETCONSOLE_DYNAMIC |
| 105 | struct config_item item; | 111 | struct config_item item; |
| 106 | #endif | 112 | #endif |
| 107 | int enabled; | 113 | bool enabled; |
| 108 | struct mutex mutex; | 114 | bool extended; |
| 109 | struct netpoll np; | 115 | struct netpoll np; |
| 110 | }; | 116 | }; |
| 111 | 117 | ||
| 112 | #ifdef CONFIG_NETCONSOLE_DYNAMIC | 118 | #ifdef CONFIG_NETCONSOLE_DYNAMIC |
| 113 | 119 | ||
| 114 | static struct configfs_subsystem netconsole_subsys; | 120 | static struct configfs_subsystem netconsole_subsys; |
| 121 | static DEFINE_MUTEX(dynamic_netconsole_mutex); | ||
| 115 | 122 | ||
| 116 | static int __init dynamic_netconsole_init(void) | 123 | static int __init dynamic_netconsole_init(void) |
| 117 | { | 124 | { |
| @@ -185,9 +192,13 @@ static struct netconsole_target *alloc_param_target(char *target_config) | |||
| 185 | strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); | 192 | strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); |
| 186 | nt->np.local_port = 6665; | 193 | nt->np.local_port = 6665; |
| 187 | nt->np.remote_port = 6666; | 194 | nt->np.remote_port = 6666; |
| 188 | mutex_init(&nt->mutex); | ||
| 189 | eth_broadcast_addr(nt->np.remote_mac); | 195 | eth_broadcast_addr(nt->np.remote_mac); |
| 190 | 196 | ||
| 197 | if (*target_config == '+') { | ||
| 198 | nt->extended = true; | ||
| 199 | target_config++; | ||
| 200 | } | ||
| 201 | |||
| 191 | /* Parse parameters and setup netpoll */ | 202 | /* Parse parameters and setup netpoll */ |
| 192 | err = netpoll_parse_options(&nt->np, target_config); | 203 | err = netpoll_parse_options(&nt->np, target_config); |
| 193 | if (err) | 204 | if (err) |
| @@ -197,7 +208,7 @@ static struct netconsole_target *alloc_param_target(char *target_config) | |||
| 197 | if (err) | 208 | if (err) |
| 198 | goto fail; | 209 | goto fail; |
| 199 | 210 | ||
| 200 | nt->enabled = 1; | 211 | nt->enabled = true; |
| 201 | 212 | ||
| 202 | return nt; | 213 | return nt; |
| 203 | 214 | ||
| @@ -258,6 +269,11 @@ static ssize_t show_enabled(struct netconsole_target *nt, char *buf) | |||
| 258 | return snprintf(buf, PAGE_SIZE, "%d\n", nt->enabled); | 269 | return snprintf(buf, PAGE_SIZE, "%d\n", nt->enabled); |
| 259 | } | 270 | } |
| 260 | 271 | ||
| 272 | static ssize_t show_extended(struct netconsole_target *nt, char *buf) | ||
| 273 | { | ||
| 274 | return snprintf(buf, PAGE_SIZE, "%d\n", nt->extended); | ||
| 275 | } | ||
| 276 | |||
| 261 | static ssize_t show_dev_name(struct netconsole_target *nt, char *buf) | 277 | static ssize_t show_dev_name(struct netconsole_target *nt, char *buf) |
| 262 | { | 278 | { |
| 263 | return snprintf(buf, PAGE_SIZE, "%s\n", nt->np.dev_name); | 279 | return snprintf(buf, PAGE_SIZE, "%s\n", nt->np.dev_name); |
| @@ -322,13 +338,18 @@ static ssize_t store_enabled(struct netconsole_target *nt, | |||
| 322 | return err; | 338 | return err; |
| 323 | if (enabled < 0 || enabled > 1) | 339 | if (enabled < 0 || enabled > 1) |
| 324 | return -EINVAL; | 340 | return -EINVAL; |
| 325 | if (enabled == nt->enabled) { | 341 | if ((bool)enabled == nt->enabled) { |
| 326 | pr_info("network logging has already %s\n", | 342 | pr_info("network logging has already %s\n", |
| 327 | nt->enabled ? "started" : "stopped"); | 343 | nt->enabled ? "started" : "stopped"); |
| 328 | return -EINVAL; | 344 | return -EINVAL; |
| 329 | } | 345 | } |
| 330 | 346 | ||
| 331 | if (enabled) { /* 1 */ | 347 | if (enabled) { /* true */ |
| 348 | if (nt->extended && !(netconsole_ext.flags & CON_ENABLED)) { | ||
| 349 | netconsole_ext.flags |= CON_ENABLED; | ||
| 350 | register_console(&netconsole_ext); | ||
| 351 | } | ||
| 352 | |||
| 332 | /* | 353 | /* |
| 333 | * Skip netpoll_parse_options() -- all the attributes are | 354 | * Skip netpoll_parse_options() -- all the attributes are |
| 334 | * already configured via configfs. Just print them out. | 355 | * already configured via configfs. Just print them out. |
| @@ -340,13 +361,13 @@ static ssize_t store_enabled(struct netconsole_target *nt, | |||
| 340 | return err; | 361 | return err; |
| 341 | 362 | ||
| 342 | pr_info("netconsole: network logging started\n"); | 363 | pr_info("netconsole: network logging started\n"); |
| 343 | } else { /* 0 */ | 364 | } else { /* false */ |
| 344 | /* We need to disable the netconsole before cleaning it up | 365 | /* We need to disable the netconsole before cleaning it up |
| 345 | * otherwise we might end up in write_msg() with | 366 | * otherwise we might end up in write_msg() with |
| 346 | * nt->np.dev == NULL and nt->enabled == 1 | 367 | * nt->np.dev == NULL and nt->enabled == true |
| 347 | */ | 368 | */ |
| 348 | spin_lock_irqsave(&target_list_lock, flags); | 369 | spin_lock_irqsave(&target_list_lock, flags); |
| 349 | nt->enabled = 0; | 370 | nt->enabled = false; |
| 350 | spin_unlock_irqrestore(&target_list_lock, flags); | 371 | spin_unlock_irqrestore(&target_list_lock, flags); |
| 351 | netpoll_cleanup(&nt->np); | 372 | netpoll_cleanup(&nt->np); |
| 352 | } | 373 | } |
| @@ -356,6 +377,30 @@ static ssize_t store_enabled(struct netconsole_target *nt, | |||
| 356 | return strnlen(buf, count); | 377 | return strnlen(buf, count); |
| 357 | } | 378 | } |
| 358 | 379 | ||
| 380 | static ssize_t store_extended(struct netconsole_target *nt, | ||
| 381 | const char *buf, | ||
| 382 | size_t count) | ||
| 383 | { | ||
| 384 | int extended; | ||
| 385 | int err; | ||
| 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 | err = kstrtoint(buf, 10, &extended); | ||
| 394 | if (err < 0) | ||
| 395 | return err; | ||
| 396 | if (extended < 0 || extended > 1) | ||
| 397 | return -EINVAL; | ||
| 398 | |||
| 399 | nt->extended = extended; | ||
| 400 | |||
| 401 | return strnlen(buf, count); | ||
| 402 | } | ||
| 403 | |||
| 359 | static ssize_t store_dev_name(struct netconsole_target *nt, | 404 | static ssize_t store_dev_name(struct netconsole_target *nt, |
| 360 | const char *buf, | 405 | const char *buf, |
| 361 | size_t count) | 406 | size_t count) |
| @@ -508,6 +553,7 @@ static struct netconsole_target_attr netconsole_target_##_name = \ | |||
| 508 | __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name) | 553 | __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name) |
| 509 | 554 | ||
| 510 | NETCONSOLE_TARGET_ATTR_RW(enabled); | 555 | NETCONSOLE_TARGET_ATTR_RW(enabled); |
| 556 | NETCONSOLE_TARGET_ATTR_RW(extended); | ||
| 511 | NETCONSOLE_TARGET_ATTR_RW(dev_name); | 557 | NETCONSOLE_TARGET_ATTR_RW(dev_name); |
| 512 | NETCONSOLE_TARGET_ATTR_RW(local_port); | 558 | NETCONSOLE_TARGET_ATTR_RW(local_port); |
| 513 | NETCONSOLE_TARGET_ATTR_RW(remote_port); | 559 | NETCONSOLE_TARGET_ATTR_RW(remote_port); |
| @@ -518,6 +564,7 @@ NETCONSOLE_TARGET_ATTR_RW(remote_mac); | |||
| 518 | 564 | ||
| 519 | static struct configfs_attribute *netconsole_target_attrs[] = { | 565 | static struct configfs_attribute *netconsole_target_attrs[] = { |
| 520 | &netconsole_target_enabled.attr, | 566 | &netconsole_target_enabled.attr, |
| 567 | &netconsole_target_extended.attr, | ||
| 521 | &netconsole_target_dev_name.attr, | 568 | &netconsole_target_dev_name.attr, |
| 522 | &netconsole_target_local_port.attr, | 569 | &netconsole_target_local_port.attr, |
| 523 | &netconsole_target_remote_port.attr, | 570 | &netconsole_target_remote_port.attr, |
| @@ -562,10 +609,10 @@ static ssize_t netconsole_target_attr_store(struct config_item *item, | |||
| 562 | struct netconsole_target_attr *na = | 609 | struct netconsole_target_attr *na = |
| 563 | container_of(attr, struct netconsole_target_attr, attr); | 610 | container_of(attr, struct netconsole_target_attr, attr); |
| 564 | 611 | ||
| 565 | mutex_lock(&nt->mutex); | 612 | mutex_lock(&dynamic_netconsole_mutex); |
| 566 | if (na->store) | 613 | if (na->store) |
| 567 | ret = na->store(nt, buf, count); | 614 | ret = na->store(nt, buf, count); |
| 568 | mutex_unlock(&nt->mutex); | 615 | mutex_unlock(&dynamic_netconsole_mutex); |
| 569 | 616 | ||
| 570 | return ret; | 617 | return ret; |
| 571 | } | 618 | } |
| @@ -594,7 +641,7 @@ static struct config_item *make_netconsole_target(struct config_group *group, | |||
| 594 | 641 | ||
| 595 | /* | 642 | /* |
| 596 | * Allocate and initialize with defaults. | 643 | * Allocate and initialize with defaults. |
| 597 | * Target is disabled at creation (enabled == 0). | 644 | * Target is disabled at creation (!enabled). |
| 598 | */ | 645 | */ |
| 599 | nt = kzalloc(sizeof(*nt), GFP_KERNEL); | 646 | nt = kzalloc(sizeof(*nt), GFP_KERNEL); |
| 600 | if (!nt) | 647 | if (!nt) |
| @@ -604,7 +651,6 @@ static struct config_item *make_netconsole_target(struct config_group *group, | |||
| 604 | strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); | 651 | strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); |
| 605 | nt->np.local_port = 6665; | 652 | nt->np.local_port = 6665; |
| 606 | nt->np.remote_port = 6666; | 653 | nt->np.remote_port = 6666; |
| 607 | mutex_init(&nt->mutex); | ||
| 608 | eth_broadcast_addr(nt->np.remote_mac); | 654 | eth_broadcast_addr(nt->np.remote_mac); |
| 609 | 655 | ||
| 610 | /* Initialize the config_item member */ | 656 | /* Initialize the config_item member */ |
| @@ -695,7 +741,7 @@ restart: | |||
| 695 | spin_lock_irqsave(&target_list_lock, flags); | 741 | spin_lock_irqsave(&target_list_lock, flags); |
| 696 | dev_put(nt->np.dev); | 742 | dev_put(nt->np.dev); |
| 697 | nt->np.dev = NULL; | 743 | nt->np.dev = NULL; |
| 698 | nt->enabled = 0; | 744 | nt->enabled = false; |
| 699 | stopped = true; | 745 | stopped = true; |
| 700 | netconsole_target_put(nt); | 746 | netconsole_target_put(nt); |
| 701 | goto restart; | 747 | goto restart; |
| @@ -729,6 +775,82 @@ static struct notifier_block netconsole_netdev_notifier = { | |||
| 729 | .notifier_call = netconsole_netdev_event, | 775 | .notifier_call = netconsole_netdev_event, |
| 730 | }; | 776 | }; |
| 731 | 777 | ||
| 778 | /** | ||
| 779 | * send_ext_msg_udp - send extended log message to target | ||
| 780 | * @nt: target to send message to | ||
| 781 | * @msg: extended log message to send | ||
| 782 | * @msg_len: length of message | ||
| 783 | * | ||
| 784 | * Transfer extended log @msg to @nt. If @msg is longer than | ||
| 785 | * MAX_PRINT_CHUNK, it'll be split and transmitted in multiple chunks with | ||
| 786 | * ncfrag header field added to identify them. | ||
| 787 | */ | ||
| 788 | static void send_ext_msg_udp(struct netconsole_target *nt, const char *msg, | ||
| 789 | int msg_len) | ||
| 790 | { | ||
| 791 | static char buf[MAX_PRINT_CHUNK]; /* protected by target_list_lock */ | ||
| 792 | const char *header, *body; | ||
| 793 | int offset = 0; | ||
| 794 | int header_len, body_len; | ||
| 795 | |||
| 796 | if (msg_len <= MAX_PRINT_CHUNK) { | ||
| 797 | netpoll_send_udp(&nt->np, msg, msg_len); | ||
| 798 | return; | ||
| 799 | } | ||
| 800 | |||
| 801 | /* need to insert extra header fields, detect header and body */ | ||
| 802 | header = msg; | ||
| 803 | body = memchr(msg, ';', msg_len); | ||
| 804 | if (WARN_ON_ONCE(!body)) | ||
| 805 | return; | ||
| 806 | |||
| 807 | header_len = body - header; | ||
| 808 | body_len = msg_len - header_len - 1; | ||
| 809 | body++; | ||
| 810 | |||
| 811 | /* | ||
| 812 | * Transfer multiple chunks with the following extra header. | ||
| 813 | * "ncfrag=<byte-offset>/<total-bytes>" | ||
| 814 | */ | ||
| 815 | memcpy(buf, header, header_len); | ||
| 816 | |||
| 817 | while (offset < body_len) { | ||
| 818 | int this_header = header_len; | ||
| 819 | int this_chunk; | ||
| 820 | |||
| 821 | this_header += scnprintf(buf + this_header, | ||
| 822 | sizeof(buf) - this_header, | ||
| 823 | ",ncfrag=%d/%d;", offset, body_len); | ||
| 824 | |||
| 825 | this_chunk = min(body_len - offset, | ||
| 826 | MAX_PRINT_CHUNK - this_header); | ||
| 827 | if (WARN_ON_ONCE(this_chunk <= 0)) | ||
| 828 | return; | ||
| 829 | |||
| 830 | memcpy(buf + this_header, body + offset, this_chunk); | ||
| 831 | |||
| 832 | netpoll_send_udp(&nt->np, buf, this_header + this_chunk); | ||
| 833 | |||
| 834 | offset += this_chunk; | ||
| 835 | } | ||
| 836 | } | ||
| 837 | |||
| 838 | static void write_ext_msg(struct console *con, const char *msg, | ||
| 839 | unsigned int len) | ||
| 840 | { | ||
| 841 | struct netconsole_target *nt; | ||
| 842 | unsigned long flags; | ||
| 843 | |||
| 844 | if ((oops_only && !oops_in_progress) || list_empty(&target_list)) | ||
| 845 | return; | ||
| 846 | |||
| 847 | spin_lock_irqsave(&target_list_lock, flags); | ||
| 848 | list_for_each_entry(nt, &target_list, list) | ||
| 849 | if (nt->extended && nt->enabled && netif_running(nt->np.dev)) | ||
| 850 | send_ext_msg_udp(nt, msg, len); | ||
| 851 | spin_unlock_irqrestore(&target_list_lock, flags); | ||
| 852 | } | ||
| 853 | |||
| 732 | static void write_msg(struct console *con, const char *msg, unsigned int len) | 854 | static void write_msg(struct console *con, const char *msg, unsigned int len) |
| 733 | { | 855 | { |
| 734 | int frag, left; | 856 | int frag, left; |
| @@ -744,8 +866,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) | |||
| 744 | 866 | ||
| 745 | spin_lock_irqsave(&target_list_lock, flags); | 867 | spin_lock_irqsave(&target_list_lock, flags); |
| 746 | list_for_each_entry(nt, &target_list, list) { | 868 | list_for_each_entry(nt, &target_list, list) { |
| 747 | netconsole_target_get(nt); | 869 | if (!nt->extended && nt->enabled && netif_running(nt->np.dev)) { |
| 748 | if (nt->enabled && netif_running(nt->np.dev)) { | ||
| 749 | /* | 870 | /* |
| 750 | * We nest this inside the for-each-target loop above | 871 | * We nest this inside the for-each-target loop above |
| 751 | * so that we're able to get as much logging out to | 872 | * so that we're able to get as much logging out to |
| @@ -760,11 +881,16 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) | |||
| 760 | left -= frag; | 881 | left -= frag; |
| 761 | } | 882 | } |
| 762 | } | 883 | } |
| 763 | netconsole_target_put(nt); | ||
| 764 | } | 884 | } |
| 765 | spin_unlock_irqrestore(&target_list_lock, flags); | 885 | spin_unlock_irqrestore(&target_list_lock, flags); |
| 766 | } | 886 | } |
| 767 | 887 | ||
| 888 | static struct console netconsole_ext = { | ||
| 889 | .name = "netcon_ext", | ||
| 890 | .flags = CON_EXTENDED, /* starts disabled, registered on first use */ | ||
| 891 | .write = write_ext_msg, | ||
| 892 | }; | ||
| 893 | |||
| 768 | static struct console netconsole = { | 894 | static struct console netconsole = { |
| 769 | .name = "netcon", | 895 | .name = "netcon", |
| 770 | .flags = CON_ENABLED, | 896 | .flags = CON_ENABLED, |
| @@ -787,7 +913,11 @@ static int __init init_netconsole(void) | |||
| 787 | goto fail; | 913 | goto fail; |
| 788 | } | 914 | } |
| 789 | /* Dump existing printks when we register */ | 915 | /* Dump existing printks when we register */ |
| 790 | netconsole.flags |= CON_PRINTBUFFER; | 916 | if (nt->extended) |
| 917 | netconsole_ext.flags |= CON_PRINTBUFFER | | ||
| 918 | CON_ENABLED; | ||
| 919 | else | ||
| 920 | netconsole.flags |= CON_PRINTBUFFER; | ||
| 791 | 921 | ||
| 792 | spin_lock_irqsave(&target_list_lock, flags); | 922 | spin_lock_irqsave(&target_list_lock, flags); |
| 793 | list_add(&nt->list, &target_list); | 923 | list_add(&nt->list, &target_list); |
| @@ -803,6 +933,8 @@ static int __init init_netconsole(void) | |||
| 803 | if (err) | 933 | if (err) |
| 804 | goto undonotifier; | 934 | goto undonotifier; |
| 805 | 935 | ||
| 936 | if (netconsole_ext.flags & CON_ENABLED) | ||
| 937 | register_console(&netconsole_ext); | ||
| 806 | register_console(&netconsole); | 938 | register_console(&netconsole); |
| 807 | pr_info("network logging started\n"); | 939 | pr_info("network logging started\n"); |
| 808 | 940 | ||
| @@ -831,6 +963,7 @@ static void __exit cleanup_netconsole(void) | |||
| 831 | { | 963 | { |
| 832 | struct netconsole_target *nt, *tmp; | 964 | struct netconsole_target *nt, *tmp; |
| 833 | 965 | ||
| 966 | unregister_console(&netconsole_ext); | ||
| 834 | unregister_console(&netconsole); | 967 | unregister_console(&netconsole); |
| 835 | dynamic_netconsole_exit(); | 968 | dynamic_netconsole_exit(); |
| 836 | unregister_netdevice_notifier(&netconsole_netdev_notifier); | 969 | unregister_netdevice_notifier(&netconsole_netdev_notifier); |
