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

team: remove synchronize_rcu() called during port disable

Check the unlikely case of team->en_port_count == 0 before modulo
operation.

Signed-off-by: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jiri Pirko and committed by
David S. Miller
735d381f d80b35be

+18 -18
+5 -15
drivers/net/team/team.c
··· 525 525 team->mode = &__team_no_mode; 526 526 } 527 527 528 - static void __team_adjust_ops(struct team *team, int en_port_count) 528 + static void team_adjust_ops(struct team *team) 529 529 { 530 530 /* 531 531 * To avoid checks in rx/tx skb paths, ensure here that non-null and 532 532 * correct ops are always set. 533 533 */ 534 534 535 - if (!en_port_count || !team_is_mode_set(team) || 535 + if (!team->en_port_count || !team_is_mode_set(team) || 536 536 !team->mode->ops->transmit) 537 537 team->ops.transmit = team_dummy_transmit; 538 538 else 539 539 team->ops.transmit = team->mode->ops->transmit; 540 540 541 - if (!en_port_count || !team_is_mode_set(team) || 541 + if (!team->en_port_count || !team_is_mode_set(team) || 542 542 !team->mode->ops->receive) 543 543 team->ops.receive = team_dummy_receive; 544 544 else 545 545 team->ops.receive = team->mode->ops->receive; 546 - } 547 - 548 - static void team_adjust_ops(struct team *team) 549 - { 550 - __team_adjust_ops(team, team->en_port_count); 551 546 } 552 547 553 548 /* ··· 872 877 hlist_del_rcu(&port->hlist); 873 878 __reconstruct_port_hlist(team, port->index); 874 879 port->index = -1; 875 - team_queue_override_port_del(team, port); 876 - __team_adjust_ops(team, team->en_port_count - 1); 877 - /* 878 - * Wait until readers see adjusted ops. This ensures that 879 - * readers never see team->en_port_count == 0 880 - */ 881 - synchronize_rcu(); 882 880 team->en_port_count--; 881 + team_queue_override_port_del(team, port); 882 + team_adjust_ops(team); 883 883 } 884 884 885 885 #define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \
+1 -2
drivers/net/team/team_mode_loadbalance.c
··· 112 112 struct sk_buff *skb, 113 113 unsigned char hash) 114 114 { 115 - int port_index; 115 + int port_index = team_num_to_port_index(team, hash); 116 116 117 - port_index = hash % team->en_port_count; 118 117 return team_get_port_by_index_rcu(team, port_index); 119 118 } 120 119
+2 -1
drivers/net/team/team_mode_roundrobin.c
··· 30 30 struct team_port *port; 31 31 int port_index; 32 32 33 - port_index = rr_priv(team)->sent_packets++ % team->en_port_count; 33 + port_index = team_num_to_port_index(team, 34 + rr_priv(team)->sent_packets++); 34 35 port = team_get_port_by_index_rcu(team, port_index); 35 36 port = team_get_first_port_txable_rcu(team, port); 36 37 if (unlikely(!port))
+10
include/linux/if_team.h
··· 229 229 return port; 230 230 return NULL; 231 231 } 232 + 233 + static inline int team_num_to_port_index(struct team *team, int num) 234 + { 235 + int en_port_count = ACCESS_ONCE(team->en_port_count); 236 + 237 + if (unlikely(!en_port_count)) 238 + return 0; 239 + return num % en_port_count; 240 + } 241 + 232 242 static inline struct team_port *team_get_port_by_index_rcu(struct team *team, 233 243 int port_index) 234 244 {