Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: complete initial namespace support

The statistics and its proc output was not implemented as per-net in the
initial network namespace support by Mario Kicherer (8e8cda6d737d).
This patch adds the missing per-net statistics for the CAN subsystem.

Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Oliver Hartkopp and committed by
Marc Kleine-Budde
cb5635a3 f2e72f43

+121 -105
+2 -2
include/linux/can/core.h
··· 5 5 * 6 6 * Authors: Oliver Hartkopp <oliver.hartkopp@volkswagen.de> 7 7 * Urs Thuermann <urs.thuermann@volkswagen.de> 8 - * Copyright (c) 2002-2007 Volkswagen Group Electronic Research 8 + * Copyright (c) 2002-2017 Volkswagen Group Electronic Research 9 9 * All rights reserved. 10 10 * 11 11 */ ··· 17 17 #include <linux/skbuff.h> 18 18 #include <linux/netdevice.h> 19 19 20 - #define CAN_VERSION "20120528" 20 + #define CAN_VERSION "20170425" 21 21 22 22 /* increment this number each time you change some user-space interface */ 23 23 #define CAN_ABI_VERSION "9"
+5
include/net/netns/can.h
··· 8 8 #include <linux/spinlock.h> 9 9 10 10 struct dev_rcv_lists; 11 + struct s_stats; 12 + struct s_pstats; 11 13 12 14 struct netns_can { 13 15 #if IS_ENABLED(CONFIG_PROC_FS) ··· 28 26 /* receive filters subscribed for 'all' CAN devices */ 29 27 struct dev_rcv_lists *can_rx_alldev_list; 30 28 spinlock_t can_rcvlists_lock; 29 + struct timer_list can_stattimer;/* timer for statistics update */ 30 + struct s_stats *can_stats; /* packet statistics */ 31 + struct s_pstats *can_pstats; /* receive list statistics */ 31 32 }; 32 33 33 34 #endif /* __NETNS_CAN_H__ */
+38 -33
net/can/af_can.c
··· 2 2 * af_can.c - Protocol family CAN core module 3 3 * (used by different CAN protocol modules) 4 4 * 5 - * Copyright (c) 2002-2007 Volkswagen Group Electronic Research 5 + * Copyright (c) 2002-2017 Volkswagen Group Electronic Research 6 6 * All rights reserved. 7 7 * 8 8 * Redistribution and use in source and binary forms, with or without ··· 80 80 /* table of registered CAN protocols */ 81 81 static const struct can_proto *proto_tab[CAN_NPROTO] __read_mostly; 82 82 static DEFINE_MUTEX(proto_tab_lock); 83 - 84 - struct timer_list can_stattimer; /* timer for statistics update */ 85 - struct s_stats can_stats; /* packet statistics */ 86 - struct s_pstats can_pstats; /* receive list statistics */ 87 83 88 84 static atomic_t skbcounter = ATOMIC_INIT(0); 89 85 ··· 217 221 { 218 222 struct sk_buff *newskb = NULL; 219 223 struct canfd_frame *cfd = (struct canfd_frame *)skb->data; 224 + struct s_stats *can_stats = dev_net(skb->dev)->can.can_stats; 220 225 int err = -EINVAL; 221 226 222 227 if (skb->len == CAN_MTU) { ··· 306 309 netif_rx_ni(newskb); 307 310 308 311 /* update statistics */ 309 - can_stats.tx_frames++; 310 - can_stats.tx_frames_delta++; 312 + can_stats->tx_frames++; 313 + can_stats->tx_frames_delta++; 311 314 312 315 return 0; 313 316 ··· 465 468 struct receiver *r; 466 469 struct hlist_head *rl; 467 470 struct dev_rcv_lists *d; 471 + struct s_pstats *can_pstats = net->can.can_pstats; 468 472 int err = 0; 469 473 470 474 /* insert new receiver (dev,canid,mask) -> (func,data) */ ··· 497 499 hlist_add_head_rcu(&r->list, rl); 498 500 d->entries++; 499 501 500 - can_pstats.rcv_entries++; 501 - if (can_pstats.rcv_entries_max < can_pstats.rcv_entries) 502 - can_pstats.rcv_entries_max = can_pstats.rcv_entries; 502 + can_pstats->rcv_entries++; 503 + if (can_pstats->rcv_entries_max < can_pstats->rcv_entries) 504 + can_pstats->rcv_entries_max = can_pstats->rcv_entries; 503 505 } else { 504 506 kmem_cache_free(rcv_cache, r); 505 507 err = -ENODEV; ··· 541 543 { 542 544 struct receiver *r = NULL; 543 545 struct hlist_head *rl; 546 + struct s_pstats *can_pstats = net->can.can_pstats; 544 547 struct dev_rcv_lists *d; 545 548 546 549 if (dev && dev->type != ARPHRD_CAN) ··· 588 589 hlist_del_rcu(&r->list); 589 590 d->entries--; 590 591 591 - if (can_pstats.rcv_entries > 0) 592 - can_pstats.rcv_entries--; 592 + if (can_pstats->rcv_entries > 0) 593 + can_pstats->rcv_entries--; 593 594 594 595 /* remove device structure requested by NETDEV_UNREGISTER */ 595 596 if (d->remove_on_zero_entries && !d->entries) { ··· 683 684 static void can_receive(struct sk_buff *skb, struct net_device *dev) 684 685 { 685 686 struct dev_rcv_lists *d; 687 + struct net *net = dev_net(dev); 688 + struct s_stats *can_stats = net->can.can_stats; 686 689 int matches; 687 690 688 691 /* update statistics */ 689 - can_stats.rx_frames++; 690 - can_stats.rx_frames_delta++; 692 + can_stats->rx_frames++; 693 + can_stats->rx_frames_delta++; 691 694 692 695 /* create non-zero unique skb identifier together with *skb */ 693 696 while (!(can_skb_prv(skb)->skbcnt)) ··· 698 697 rcu_read_lock(); 699 698 700 699 /* deliver the packet to sockets listening on all devices */ 701 - matches = can_rcv_filter(dev_net(dev)->can.can_rx_alldev_list, skb); 700 + matches = can_rcv_filter(net->can.can_rx_alldev_list, skb); 702 701 703 702 /* find receive list for this device */ 704 - d = find_dev_rcv_lists(dev_net(dev), dev); 703 + d = find_dev_rcv_lists(net, dev); 705 704 if (d) 706 705 matches += can_rcv_filter(d, skb); 707 706 ··· 711 710 consume_skb(skb); 712 711 713 712 if (matches > 0) { 714 - can_stats.matches++; 715 - can_stats.matches_delta++; 713 + can_stats->matches++; 714 + can_stats->matches_delta++; 716 715 } 717 716 } 718 717 ··· 877 876 net->can.can_rx_alldev_list = 878 877 kzalloc(sizeof(struct dev_rcv_lists), GFP_KERNEL); 879 878 880 - if (IS_ENABLED(CONFIG_PROC_FS)) 879 + net->can.can_stats = kzalloc(sizeof(struct s_stats), GFP_KERNEL); 880 + net->can.can_pstats = kzalloc(sizeof(struct s_pstats), GFP_KERNEL); 881 + 882 + if (IS_ENABLED(CONFIG_PROC_FS)) { 883 + /* the statistics are updated every second (timer triggered) */ 884 + if (stats_timer) { 885 + setup_timer(&net->can.can_stattimer, can_stat_update, 886 + (unsigned long)net); 887 + mod_timer(&net->can.can_stattimer, 888 + round_jiffies(jiffies + HZ)); 889 + } 890 + net->can.can_stats->jiffies_init = jiffies; 881 891 can_init_proc(net); 892 + } 882 893 883 894 return 0; 884 895 } ··· 899 886 { 900 887 struct net_device *dev; 901 888 902 - if (IS_ENABLED(CONFIG_PROC_FS)) 889 + if (IS_ENABLED(CONFIG_PROC_FS)) { 903 890 can_remove_proc(net); 891 + if (stats_timer) 892 + del_timer_sync(&net->can.can_stattimer); 893 + } 904 894 905 895 /* remove created dev_rcv_lists from still registered CAN devices */ 906 896 rcu_read_lock(); ··· 919 903 rcu_read_unlock(); 920 904 921 905 kfree(net->can.can_rx_alldev_list); 906 + kfree(net->can.can_stats); 907 + kfree(net->can.can_pstats); 922 908 } 923 909 924 910 /* ··· 968 950 if (!rcv_cache) 969 951 return -ENOMEM; 970 952 971 - if (IS_ENABLED(CONFIG_PROC_FS)) { 972 - if (stats_timer) { 973 - /* the statistics are updated every second (timer triggered) */ 974 - setup_timer(&can_stattimer, can_stat_update, 0); 975 - mod_timer(&can_stattimer, round_jiffies(jiffies + HZ)); 976 - } 977 - } 978 - 979 953 register_pernet_subsys(&can_pernet_ops); 980 954 981 955 /* protocol register */ ··· 981 971 982 972 static __exit void can_exit(void) 983 973 { 984 - if (IS_ENABLED(CONFIG_PROC_FS)) { 985 - if (stats_timer) 986 - del_timer_sync(&can_stattimer); 987 - } 988 - 989 974 /* protocol unregister */ 990 975 dev_remove_pack(&canfd_packet); 991 976 dev_remove_pack(&can_packet);
-5
net/can/af_can.h
··· 115 115 void can_remove_proc(struct net *net); 116 116 void can_stat_update(unsigned long data); 117 117 118 - /* structures and variables from af_can.c needed in proc.c for reading */ 119 - extern struct timer_list can_stattimer; /* timer for statistics update */ 120 - extern struct s_stats can_stats; /* packet statistics */ 121 - extern struct s_pstats can_pstats; /* receive list statistics */ 122 - 123 118 #endif /* AF_CAN_H */
+76 -65
net/can/proc.c
··· 75 75 * af_can statistics stuff 76 76 */ 77 77 78 - static void can_init_stats(void) 78 + static void can_init_stats(struct net *net) 79 79 { 80 + struct s_stats *can_stats = net->can.can_stats; 81 + struct s_pstats *can_pstats = net->can.can_pstats; 80 82 /* 81 83 * This memset function is called from a timer context (when 82 84 * can_stattimer is active which is the default) OR in a process 83 85 * context (reading the proc_fs when can_stattimer is disabled). 84 86 */ 85 - memset(&can_stats, 0, sizeof(can_stats)); 86 - can_stats.jiffies_init = jiffies; 87 + memset(can_stats, 0, sizeof(struct s_stats)); 88 + can_stats->jiffies_init = jiffies; 87 89 88 - can_pstats.stats_reset++; 90 + can_pstats->stats_reset++; 89 91 90 92 if (user_reset) { 91 93 user_reset = 0; 92 - can_pstats.user_reset++; 94 + can_pstats->user_reset++; 93 95 } 94 96 } 95 97 ··· 117 115 118 116 void can_stat_update(unsigned long data) 119 117 { 118 + struct net *net = (struct net *)data; 119 + struct s_stats *can_stats = net->can.can_stats; 120 120 unsigned long j = jiffies; /* snapshot */ 121 121 122 122 /* restart counting in timer context on user request */ 123 123 if (user_reset) 124 - can_init_stats(); 124 + can_init_stats(net); 125 125 126 126 /* restart counting on jiffies overflow */ 127 - if (j < can_stats.jiffies_init) 128 - can_init_stats(); 127 + if (j < can_stats->jiffies_init) 128 + can_init_stats(net); 129 129 130 130 /* prevent overflow in calc_rate() */ 131 - if (can_stats.rx_frames > (ULONG_MAX / HZ)) 132 - can_init_stats(); 131 + if (can_stats->rx_frames > (ULONG_MAX / HZ)) 132 + can_init_stats(net); 133 133 134 134 /* prevent overflow in calc_rate() */ 135 - if (can_stats.tx_frames > (ULONG_MAX / HZ)) 136 - can_init_stats(); 135 + if (can_stats->tx_frames > (ULONG_MAX / HZ)) 136 + can_init_stats(net); 137 137 138 138 /* matches overflow - very improbable */ 139 - if (can_stats.matches > (ULONG_MAX / 100)) 140 - can_init_stats(); 139 + if (can_stats->matches > (ULONG_MAX / 100)) 140 + can_init_stats(net); 141 141 142 142 /* calc total values */ 143 - if (can_stats.rx_frames) 144 - can_stats.total_rx_match_ratio = (can_stats.matches * 100) / 145 - can_stats.rx_frames; 143 + if (can_stats->rx_frames) 144 + can_stats->total_rx_match_ratio = (can_stats->matches * 100) / 145 + can_stats->rx_frames; 146 146 147 - can_stats.total_tx_rate = calc_rate(can_stats.jiffies_init, j, 148 - can_stats.tx_frames); 149 - can_stats.total_rx_rate = calc_rate(can_stats.jiffies_init, j, 150 - can_stats.rx_frames); 147 + can_stats->total_tx_rate = calc_rate(can_stats->jiffies_init, j, 148 + can_stats->tx_frames); 149 + can_stats->total_rx_rate = calc_rate(can_stats->jiffies_init, j, 150 + can_stats->rx_frames); 151 151 152 152 /* calc current values */ 153 - if (can_stats.rx_frames_delta) 154 - can_stats.current_rx_match_ratio = 155 - (can_stats.matches_delta * 100) / 156 - can_stats.rx_frames_delta; 153 + if (can_stats->rx_frames_delta) 154 + can_stats->current_rx_match_ratio = 155 + (can_stats->matches_delta * 100) / 156 + can_stats->rx_frames_delta; 157 157 158 - can_stats.current_tx_rate = calc_rate(0, HZ, can_stats.tx_frames_delta); 159 - can_stats.current_rx_rate = calc_rate(0, HZ, can_stats.rx_frames_delta); 158 + can_stats->current_tx_rate = calc_rate(0, HZ, can_stats->tx_frames_delta); 159 + can_stats->current_rx_rate = calc_rate(0, HZ, can_stats->rx_frames_delta); 160 160 161 161 /* check / update maximum values */ 162 - if (can_stats.max_tx_rate < can_stats.current_tx_rate) 163 - can_stats.max_tx_rate = can_stats.current_tx_rate; 162 + if (can_stats->max_tx_rate < can_stats->current_tx_rate) 163 + can_stats->max_tx_rate = can_stats->current_tx_rate; 164 164 165 - if (can_stats.max_rx_rate < can_stats.current_rx_rate) 166 - can_stats.max_rx_rate = can_stats.current_rx_rate; 165 + if (can_stats->max_rx_rate < can_stats->current_rx_rate) 166 + can_stats->max_rx_rate = can_stats->current_rx_rate; 167 167 168 - if (can_stats.max_rx_match_ratio < can_stats.current_rx_match_ratio) 169 - can_stats.max_rx_match_ratio = can_stats.current_rx_match_ratio; 168 + if (can_stats->max_rx_match_ratio < can_stats->current_rx_match_ratio) 169 + can_stats->max_rx_match_ratio = can_stats->current_rx_match_ratio; 170 170 171 171 /* clear values for 'current rate' calculation */ 172 - can_stats.tx_frames_delta = 0; 173 - can_stats.rx_frames_delta = 0; 174 - can_stats.matches_delta = 0; 172 + can_stats->tx_frames_delta = 0; 173 + can_stats->rx_frames_delta = 0; 174 + can_stats->matches_delta = 0; 175 175 176 176 /* restart timer (one second) */ 177 - mod_timer(&can_stattimer, round_jiffies(jiffies + HZ)); 177 + mod_timer(&net->can.can_stattimer, round_jiffies(jiffies + HZ)); 178 178 } 179 179 180 180 /* ··· 210 206 211 207 static int can_stats_proc_show(struct seq_file *m, void *v) 212 208 { 209 + struct net *net = m->private; 210 + struct s_stats *can_stats = net->can.can_stats; 211 + struct s_pstats *can_pstats = net->can.can_pstats; 212 + 213 213 seq_putc(m, '\n'); 214 - seq_printf(m, " %8ld transmitted frames (TXF)\n", can_stats.tx_frames); 215 - seq_printf(m, " %8ld received frames (RXF)\n", can_stats.rx_frames); 216 - seq_printf(m, " %8ld matched frames (RXMF)\n", can_stats.matches); 214 + seq_printf(m, " %8ld transmitted frames (TXF)\n", can_stats->tx_frames); 215 + seq_printf(m, " %8ld received frames (RXF)\n", can_stats->rx_frames); 216 + seq_printf(m, " %8ld matched frames (RXMF)\n", can_stats->matches); 217 217 218 218 seq_putc(m, '\n'); 219 219 220 - if (can_stattimer.function == can_stat_update) { 220 + if (net->can.can_stattimer.function == can_stat_update) { 221 221 seq_printf(m, " %8ld %% total match ratio (RXMR)\n", 222 - can_stats.total_rx_match_ratio); 222 + can_stats->total_rx_match_ratio); 223 223 224 224 seq_printf(m, " %8ld frames/s total tx rate (TXR)\n", 225 - can_stats.total_tx_rate); 225 + can_stats->total_tx_rate); 226 226 seq_printf(m, " %8ld frames/s total rx rate (RXR)\n", 227 - can_stats.total_rx_rate); 227 + can_stats->total_rx_rate); 228 228 229 229 seq_putc(m, '\n'); 230 230 231 231 seq_printf(m, " %8ld %% current match ratio (CRXMR)\n", 232 - can_stats.current_rx_match_ratio); 232 + can_stats->current_rx_match_ratio); 233 233 234 234 seq_printf(m, " %8ld frames/s current tx rate (CTXR)\n", 235 - can_stats.current_tx_rate); 235 + can_stats->current_tx_rate); 236 236 seq_printf(m, " %8ld frames/s current rx rate (CRXR)\n", 237 - can_stats.current_rx_rate); 237 + can_stats->current_rx_rate); 238 238 239 239 seq_putc(m, '\n'); 240 240 241 241 seq_printf(m, " %8ld %% max match ratio (MRXMR)\n", 242 - can_stats.max_rx_match_ratio); 242 + can_stats->max_rx_match_ratio); 243 243 244 244 seq_printf(m, " %8ld frames/s max tx rate (MTXR)\n", 245 - can_stats.max_tx_rate); 245 + can_stats->max_tx_rate); 246 246 seq_printf(m, " %8ld frames/s max rx rate (MRXR)\n", 247 - can_stats.max_rx_rate); 247 + can_stats->max_rx_rate); 248 248 249 249 seq_putc(m, '\n'); 250 250 } 251 251 252 252 seq_printf(m, " %8ld current receive list entries (CRCV)\n", 253 - can_pstats.rcv_entries); 253 + can_pstats->rcv_entries); 254 254 seq_printf(m, " %8ld maximum receive list entries (MRCV)\n", 255 - can_pstats.rcv_entries_max); 255 + can_pstats->rcv_entries_max); 256 256 257 - if (can_pstats.stats_reset) 257 + if (can_pstats->stats_reset) 258 258 seq_printf(m, "\n %8ld statistic resets (STR)\n", 259 - can_pstats.stats_reset); 259 + can_pstats->stats_reset); 260 260 261 - if (can_pstats.user_reset) 261 + if (can_pstats->user_reset) 262 262 seq_printf(m, " %8ld user statistic resets (USTR)\n", 263 - can_pstats.user_reset); 263 + can_pstats->user_reset); 264 264 265 265 seq_putc(m, '\n'); 266 266 return 0; ··· 272 264 273 265 static int can_stats_proc_open(struct inode *inode, struct file *file) 274 266 { 275 - return single_open(file, can_stats_proc_show, NULL); 267 + return single_open_net(inode, file, can_stats_proc_show); 276 268 } 277 269 278 270 static const struct file_operations can_stats_proc_fops = { ··· 285 277 286 278 static int can_reset_stats_proc_show(struct seq_file *m, void *v) 287 279 { 280 + struct net *net = m->private; 281 + struct s_pstats *can_pstats = net->can.can_pstats; 282 + struct s_stats *can_stats = net->can.can_stats; 283 + 288 284 user_reset = 1; 289 285 290 - if (can_stattimer.function == can_stat_update) { 286 + if (net->can.can_stattimer.function == can_stat_update) { 291 287 seq_printf(m, "Scheduled statistic reset #%ld.\n", 292 - can_pstats.stats_reset + 1); 293 - 288 + can_pstats->stats_reset + 1); 294 289 } else { 295 - if (can_stats.jiffies_init != jiffies) 296 - can_init_stats(); 290 + if (can_stats->jiffies_init != jiffies) 291 + can_init_stats(net); 297 292 298 293 seq_printf(m, "Performed statistic reset #%ld.\n", 299 - can_pstats.stats_reset); 294 + can_pstats->stats_reset); 300 295 } 301 296 return 0; 302 297 } 303 298 304 299 static int can_reset_stats_proc_open(struct inode *inode, struct file *file) 305 300 { 306 - return single_open(file, can_reset_stats_proc_show, NULL); 301 + return single_open_net(inode, file, can_reset_stats_proc_show); 307 302 } 308 303 309 304 static const struct file_operations can_reset_stats_proc_fops = { ··· 325 314 326 315 static int can_version_proc_open(struct inode *inode, struct file *file) 327 316 { 328 - return single_open(file, can_version_proc_show, NULL); 317 + return single_open_net(inode, file, can_version_proc_show); 329 318 } 330 319 331 320 static const struct file_operations can_version_proc_fops = {