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/netconsole.c | |
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/netconsole.c')
-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); |