Skip to content

Commit 20dd385

Browse files
hartkoppdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 75ed0a8 commit 20dd385

File tree

3 files changed

+96
-119
lines changed

3 files changed

+96
-119
lines changed

net/can/af_can.c

Lines changed: 34 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ static int stats_timer __read_mostly = 1;
7777
module_param(stats_timer, int, S_IRUGO);
7878
MODULE_PARM_DESC(stats_timer, "enable timer for statistics (default:on)");
7979

80-
HLIST_HEAD(can_rx_dev_list);
81-
static struct dev_rcv_lists can_rx_alldev_list;
80+
/* receive filters subscribed for 'all' CAN devices */
81+
struct dev_rcv_lists can_rx_alldev_list;
8282
static DEFINE_SPINLOCK(can_rcvlists_lock);
8383

8484
static struct kmem_cache *rcv_cache __read_mostly;
@@ -292,28 +292,10 @@ EXPORT_SYMBOL(can_send);
292292

293293
static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev)
294294
{
295-
struct dev_rcv_lists *d = NULL;
296-
struct hlist_node *n;
297-
298-
/*
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;
295+
if (!dev)
296+
return &can_rx_alldev_list;
297+
else
298+
return (struct dev_rcv_lists *)dev->ml_priv;
317299
}
318300

319301
/**
@@ -467,16 +449,6 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
467449
}
468450
EXPORT_SYMBOL(can_rx_register);
469451

470-
/*
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-
480452
/*
481453
* can_rx_delete_receiver - rcu callback for single receiver entry removal
482454
*/
@@ -541,7 +513,6 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
541513
"dev %s, id %03X, mask %03X\n",
542514
DNAME(dev), can_id, mask);
543515
r = NULL;
544-
d = NULL;
545516
goto out;
546517
}
547518

@@ -552,21 +523,17 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
552523
can_pstats.rcv_entries--;
553524

554525
/* remove device structure requested by NETDEV_UNREGISTER */
555-
if (d->remove_on_zero_entries && !d->entries)
556-
hlist_del_rcu(&d->list);
557-
else
558-
d = NULL;
526+
if (d->remove_on_zero_entries && !d->entries) {
527+
kfree(d);
528+
dev->ml_priv = NULL;
529+
}
559530

560531
out:
561532
spin_unlock(&can_rcvlists_lock);
562533

563534
/* schedule the receiver item for deletion */
564535
if (r)
565536
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);
570537
}
571538
EXPORT_SYMBOL(can_rx_unregister);
572539

@@ -780,48 +747,35 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
780747

781748
case NETDEV_REGISTER:
782749

783-
/*
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-
750+
/* create new dev_rcv_lists for this device */
792751
d = kzalloc(sizeof(*d), GFP_KERNEL);
793752
if (!d) {
794753
printk(KERN_ERR
795754
"can: allocation of receive list failed\n");
796755
return NOTIFY_DONE;
797756
}
798-
d->dev = dev;
799-
800-
spin_lock(&can_rcvlists_lock);
801-
hlist_add_head_rcu(&d->list, &can_rx_dev_list);
802-
spin_unlock(&can_rcvlists_lock);
757+
BUG_ON(dev->ml_priv);
758+
dev->ml_priv = d;
803759

804760
break;
805761

806762
case NETDEV_UNREGISTER:
807763
spin_lock(&can_rcvlists_lock);
808764

809-
d = find_dev_rcv_lists(dev);
765+
d = dev->ml_priv;
810766
if (d) {
811-
if (d->entries) {
767+
if (d->entries)
812768
d->remove_on_zero_entries = 1;
813-
d = NULL;
814-
} else
815-
hlist_del_rcu(&d->list);
769+
else {
770+
kfree(d);
771+
dev->ml_priv = NULL;
772+
}
816773
} else
817774
printk(KERN_ERR "can: notifier: receive list not "
818775
"found for dev %s\n", dev->name);
819776

820777
spin_unlock(&can_rcvlists_lock);
821778

822-
if (d)
823-
call_rcu(&d->rcu, can_rx_delete_device);
824-
825779
break;
826780
}
827781

