58
58
#include <linux/can/skb.h>
59
59
#include <linux/can/bcm.h>
60
60
#include <linux/slab.h>
61
+ #include <linux/spinlock.h>
61
62
#include <net/sock.h>
62
63
#include <net/net_namespace.h>
63
64
@@ -122,6 +123,7 @@ struct bcm_op {
122
123
struct canfd_frame last_sframe ;
123
124
struct sock * sk ;
124
125
struct net_device * rx_reg_dev ;
126
+ spinlock_t bcm_tx_lock ; /* protect currframe/count in runtime updates */
125
127
};
126
128
127
129
struct bcm_sock {
@@ -217,7 +219,9 @@ static int bcm_proc_show(struct seq_file *m, void *v)
217
219
seq_printf (m , " / bound %s" , bcm_proc_getifname (net , ifname , bo -> ifindex ));
218
220
seq_printf (m , " <<<\n" );
219
221
220
- list_for_each_entry (op , & bo -> rx_ops , list ) {
222
+ rcu_read_lock ();
223
+
224
+ list_for_each_entry_rcu (op , & bo -> rx_ops , list ) {
221
225
222
226
unsigned long reduction ;
223
227
@@ -273,6 +277,9 @@ static int bcm_proc_show(struct seq_file *m, void *v)
273
277
seq_printf (m , "# sent %ld\n" , op -> frames_abs );
274
278
}
275
279
seq_putc (m , '\n' );
280
+
281
+ rcu_read_unlock ();
282
+
276
283
return 0 ;
277
284
}
278
285
#endif /* CONFIG_PROC_FS */
@@ -285,13 +292,18 @@ static void bcm_can_tx(struct bcm_op *op)
285
292
{
286
293
struct sk_buff * skb ;
287
294
struct net_device * dev ;
288
- struct canfd_frame * cf = op -> frames + op -> cfsiz * op -> currframe ;
295
+ struct canfd_frame * cf ;
289
296
int err ;
290
297
291
298
/* no target device? => exit */
292
299
if (!op -> ifindex )
293
300
return ;
294
301
302
+ /* read currframe under lock protection */
303
+ spin_lock_bh (& op -> bcm_tx_lock );
304
+ cf = op -> frames + op -> cfsiz * op -> currframe ;
305
+ spin_unlock_bh (& op -> bcm_tx_lock );
306
+
295
307
dev = dev_get_by_index (sock_net (op -> sk ), op -> ifindex );
296
308
if (!dev ) {
297
309
/* RFC: should this bcm_op remove itself here? */
@@ -312,6 +324,10 @@ static void bcm_can_tx(struct bcm_op *op)
312
324
skb -> dev = dev ;
313
325
can_skb_set_owner (skb , op -> sk );
314
326
err = can_send (skb , 1 );
327
+
328
+ /* update currframe and count under lock protection */
329
+ spin_lock_bh (& op -> bcm_tx_lock );
330
+
315
331
if (!err )
316
332
op -> frames_abs ++ ;
317
333
@@ -320,6 +336,11 @@ static void bcm_can_tx(struct bcm_op *op)
320
336
/* reached last frame? */
321
337
if (op -> currframe >= op -> nframes )
322
338
op -> currframe = 0 ;
339
+
340
+ if (op -> count > 0 )
341
+ op -> count -- ;
342
+
343
+ spin_unlock_bh (& op -> bcm_tx_lock );
323
344
out :
324
345
dev_put (dev );
325
346
}
@@ -430,7 +451,7 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
430
451
struct bcm_msg_head msg_head ;
431
452
432
453
if (op -> kt_ival1 && (op -> count > 0 )) {
433
- op -> count -- ;
454
+ bcm_can_tx ( op ) ;
434
455
if (!op -> count && (op -> flags & TX_COUNTEVT )) {
435
456
436
457
/* create notification to user */
@@ -445,7 +466,6 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
445
466
446
467
bcm_send_to_user (op , & msg_head , NULL , 0 );
447
468
}
448
- bcm_can_tx (op );
449
469
450
470
} else if (op -> kt_ival2 ) {
451
471
bcm_can_tx (op );
@@ -843,7 +863,7 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
843
863
REGMASK (op -> can_id ),
844
864
bcm_rx_handler , op );
845
865
846
- list_del (& op -> list );
866
+ list_del_rcu (& op -> list );
847
867
bcm_remove_op (op );
848
868
return 1 ; /* done */
849
869
}
@@ -863,7 +883,7 @@ static int bcm_delete_tx_op(struct list_head *ops, struct bcm_msg_head *mh,
863
883
list_for_each_entry_safe (op , n , ops , list ) {
864
884
if ((op -> can_id == mh -> can_id ) && (op -> ifindex == ifindex ) &&
865
885
(op -> flags & CAN_FD_FRAME ) == (mh -> flags & CAN_FD_FRAME )) {
866
- list_del (& op -> list );
886
+ list_del_rcu (& op -> list );
867
887
bcm_remove_op (op );
868
888
return 1 ; /* done */
869
889
}
@@ -956,16 +976,42 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
956
976
}
957
977
op -> flags = msg_head -> flags ;
958
978
979
+ /* only lock for unlikely count/nframes/currframe changes */
980
+ if (op -> nframes != msg_head -> nframes ||
981
+ op -> flags & TX_RESET_MULTI_IDX ||
982
+ op -> flags & SETTIMER ) {
983
+
984
+ spin_lock_bh (& op -> bcm_tx_lock );
985
+
986
+ if (op -> nframes != msg_head -> nframes ||
987
+ op -> flags & TX_RESET_MULTI_IDX ) {
988
+ /* potentially update changed nframes */
989
+ op -> nframes = msg_head -> nframes ;
990
+ /* restart multiple frame transmission */
991
+ op -> currframe = 0 ;
992
+ }
993
+
994
+ if (op -> flags & SETTIMER )
995
+ op -> count = msg_head -> count ;
996
+
997
+ spin_unlock_bh (& op -> bcm_tx_lock );
998
+ }
999
+
959
1000
} else {
960
1001
/* insert new BCM operation for the given can_id */
961
1002
962
1003
op = kzalloc (OPSIZ , GFP_KERNEL );
963
1004
if (!op )
964
1005
return - ENOMEM ;
965
1006
1007
+ spin_lock_init (& op -> bcm_tx_lock );
966
1008
op -> can_id = msg_head -> can_id ;
967
1009
op -> cfsiz = CFSIZ (msg_head -> flags );
968
1010
op -> flags = msg_head -> flags ;
1011
+ op -> nframes = msg_head -> nframes ;
1012
+
1013
+ if (op -> flags & SETTIMER )
1014
+ op -> count = msg_head -> count ;
969
1015
970
1016
/* create array for CAN frames and copy the data */
971
1017
if (msg_head -> nframes > 1 ) {
@@ -1023,22 +1069,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
1023
1069
1024
1070
} /* if ((op = bcm_find_op(&bo->tx_ops, msg_head->can_id, ifindex))) */
1025
1071
1026
- if (op -> nframes != msg_head -> nframes ) {
1027
- op -> nframes = msg_head -> nframes ;
1028
- /* start multiple frame transmission with index 0 */
1029
- op -> currframe = 0 ;
1030
- }
1031
-
1032
- /* check flags */
1033
-
1034
- if (op -> flags & TX_RESET_MULTI_IDX ) {
1035
- /* start multiple frame transmission with index 0 */
1036
- op -> currframe = 0 ;
1037
- }
1038
-
1039
1072
if (op -> flags & SETTIMER ) {
1040
1073
/* set timer values */
1041
- op -> count = msg_head -> count ;
1042
1074
op -> ival1 = msg_head -> ival1 ;
1043
1075
op -> ival2 = msg_head -> ival2 ;
1044
1076
op -> kt_ival1 = bcm_timeval_to_ktime (msg_head -> ival1 );
@@ -1055,11 +1087,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
1055
1087
op -> flags |= TX_ANNOUNCE ;
1056
1088
}
1057
1089
1058
- if (op -> flags & TX_ANNOUNCE ) {
1090
+ if (op -> flags & TX_ANNOUNCE )
1059
1091
bcm_can_tx (op );
1060
- if (op -> count )
1061
- op -> count -- ;
1062
- }
1063
1092
1064
1093
if (op -> flags & STARTTIMER )
1065
1094
bcm_tx_start_timer (op );
@@ -1272,7 +1301,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
1272
1301
bcm_rx_handler , op , "bcm" , sk );
1273
1302
if (err ) {
1274
1303
/* this bcm rx op is broken -> remove it */
1275
- list_del (& op -> list );
1304
+ list_del_rcu (& op -> list );
1276
1305
bcm_remove_op (op );
1277
1306
return err ;
1278
1307
}
0 commit comments