diff options
Diffstat (limited to 'net/can/proc.c')
-rw-r--r-- | net/can/proc.c | 93 |
1 files changed, 61 insertions, 32 deletions
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'); |