diff options
Diffstat (limited to 'net/can')
-rw-r--r-- | net/can/af_can.c | 118 | ||||
-rw-r--r-- | net/can/af_can.h | 4 | ||||
-rw-r--r-- | net/can/proc.c | 93 |
3 files changed, 96 insertions, 119 deletions
diff --git a/net/can/af_can.c b/net/can/af_can.c index 51adc4c2b860..bc18b084ffdb 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c | |||
@@ -77,8 +77,8 @@ static int stats_timer __read_mostly = 1; | |||
77 | module_param(stats_timer, int, S_IRUGO); | 77 | module_param(stats_timer, int, S_IRUGO); |
78 | MODULE_PARM_DESC(stats_timer, "enable timer for statistics (default:on)"); | 78 | MODULE_PARM_DESC(stats_timer, "enable timer for statistics (default:on)"); |
79 | 79 | ||
80 | HLIST_HEAD(can_rx_dev_list); | 80 | /* receive filters subscribed for 'all' CAN devices */ |
81 | static struct dev_rcv_lists can_rx_alldev_list; | 81 | struct dev_rcv_lists can_rx_alldev_list; |
82 | static DEFINE_SPINLOCK(can_rcvlists_lock); | 82 | static DEFINE_SPINLOCK(can_rcvlists_lock); |
83 | 83 | ||
84 | static struct kmem_cache *rcv_cache __read_mostly; | 84 | static struct kmem_cache *rcv_cache __read_mostly; |
@@ -292,28 +292,10 @@ EXPORT_SYMBOL(can_send); | |||
292 | 292 | ||
293 | static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev) | 293 | static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev) |
294 | { | 294 | { |
295 | struct dev_rcv_lists *d = NULL; | 295 | if (!dev) |
296 | struct hlist_node *n; | 296 | return &can_rx_alldev_list; |
297 | 297 | else | |
298 | /* | 298 | return (struct dev_rcv_lists *)dev->ml_priv; |
299 | * find receive list for this device | ||
300 | * | ||
301 | * The hlist_for_each_entry*() macros curse through the list | ||
302 | * using the pointer variable n and set d to the containing | ||
303 | * struct in each list iteration. Therefore, after list | ||
304 | * iteration, d is unmodified when the list is empty, and it | ||
305 | * points to last list element, when the list is non-empty | ||
306 | * but no match in the loop body is found. I.e. d is *not* | ||
307 | * NULL when no match is found. We can, however, use the | ||
308 | * cursor variable n to decide if a match was found. | ||
309 | */ | ||
310 | |||
311 | hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) { | ||
312 | if (d->dev == dev) | ||
313 | break; | ||
314 | } | ||
315 | |||
316 | return n ? d : NULL; | ||
317 | } | 299 | } |
318 | 300 | ||
319 | /** | 301 | /** |
@@ -468,16 +450,6 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask, | |||
468 | EXPORT_SYMBOL(can_rx_register); | 450 | EXPORT_SYMBOL(can_rx_register); |
469 | 451 | ||
470 | /* | 452 | /* |
471 | * can_rx_delete_device - rcu callback for dev_rcv_lists structure removal | ||
472 | */ | ||
473 | static void can_rx_delete_device(struct rcu_head *rp) | ||
474 | { | ||
475 | struct dev_rcv_lists *d = container_of(rp, struct dev_rcv_lists, rcu); | ||
476 | |||
477 | kfree(d); | ||
478 | } | ||
479 | |||
480 | /* | ||
481 | * can_rx_delete_receiver - rcu callback for single receiver entry removal | 453 | * can_rx_delete_receiver - rcu callback for single receiver entry removal |
482 | */ | 454 | */ |
483 | static void can_rx_delete_receiver(struct rcu_head *rp) | 455 | static void can_rx_delete_receiver(struct rcu_head *rp) |
@@ -541,7 +513,6 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, | |||
541 | "dev %s, id %03X, mask %03X\n", | 513 | "dev %s, id %03X, mask %03X\n", |
542 | DNAME(dev), can_id, mask); | 514 | DNAME(dev), can_id, mask); |
543 | r = NULL; | 515 | r = NULL; |
544 | d = NULL; | ||
545 | goto out; | 516 | goto out; |
546 | } | 517 | } |
547 | 518 | ||
@@ -552,10 +523,10 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, | |||
552 | can_pstats.rcv_entries--; | 523 | can_pstats.rcv_entries--; |
553 | 524 | ||
554 | /* remove device structure requested by NETDEV_UNREGISTER */ | 525 | /* remove device structure requested by NETDEV_UNREGISTER */ |
555 | if (d->remove_on_zero_entries && !d->entries) | 526 | if (d->remove_on_zero_entries && !d->entries) { |
556 | hlist_del_rcu(&d->list); | 527 | kfree(d); |
557 | else | 528 | dev->ml_priv = NULL; |
558 | d = NULL; | 529 | } |
559 | 530 | ||
560 | out: | 531 | out: |
561 | spin_unlock(&can_rcvlists_lock); | 532 | spin_unlock(&can_rcvlists_lock); |
@@ -563,10 +534,6 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask, | |||
563 | /* schedule the receiver item for deletion */ | 534 | /* schedule the receiver item for deletion */ |
564 | if (r) | 535 | if (r) |
565 | call_rcu(&r->rcu, can_rx_delete_receiver); | 536 | call_rcu(&r->rcu, can_rx_delete_receiver); |
566 | |||
567 | /* schedule the device structure for deletion */ | ||
568 | if (d) | ||
569 | call_rcu(&d->rcu, can_rx_delete_device); | ||
570 | } | 537 | } |
571 | EXPORT_SYMBOL(can_rx_unregister); | 538 | EXPORT_SYMBOL(can_rx_unregister); |
572 | 539 | ||
@@ -780,48 +747,35 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg, | |||
780 | 747 | ||
781 | case NETDEV_REGISTER: | 748 | case NETDEV_REGISTER: |
782 | 749 | ||
783 | /* | 750 | /* create new dev_rcv_lists for this device */ |
784 | * create new dev_rcv_lists for this device | ||
785 | * | ||
786 | * N.B. zeroing the struct is the correct initialization | ||
787 | * for the embedded hlist_head structs. | ||
788 | * Another list type, e.g. list_head, would require | ||
789 | * explicit initialization. | ||
790 | */ | ||
791 | |||
792 | d = kzalloc(sizeof(*d), GFP_KERNEL); | 751 | d = kzalloc(sizeof(*d), GFP_KERNEL); |
793 | if (!d) { | 752 | if (!d) { |
794 | printk(KERN_ERR | 753 | printk(KERN_ERR |
795 | "can: allocation of receive list failed\n"); | 754 | "can: allocation of receive list failed\n"); |
796 | return NOTIFY_DONE; | 755 | return NOTIFY_DONE; |
797 | } | 756 | } |
798 | d->dev = dev; | 757 | BUG_ON(dev->ml_priv); |
799 | 758 | dev->ml_priv = d; | |
800 | spin_lock(&can_rcvlists_lock); | ||
801 | hlist_add_head_rcu(&d->list, &can_rx_dev_list); | ||
802 | spin_unlock(&can_rcvlists_lock); | ||
803 | 759 | ||
804 | break; | 760 | break; |
805 | 761 | ||
806 | case NETDEV_UNREGISTER: | 762 | case NETDEV_UNREGISTER: |
807 | spin_lock(&can_rcvlists_lock); | 763 | spin_lock(&can_rcvlists_lock); |
808 | 764 | ||
809 | d = find_dev_rcv_lists(dev); | 765 | d = dev->ml_priv; |
810 | if (d) { | 766 | if (d) { |
811 | if (d->entries) { | 767 | if (d->entries) |
812 | d->remove_on_zero_entries = 1; | 768 | d->remove_on_zero_entries = 1; |
813 | d = NULL; | 769 | else { |
814 | } else | 770 | kfree(d); |
815 | hlist_del_rcu(&d->list); | 771 | dev->ml_priv = NULL; |
772 | } | ||
816 | } else | 773 | } else |
817 | printk(KERN_ERR "can: notifier: receive list not " | 774 | printk(KERN_ERR "can: notifier: receive list not " |
818 | "found for dev %s\n", dev->name); | 775 | "found for dev %s\n", dev->name); |
819 | 776 | ||
820 | spin_unlock(&can_rcvlists_lock); | 777 | spin_unlock(&can_rcvlists_lock); |
821 | 778 | ||
822 | if (d) | ||
823 | call_rcu(&d->rcu, can_rx_delete_device); | ||
824 | |||
825 | break; | 779 | break; |
826 | } | 780 | } |
827 | 781 | ||
@@ -853,21 +807,13 @@ static __init int can_init(void) | |||
853 | { | 807 | { |
854 | printk(banner); | 808 | printk(banner); |
855 | 809 | ||
810 | memset(&can_rx_alldev_list, 0, sizeof(can_rx_alldev_list)); | ||
811 | |||
856 | rcv_cache = kmem_cache_create("can_receiver", sizeof(struct receiver), | 812 | rcv_cache = kmem_cache_create("can_receiver", sizeof(struct receiver), |
857 | 0, 0, NULL); | 813 | 0, 0, NULL); |
858 | if (!rcv_cache) | 814 | if (!rcv_cache) |
859 | return -ENOMEM; | 815 | return -ENOMEM; |
860 | 816 | ||
861 | /* | ||
862 | * Insert can_rx_alldev_list for reception on all devices. | ||
863 | * This struct is zero initialized which is correct for the | ||
864 | * embedded hlist heads, the dev pointer, and the entries counter. | ||
865 | */ | ||
866 | |||
867 | spin_lock(&can_rcvlists_lock); | ||
868 | hlist_add_head_rcu(&can_rx_alldev_list.list, &can_rx_dev_list); | ||
869 | spin_unlock(&can_rcvlists_lock); | ||
870 | |||
871 | if (stats_timer) { | 817 | if (stats_timer) { |
872 | /* the statistics are updated every second (timer triggered) */ | 818 | /* the statistics are updated every second (timer triggered) */ |
873 | setup_timer(&can_stattimer, can_stat_update, 0); | 819 | setup_timer(&can_stattimer, can_stat_update, 0); |
@@ -887,8 +833,7 @@ static __init int can_init(void) | |||
887 | 833 | ||
888 | static __exit void can_exit(void) | 834 | static __exit void can_exit(void) |
889 | { | 835 | { |
890 | struct dev_rcv_lists *d; | 836 | struct net_device *dev; |
891 | struct hlist_node *n, *next; | ||
892 | 837 | ||
893 | if (stats_timer) | 838 | if (stats_timer) |
894 | del_timer(&can_stattimer); | 839 | del_timer(&can_stattimer); |
@@ -900,14 +845,19 @@ static __exit void can_exit(void) | |||
900 | unregister_netdevice_notifier(&can_netdev_notifier); | 845 | unregister_netdevice_notifier(&can_netdev_notifier); |
901 | sock_unregister(PF_CAN); | 846 | sock_unregister(PF_CAN); |
902 | 847 | ||
903 | /* remove can_rx_dev_list */ | 848 | /* remove created dev_rcv_lists from still registered CAN devices */ |
904 | spin_lock(&can_rcvlists_lock); | 849 | rcu_read_lock(); |
905 | hlist_del(&can_rx_alldev_list.list); | 850 | for_each_netdev_rcu(&init_net, dev) { |
906 | hlist_for_each_entry_safe(d, n, next, &can_rx_dev_list, list) { | 851 | if (dev->type == ARPHRD_CAN && dev->ml_priv){ |
907 | hlist_del(&d->list); | 852 | |
908 | kfree(d); | 853 | struct dev_rcv_lists *d = dev->ml_priv; |
854 | |||
855 | BUG_ON(d->entries); | ||
856 | kfree(d); | ||
857 | dev->ml_priv = NULL; | ||
858 | } | ||
909 | } | 859 | } |
910 | spin_unlock(&can_rcvlists_lock); | 860 | rcu_read_unlock(); |
911 | 861 | ||
912 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ | 862 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
913 | 863 | ||
diff --git a/net/can/af_can.h b/net/can/af_can.h index 18f91e37cc30..34253b84e30f 100644 --- a/net/can/af_can.h +++ b/net/can/af_can.h | |||
@@ -63,10 +63,8 @@ struct receiver { | |||
63 | 63 | ||
64 | enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_EFF, RX_MAX }; | 64 | enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_EFF, RX_MAX }; |
65 | 65 | ||
66 | /* per device receive filters linked at dev->ml_priv */ | ||
66 | struct dev_rcv_lists { | 67 | struct dev_rcv_lists { |
67 | struct hlist_node list; | ||
68 | struct rcu_head rcu; | ||
69 | struct net_device *dev; | ||
70 | struct hlist_head rx[RX_MAX]; | 68 | struct hlist_head rx[RX_MAX]; |
71 | struct hlist_head rx_sff[0x800]; | 69 | struct hlist_head rx_sff[0x800]; |
72 | int remove_on_zero_entries; | 70 | int remove_on_zero_entries; |
diff --git a/net/can/proc.c b/net/can/proc.c index 9b9ad29be567..f4265cc9c3fb 100644 --- a/net/can/proc.c +++ b/net/can/proc.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/proc_fs.h> | 45 | #include <linux/proc_fs.h> |
46 | #include <linux/list.h> | 46 | #include <linux/list.h> |
47 | #include <linux/rcupdate.h> | 47 | #include <linux/rcupdate.h> |
48 | #include <linux/if_arp.h> | ||
48 | #include <linux/can/core.h> | 49 | #include <linux/can/core.h> |
49 | 50 | ||
50 | #include "af_can.h" | 51 | #include "af_can.h" |
@@ -84,6 +85,9 @@ static const char rx_list_name[][8] = { | |||
84 | [RX_EFF] = "rx_eff", | 85 | [RX_EFF] = "rx_eff", |
85 | }; | 86 | }; |
86 | 87 | ||
88 | /* receive filters subscribed for 'all' CAN devices */ | ||
89 | extern struct dev_rcv_lists can_rx_alldev_list; | ||
90 | |||
87 | /* | 91 | /* |
88 | * af_can statistics stuff | 92 | * af_can statistics stuff |
89 | */ | 93 | */ |
@@ -190,10 +194,6 @@ void can_stat_update(unsigned long data) | |||
190 | 194 | ||
191 | /* | 195 | /* |
192 | * proc read functions | 196 | * proc read functions |
193 | * | ||
194 | * From known use-cases we expect about 10 entries in a receive list to be | ||
195 | * printed in the proc_fs. So PAGE_SIZE is definitely enough space here. | ||
196 | * | ||
197 | */ | 197 | */ |
198 | 198 | ||
199 | static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list, | 199 | static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list, |
@@ -202,7 +202,6 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list, | |||
202 | struct receiver *r; | 202 | struct receiver *r; |
203 | struct hlist_node *n; | 203 | struct hlist_node *n; |
204 | 204 | ||
205 | rcu_read_lock(); | ||
206 | hlist_for_each_entry_rcu(r, n, rx_list, list) { | 205 | hlist_for_each_entry_rcu(r, n, rx_list, list) { |
207 | char *fmt = (r->can_id & CAN_EFF_FLAG)? | 206 | char *fmt = (r->can_id & CAN_EFF_FLAG)? |
208 | " %-5s %08X %08x %08x %08x %8ld %s\n" : | 207 | " %-5s %08X %08x %08x %08x %8ld %s\n" : |
@@ -212,7 +211,6 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list, | |||
212 | (unsigned long)r->func, (unsigned long)r->data, | 211 | (unsigned long)r->func, (unsigned long)r->data, |
213 | r->matches, r->ident); | 212 | r->matches, r->ident); |
214 | } | 213 | } |
215 | rcu_read_unlock(); | ||
216 | } | 214 | } |
217 | 215 | ||
218 | static void can_print_recv_banner(struct seq_file *m) | 216 | static void can_print_recv_banner(struct seq_file *m) |
@@ -346,24 +344,39 @@ static const struct file_operations can_version_proc_fops = { | |||
346 | .release = single_release, | 344 | .release = single_release, |
347 | }; | 345 | }; |
348 | 346 | ||
347 | static inline void can_rcvlist_proc_show_one(struct seq_file *m, int idx, | ||
348 | struct net_device *dev, | ||
349 | struct dev_rcv_lists *d) | ||
350 | { | ||
351 | if (!hlist_empty(&d->rx[idx])) { | ||
352 | can_print_recv_banner(m); | ||
353 | can_print_rcvlist(m, &d->rx[idx], dev); | ||
354 | } else | ||
355 | seq_printf(m, " (%s: no entry)\n", DNAME(dev)); | ||
356 | |||
357 | } | ||
358 | |||
349 | static int can_rcvlist_proc_show(struct seq_file *m, void *v) | 359 | static int can_rcvlist_proc_show(struct seq_file *m, void *v) |
350 | { | 360 | { |
351 | /* double cast to prevent GCC warning */ | 361 | /* double cast to prevent GCC warning */ |
352 | int idx = (int)(long)m->private; | 362 | int idx = (int)(long)m->private; |
363 | struct net_device *dev; | ||
353 | struct dev_rcv_lists *d; | 364 | struct dev_rcv_lists *d; |
354 | struct hlist_node *n; | ||
355 | 365 | ||
356 | seq_printf(m, "\nreceive list '%s':\n", rx_list_name[idx]); | 366 | seq_printf(m, "\nreceive list '%s':\n", rx_list_name[idx]); |
357 | 367 | ||
358 | rcu_read_lock(); | 368 | rcu_read_lock(); |
359 | hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) { | ||
360 | 369 | ||
361 | if (!hlist_empty(&d->rx[idx])) { | 370 | /* receive list for 'all' CAN devices (dev == NULL) */ |
362 | can_print_recv_banner(m); | 371 | d = &can_rx_alldev_list; |
363 | can_print_rcvlist(m, &d->rx[idx], d->dev); | 372 | can_rcvlist_proc_show_one(m, idx, NULL, d); |
364 | } else | 373 | |
365 | seq_printf(m, " (%s: no entry)\n", DNAME(d->dev)); | 374 | /* receive list for registered CAN devices */ |
375 | for_each_netdev_rcu(&init_net, dev) { | ||
376 | if (dev->type == ARPHRD_CAN && dev->ml_priv) | ||
377 | can_rcvlist_proc_show_one(m, idx, dev, dev->ml_priv); | ||
366 | } | 378 | } |
379 | |||
367 | rcu_read_unlock(); | 380 | rcu_read_unlock(); |
368 | 381 | ||
369 | seq_putc(m, '\n'); | 382 | seq_putc(m, '\n'); |
@@ -383,34 +396,50 @@ static const struct file_operations can_rcvlist_proc_fops = { | |||
383 | .release = single_release, | 396 | .release = single_release, |
384 | }; | 397 | }; |
385 | 398 | ||
399 | static inline void can_rcvlist_sff_proc_show_one(struct seq_file *m, | ||
400 | struct net_device *dev, | ||
401 | struct dev_rcv_lists *d) | ||
402 | { | ||
403 | int i; | ||
404 | int all_empty = 1; | ||
405 | |||
406 | /* check wether at least one list is non-empty */ | ||
407 | for (i = 0; i < 0x800; i++) | ||
408 | if (!hlist_empty(&d->rx_sff[i])) { | ||
409 | all_empty = 0; | ||
410 | break; | ||
411 | } | ||
412 | |||
413 | if (!all_empty) { | ||
414 | can_print_recv_banner(m); | ||
415 | for (i = 0; i < 0x800; i++) { | ||
416 | if (!hlist_empty(&d->rx_sff[i])) | ||
417 | can_print_rcvlist(m, &d->rx_sff[i], dev); | ||
418 | } | ||
419 | } else | ||
420 | seq_printf(m, " (%s: no entry)\n", DNAME(dev)); | ||
421 | } | ||
422 | |||
386 | static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v) | 423 | static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v) |
387 | { | 424 | { |
425 | struct net_device *dev; | ||
388 | struct dev_rcv_lists *d; | 426 | struct dev_rcv_lists *d; |
389 | struct hlist_node *n; | ||
390 | 427 | ||
391 | /* RX_SFF */ | 428 | /* RX_SFF */ |
392 | seq_puts(m, "\nreceive list 'rx_sff':\n"); | 429 | seq_puts(m, "\nreceive list 'rx_sff':\n"); |
393 | 430 | ||
394 | rcu_read_lock(); | 431 | rcu_read_lock(); |
395 | hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) { | 432 | |
396 | int i, all_empty = 1; | 433 | /* sff receive list for 'all' CAN devices (dev == NULL) */ |
397 | /* check wether at least one list is non-empty */ | 434 | d = &can_rx_alldev_list; |
398 | for (i = 0; i < 0x800; i++) | 435 | can_rcvlist_sff_proc_show_one(m, NULL, d); |
399 | if (!hlist_empty(&d->rx_sff[i])) { | 436 | |
400 | all_empty = 0; | 437 | /* sff receive list for registered CAN devices */ |
401 | break; | 438 | for_each_netdev_rcu(&init_net, dev) { |
402 | } | 439 | if (dev->type == ARPHRD_CAN && dev->ml_priv) |
403 | 440 | can_rcvlist_sff_proc_show_one(m, dev, dev->ml_priv); | |
404 | if (!all_empty) { | ||
405 | can_print_recv_banner(m); | ||
406 | for (i = 0; i < 0x800; i++) { | ||
407 | if (!hlist_empty(&d->rx_sff[i])) | ||
408 | can_print_rcvlist(m, &d->rx_sff[i], | ||
409 | d->dev); | ||
410 | } | ||
411 | } else | ||
412 | seq_printf(m, " (%s: no entry)\n", DNAME(d->dev)); | ||
413 | } | 441 | } |
442 | |||
414 | rcu_read_unlock(); | 443 | rcu_read_unlock(); |
415 | 444 | ||
416 | seq_putc(m, '\n'); | 445 | seq_putc(m, '\n'); |