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'); |