@@ -853,21 +807,13 @@ static __init int can_init(void)
853807
{
854808
printk(banner);
855809

810+
memset(&can_rx_alldev_list, 0, sizeof(can_rx_alldev_list));
811+
856812
rcv_cache = kmem_cache_create("can_receiver", sizeof(struct receiver),
857813
0, 0, NULL);
858814
if (!rcv_cache)
859815
return -ENOMEM;
860816

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-
871817
if (stats_timer) {
872818
/* the statistics are updated every second (timer triggered) */
873819
setup_timer(&can_stattimer, can_stat_update, 0);
@@ -887,8 +833,7 @@ static __init int can_init(void)
887833

888834
static __exit void can_exit(void)
889835
{
890-
struct dev_rcv_lists *d;
891-
struct hlist_node *n, *next;
836+
struct net_device *dev;
892837

893838
if (stats_timer)
894839
del_timer(&can_stattimer);
@@ -900,14 +845,19 @@ static __exit void can_exit(void)
900845
unregister_netdevice_notifier(&can_netdev_notifier);
901846
sock_unregister(PF_CAN);
902847

903-
/* remove can_rx_dev_list */
904-
spin_lock(&can_rcvlists_lock);
905-
hlist_del(&can_rx_alldev_list.list);
906-
hlist_for_each_entry_safe(d, n, next, &can_rx_dev_list, list) {
907-
hlist_del(&d->list);
908-
kfree(d);
848+
/* remove created dev_rcv_lists from still registered CAN devices */
849+
rcu_read_lock();
850+
for_each_netdev_rcu(&init_net, dev) {
851+
if (dev->type == ARPHRD_CAN && dev->ml_priv){
852+
853+
struct dev_rcv_lists *d = dev->ml_priv;
854+
855+
BUG_ON(d->entries);
856+
kfree(d);
857+
dev->ml_priv = NULL;
858+
}
909859
}
910-
spin_unlock(&can_rcvlists_lock);
860+
rcu_read_unlock();
911861

912862
rcu_barrier(); /* Wait for completion of call_rcu()'s */
913863

net/can/af_can.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,8 @@ struct receiver {
6363

6464
enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_EFF, RX_MAX };
6565

66+
/* per device receive filters linked at dev->ml_priv */
6667
struct dev_rcv_lists {
67-
struct hlist_node list;
68-
struct rcu_head rcu;
69-
struct net_device *dev;
7068
struct hlist_head rx[RX_MAX];
7169
struct hlist_head rx_sff[0x800];
7270
int remove_on_zero_entries;

net/can/proc.c

Lines changed: 61 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include <linux/proc_fs.h>
4646
#include <linux/list.h>
4747
#include <linux/rcupdate.h>
48+
#include <linux/if_arp.h>
4849
#include <linux/can/core.h>
4950

5051
#include "af_can.h"
@@ -84,6 +85,9 @@ static const char rx_list_name[][8] = {
8485
[RX_EFF] = "rx_eff",
8586
};
8687

88+
/* receive filters subscribed for 'all' CAN devices */
89+
extern struct dev_rcv_lists can_rx_alldev_list;
90+
8791
/*
8892
* af_can statistics stuff
8993
*/
@@ -190,10 +194,6 @@ void can_stat_update(unsigned long data)
190194

191195
/*
192196
* 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-
*
197197
*/
198198

199199
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,
202202
struct receiver *r;
203203
struct hlist_node *n;
204204

205-
rcu_read_lock();
206205
hlist_for_each_entry_rcu(r, n, rx_list, list) {
207206
char *fmt = (r->can_id & CAN_EFF_FLAG)?
208207
" %-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,
212211
(unsigned long)r->func, (unsigned long)r->data,
213212
r->matches, r->ident);
214213
}
215-
rcu_read_unlock();
216214
}
217215

218216
static void can_print_recv_banner(struct seq_file *m)
@@ -346,24 +344,39 @@ static const struct file_operations can_version_proc_fops = {
346344
.release = single_release,
347345
};
348346

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+
349359
static int can_rcvlist_proc_show(struct seq_file *m, void *v)
350360
{
351361
/* double cast to prevent GCC warning */
352362
int idx = (int)(long)m->private;
363+
struct net_device *dev;
353364
struct dev_rcv_lists *d;
354-
struct hlist_node *n;
355365

356366
seq_printf(m, "\nreceive list '%s':\n", rx_list_name[idx]);
357367

358368
rcu_read_lock();
359-
hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) {
360369

361-
if (!hlist_empty(&d->rx[idx])) {
362-
can_print_recv_banner(m);
363-
can_print_rcvlist(m, &d->rx[idx], d->dev);
364-
} else
365-
seq_printf(m, " (%s: no entry)\n", DNAME(d->dev));
370+
/* receive list for 'all' CAN devices (dev == NULL) */
371+
d = &can_rx_alldev_list;
372+
can_rcvlist_proc_show_one(m, idx, NULL, d);
373+
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);
366378
}
379+
367380
rcu_read_unlock();
368381

369382
seq_putc(m, '\n');
@@ -383,34 +396,50 @@ static const struct file_operations can_rcvlist_proc_fops = {
383396
.release = single_release,
384397
};
385398

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+
386423
static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v)
387424
{
425+
struct net_device *dev;
388426
struct dev_rcv_lists *d;
389-
struct hlist_node *n;
390427

391428
/* RX_SFF */
392429
seq_puts(m, "\nreceive list 'rx_sff':\n");
393430

394431
rcu_read_lock();
395-
hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) {
396-
int i, all_empty = 1;
397-
/* check wether at least one list is non-empty */
398-
for (i = 0; i < 0x800; i++)
399-
if (!hlist_empty(&d->rx_sff[i])) {
400-
all_empty = 0;
401-
break;
402-
}
403-
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));
432+
433+
/* sff receive list for 'all' CAN devices (dev == NULL) */
434+
d = &can_rx_alldev_list;
435+
can_rcvlist_sff_proc_show_one(m, NULL, d);
436+
437+
/* sff receive list for registered CAN devices */
438+
for_each_netdev_rcu(&init_net, dev) {
439+
if (dev->type == ARPHRD_CAN && dev->ml_priv)
440+
can_rcvlist_sff_proc_show_one(m, dev, dev->ml_priv);
413441
}
442+
414443
rcu_read_unlock();
415444

416445
seq_putc(m, '\n');

0 commit comments

Comments
 (0)