aboutsummaryrefslogtreecommitdiffstats
path: root/net/can
diff options
context:
space:
mode:
authorOliver Hartkopp <socketcan@hartkopp.net>2009-12-25 01:47:47 -0500
committerDavid S. Miller <davem@davemloft.net>2010-01-04 00:31:03 -0500
commit20dd3850bcf860561496827b711fa10fecf6e787 (patch)
tree95ecd549717f2d654b870ffb44d342c04ab048b6 /net/can
parent75ed0a897208c3273fd8dc0f71e1417dba5a049b (diff)
can: Speed up CAN frame receiption by using ml_priv
this patch removes the hlist that contains the CAN receiver filter lists. It uses the 'midlayer private' pointer ml_priv and links the filters directly to the CAN netdevice, which allows to omit the walk through the complete CAN devices hlist for each received CAN frame. This patch is tested and does not remove any locking. Signed-off-by: Oliver Hartkopp <oliver@hartkopp.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/can')
-rw-r--r--net/can/af_can.c118
-rw-r--r--net/can/af_can.h4
-rw-r--r--net/can/proc.c93
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;
77module_param(stats_timer, int, S_IRUGO); 77module_param(stats_timer, int, S_IRUGO);
78MODULE_PARM_DESC(stats_timer, "enable timer for statistics (default:on)"); 78MODULE_PARM_DESC(stats_timer, "enable timer for statistics (default:on)");
79 79
80HLIST_HEAD(can_rx_dev_list); 80/* receive filters subscribed for 'all' CAN devices */
81static struct dev_rcv_lists can_rx_alldev_list; 81struct dev_rcv_lists can_rx_alldev_list;
82static DEFINE_SPINLOCK(can_rcvlists_lock); 82static DEFINE_SPINLOCK(can_rcvlists_lock);
83 83
84static struct kmem_cache *rcv_cache __read_mostly; 84static struct kmem_cache *rcv_cache __read_mostly;
@@ -292,28 +292,10 @@ EXPORT_SYMBOL(can_send);
292 292
293static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev) 293static 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,
468EXPORT_SYMBOL(can_rx_register); 450EXPORT_SYMBOL(can_rx_register);
469 451
470/* 452/*
471 * can_rx_delete_device - rcu callback for dev_rcv_lists structure removal
472 */
473static 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 */
483static void can_rx_delete_receiver(struct rcu_head *rp) 455static 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}
571EXPORT_SYMBOL(can_rx_unregister); 538EXPORT_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
888static __exit void can_exit(void) 834static __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
64enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_EFF, RX_MAX }; 64enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_EFF, RX_MAX };
65 65
66/* per device receive filters linked at dev->ml_priv */
66struct dev_rcv_lists { 67struct 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 */
89extern 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
199static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list, 199static 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
218static void can_print_recv_banner(struct seq_file *m) 216static 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
347static 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
349static int can_rcvlist_proc_show(struct seq_file *m, void *v) 359static 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
399static 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
386static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v) 423static 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');