mirror of
https://github.com/torvalds/linux.git
synced 2026-06-04 12:35:52 +02:00
bonding: 3ad: implement proper RCU rules for port->aggregator
syzbot found a data-race in bond_3ad_get_active_agg_info /
bond_3ad_state_machine_handler [1] which hints at lack of proper
RCU implementation.
Add __rcu qualifier to port->aggregator, and add proper RCU API.
[1]
BUG: KCSAN: data-race in bond_3ad_get_active_agg_info / bond_3ad_state_machine_handler
write to 0xffff88813cf5c4b0 of 8 bytes by task 36 on cpu 0:
ad_port_selection_logic drivers/net/bonding/bond_3ad.c:1659 [inline]
bond_3ad_state_machine_handler+0x9d5/0x2d60 drivers/net/bonding/bond_3ad.c:2569
process_one_work kernel/workqueue.c:3302 [inline]
process_scheduled_works+0x4f0/0x9c0 kernel/workqueue.c:3385
worker_thread+0x58a/0x780 kernel/workqueue.c:3466
kthread+0x22a/0x280 kernel/kthread.c:436
ret_from_fork+0x146/0x330 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
read to 0xffff88813cf5c4b0 of 8 bytes by task 22063 on cpu 1:
__bond_3ad_get_active_agg_info drivers/net/bonding/bond_3ad.c:2858 [inline]
bond_3ad_get_active_agg_info+0x8c/0x230 drivers/net/bonding/bond_3ad.c:2881
bond_fill_info+0xe0f/0x10f0 drivers/net/bonding/bond_netlink.c:853
rtnl_link_info_fill net/core/rtnetlink.c:906 [inline]
rtnl_link_fill+0x1d7/0x4e0 net/core/rtnetlink.c:927
rtnl_fill_ifinfo+0xf8e/0x1380 net/core/rtnetlink.c:2168
rtmsg_ifinfo_build_skb+0x11c/0x1b0 net/core/rtnetlink.c:4453
rtmsg_ifinfo_event net/core/rtnetlink.c:4486 [inline]
rtmsg_ifinfo+0x6d/0x110 net/core/rtnetlink.c:4495
__dev_notify_flags+0x76/0x390 net/core/dev.c:9790
netif_change_flags+0xac/0xd0 net/core/dev.c:9823
do_setlink+0x905/0x2950 net/core/rtnetlink.c:3180
rtnl_group_changelink net/core/rtnetlink.c:3813 [inline]
__rtnl_newlink net/core/rtnetlink.c:3981 [inline]
rtnl_newlink+0xf55/0x1400 net/core/rtnetlink.c:4109
rtnetlink_rcv_msg+0x64b/0x720 net/core/rtnetlink.c:6995
netlink_rcv_skb+0x123/0x220 net/netlink/af_netlink.c:2550
rtnetlink_rcv+0x1c/0x30 net/core/rtnetlink.c:7022
netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
netlink_unicast+0x5a8/0x680 net/netlink/af_netlink.c:1344
netlink_sendmsg+0x5c8/0x6f0 net/netlink/af_netlink.c:1894
sock_sendmsg_nosec net/socket.c:787 [inline]
__sock_sendmsg net/socket.c:802 [inline]
____sys_sendmsg+0x563/0x5b0 net/socket.c:2698
___sys_sendmsg+0x195/0x1e0 net/socket.c:2752
__sys_sendmsg net/socket.c:2784 [inline]
__do_sys_sendmsg net/socket.c:2789 [inline]
__se_sys_sendmsg net/socket.c:2787 [inline]
__x64_sys_sendmsg+0xd4/0x160 net/socket.c:2787
x64_sys_call+0x194c/0x3020 arch/x86/include/generated/asm/syscalls_64.h:47
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x12c/0x3b0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
value changed: 0x0000000000000000 -> 0xffff88813cf5c400
Reported by Kernel Concurrency Sanitizer on:
CPU: 1 UID: 0 PID: 22063 Comm: syz.0.31122 Tainted: G W syzkaller #0 PREEMPT(full)
Tainted: [W]=WARN
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026
Fixes: 47e91f5600 ("bonding: use RCU protection for 3ad xmit path")
Reported-by: syzbot+9bb2ff2a4ab9e17307e1@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/69f0a82f.050a0220.3aadc4.0000.GAE@google.com/
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Jay Vosburgh <jv@jvosburgh.net>
Cc: Andrew Lunn <andrew+netdev@lunn.ch>
Link: https://patch.msgid.link/20260428123207.3809211-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
4ca01292ea
commit
c4f050ce06
|
|
@ -1029,6 +1029,7 @@ static void ad_cond_set_peer_notif(struct port *port)
|
|||
static void ad_mux_machine(struct port *port, bool *update_slave_arr)
|
||||
{
|
||||
struct bonding *bond = __get_bond_by_port(port);
|
||||
struct aggregator *aggregator;
|
||||
mux_states_t last_state;
|
||||
|
||||
/* keep current State Machine state to compare later if it was
|
||||
|
|
@ -1036,6 +1037,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
|
|||
*/
|
||||
last_state = port->sm_mux_state;
|
||||
|
||||
aggregator = rcu_dereference(port->aggregator);
|
||||
if (port->sm_vars & AD_PORT_BEGIN) {
|
||||
port->sm_mux_state = AD_MUX_DETACHED;
|
||||
} else {
|
||||
|
|
@ -1055,7 +1057,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
|
|||
* cycle to update ready variable, we check
|
||||
* READY_N and update READY here
|
||||
*/
|
||||
__set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
|
||||
__set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator));
|
||||
port->sm_mux_state = AD_MUX_DETACHED;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1070,7 +1072,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
|
|||
* update ready variable, we check READY_N and update
|
||||
* READY here
|
||||
*/
|
||||
__set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
|
||||
__set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator));
|
||||
|
||||
/* if the wait_while_timer expired, and the port is
|
||||
* in READY state, move to ATTACHED state
|
||||
|
|
@ -1086,7 +1088,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
|
|||
if ((port->sm_vars & AD_PORT_SELECTED) &&
|
||||
(port->partner_oper.port_state & LACP_STATE_SYNCHRONIZATION) &&
|
||||
!__check_agg_selection_timer(port)) {
|
||||
if (port->aggregator->is_active) {
|
||||
if (aggregator->is_active) {
|
||||
int state = AD_MUX_COLLECTING_DISTRIBUTING;
|
||||
|
||||
if (!bond->params.coupled_control)
|
||||
|
|
@ -1102,9 +1104,9 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
|
|||
* cycle to update ready variable, we check
|
||||
* READY_N and update READY here
|
||||
*/
|
||||
__set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
|
||||
__set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator));
|
||||
port->sm_mux_state = AD_MUX_DETACHED;
|
||||
} else if (port->aggregator->is_active) {
|
||||
} else if (aggregator->is_active) {
|
||||
port->actor_oper_port_state |=
|
||||
LACP_STATE_SYNCHRONIZATION;
|
||||
}
|
||||
|
|
@ -1115,7 +1117,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
|
|||
* sure that a collecting distributing
|
||||
* port in an active aggregator is enabled
|
||||
*/
|
||||
if (port->aggregator->is_active &&
|
||||
if (aggregator->is_active &&
|
||||
!__port_is_collecting_distributing(port)) {
|
||||
__enable_port(port);
|
||||
*update_slave_arr = true;
|
||||
|
|
@ -1134,7 +1136,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
|
|||
*/
|
||||
struct slave *slave = port->slave;
|
||||
|
||||
if (port->aggregator->is_active &&
|
||||
if (aggregator->is_active &&
|
||||
bond_is_slave_rx_disabled(slave)) {
|
||||
ad_enable_collecting(port);
|
||||
*update_slave_arr = true;
|
||||
|
|
@ -1154,8 +1156,8 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
|
|||
* sure that a collecting distributing
|
||||
* port in an active aggregator is enabled
|
||||
*/
|
||||
if (port->aggregator &&
|
||||
port->aggregator->is_active &&
|
||||
if (aggregator &&
|
||||
aggregator->is_active &&
|
||||
!__port_is_collecting_distributing(port)) {
|
||||
__enable_port(port);
|
||||
*update_slave_arr = true;
|
||||
|
|
@ -1187,7 +1189,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
|
|||
port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0);
|
||||
break;
|
||||
case AD_MUX_ATTACHED:
|
||||
if (port->aggregator->is_active)
|
||||
if (aggregator->is_active)
|
||||
port->actor_oper_port_state |=
|
||||
LACP_STATE_SYNCHRONIZATION;
|
||||
else
|
||||
|
|
@ -1561,9 +1563,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
|
|||
bond = __get_bond_by_port(port);
|
||||
|
||||
/* if the port is connected to other aggregator, detach it */
|
||||
if (port->aggregator) {
|
||||
temp_aggregator = rcu_dereference(port->aggregator);
|
||||
if (temp_aggregator) {
|
||||
/* detach the port from its former aggregator */
|
||||
temp_aggregator = port->aggregator;
|
||||
for (curr_port = temp_aggregator->lag_ports; curr_port;
|
||||
last_port = curr_port,
|
||||
curr_port = curr_port->next_port_in_aggregator) {
|
||||
|
|
@ -1586,7 +1588,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
|
|||
/* clear the port's relations to this
|
||||
* aggregator
|
||||
*/
|
||||
port->aggregator = NULL;
|
||||
RCU_INIT_POINTER(port->aggregator, NULL);
|
||||
port->next_port_in_aggregator = NULL;
|
||||
port->actor_port_aggregator_identifier = 0;
|
||||
|
||||
|
|
@ -1609,7 +1611,7 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
|
|||
port->slave->bond->dev->name,
|
||||
port->slave->dev->name,
|
||||
port->actor_port_number,
|
||||
port->aggregator->aggregator_identifier);
|
||||
temp_aggregator->aggregator_identifier);
|
||||
}
|
||||
}
|
||||
/* search on all aggregators for a suitable aggregator for this port */
|
||||
|
|
@ -1633,15 +1635,15 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
|
|||
)
|
||||
) {
|
||||
/* attach to the founded aggregator */
|
||||
port->aggregator = aggregator;
|
||||
rcu_assign_pointer(port->aggregator, aggregator);
|
||||
port->actor_port_aggregator_identifier =
|
||||
port->aggregator->aggregator_identifier;
|
||||
aggregator->aggregator_identifier;
|
||||
port->next_port_in_aggregator = aggregator->lag_ports;
|
||||
port->aggregator->num_of_ports++;
|
||||
aggregator->num_of_ports++;
|
||||
aggregator->lag_ports = port;
|
||||
slave_dbg(bond->dev, slave->dev, "Port %d joined LAG %d (existing LAG)\n",
|
||||
port->actor_port_number,
|
||||
port->aggregator->aggregator_identifier);
|
||||
aggregator->aggregator_identifier);
|
||||
|
||||
/* mark this port as selected */
|
||||
port->sm_vars |= AD_PORT_SELECTED;
|
||||
|
|
@ -1656,39 +1658,40 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
|
|||
if (!found) {
|
||||
if (free_aggregator) {
|
||||
/* assign port a new aggregator */
|
||||
port->aggregator = free_aggregator;
|
||||
port->actor_port_aggregator_identifier =
|
||||
port->aggregator->aggregator_identifier;
|
||||
free_aggregator->aggregator_identifier;
|
||||
|
||||
/* update the new aggregator's parameters
|
||||
* if port was responsed from the end-user
|
||||
*/
|
||||
if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS)
|
||||
/* if port is full duplex */
|
||||
port->aggregator->is_individual = false;
|
||||
free_aggregator->is_individual = false;
|
||||
else
|
||||
port->aggregator->is_individual = true;
|
||||
free_aggregator->is_individual = true;
|
||||
|
||||
port->aggregator->actor_admin_aggregator_key =
|
||||
free_aggregator->actor_admin_aggregator_key =
|
||||
port->actor_admin_port_key;
|
||||
port->aggregator->actor_oper_aggregator_key =
|
||||
free_aggregator->actor_oper_aggregator_key =
|
||||
port->actor_oper_port_key;
|
||||
port->aggregator->partner_system =
|
||||
free_aggregator->partner_system =
|
||||
port->partner_oper.system;
|
||||
port->aggregator->partner_system_priority =
|
||||
free_aggregator->partner_system_priority =
|
||||
port->partner_oper.system_priority;
|
||||
port->aggregator->partner_oper_aggregator_key = port->partner_oper.key;
|
||||
port->aggregator->receive_state = 1;
|
||||
port->aggregator->transmit_state = 1;
|
||||
port->aggregator->lag_ports = port;
|
||||
port->aggregator->num_of_ports++;
|
||||
free_aggregator->partner_oper_aggregator_key = port->partner_oper.key;
|
||||
free_aggregator->receive_state = 1;
|
||||
free_aggregator->transmit_state = 1;
|
||||
free_aggregator->lag_ports = port;
|
||||
free_aggregator->num_of_ports++;
|
||||
|
||||
rcu_assign_pointer(port->aggregator, free_aggregator);
|
||||
|
||||
/* mark this port as selected */
|
||||
port->sm_vars |= AD_PORT_SELECTED;
|
||||
|
||||
slave_dbg(bond->dev, port->slave->dev, "Port %d joined LAG %d (new LAG)\n",
|
||||
port->actor_port_number,
|
||||
port->aggregator->aggregator_identifier);
|
||||
free_aggregator->aggregator_identifier);
|
||||
} else {
|
||||
slave_err(bond->dev, port->slave->dev,
|
||||
"Port %d did not find a suitable aggregator\n",
|
||||
|
|
@ -1700,13 +1703,12 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
|
|||
* in all aggregator's ports, else set ready=FALSE in all
|
||||
* aggregator's ports
|
||||
*/
|
||||
__set_agg_ports_ready(port->aggregator,
|
||||
__agg_ports_are_ready(port->aggregator));
|
||||
aggregator = rcu_dereference(port->aggregator);
|
||||
__set_agg_ports_ready(aggregator, __agg_ports_are_ready(aggregator));
|
||||
|
||||
aggregator = __get_first_agg(port);
|
||||
ad_agg_selection_logic(aggregator, update_slave_arr);
|
||||
ad_agg_selection_logic(__get_first_agg(port), update_slave_arr);
|
||||
|
||||
if (!port->aggregator->is_active)
|
||||
if (!aggregator->is_active)
|
||||
port->actor_oper_port_state &= ~LACP_STATE_SYNCHRONIZATION;
|
||||
}
|
||||
|
||||
|
|
@ -2075,13 +2077,15 @@ static void ad_initialize_port(struct port *port, const struct bond_params *bond
|
|||
*/
|
||||
static void ad_enable_collecting(struct port *port)
|
||||
{
|
||||
if (port->aggregator->is_active) {
|
||||
struct aggregator *aggregator = rcu_dereference(port->aggregator);
|
||||
|
||||
if (aggregator->is_active) {
|
||||
struct slave *slave = port->slave;
|
||||
|
||||
slave_dbg(slave->bond->dev, slave->dev,
|
||||
"Enabling collecting on port %d (LAG %d)\n",
|
||||
port->actor_port_number,
|
||||
port->aggregator->aggregator_identifier);
|
||||
aggregator->aggregator_identifier);
|
||||
__enable_collecting_port(port);
|
||||
}
|
||||
}
|
||||
|
|
@ -2093,11 +2097,13 @@ static void ad_enable_collecting(struct port *port)
|
|||
*/
|
||||
static void ad_disable_distributing(struct port *port, bool *update_slave_arr)
|
||||
{
|
||||
if (port->aggregator && __agg_has_partner(port->aggregator)) {
|
||||
struct aggregator *aggregator = rcu_dereference(port->aggregator);
|
||||
|
||||
if (aggregator && __agg_has_partner(aggregator)) {
|
||||
slave_dbg(port->slave->bond->dev, port->slave->dev,
|
||||
"Disabling distributing on port %d (LAG %d)\n",
|
||||
port->actor_port_number,
|
||||
port->aggregator->aggregator_identifier);
|
||||
aggregator->aggregator_identifier);
|
||||
__disable_distributing_port(port);
|
||||
/* Slave array needs an update */
|
||||
*update_slave_arr = true;
|
||||
|
|
@ -2114,11 +2120,13 @@ static void ad_disable_distributing(struct port *port, bool *update_slave_arr)
|
|||
static void ad_enable_collecting_distributing(struct port *port,
|
||||
bool *update_slave_arr)
|
||||
{
|
||||
if (port->aggregator->is_active) {
|
||||
struct aggregator *aggregator = rcu_dereference(port->aggregator);
|
||||
|
||||
if (aggregator->is_active) {
|
||||
slave_dbg(port->slave->bond->dev, port->slave->dev,
|
||||
"Enabling port %d (LAG %d)\n",
|
||||
port->actor_port_number,
|
||||
port->aggregator->aggregator_identifier);
|
||||
aggregator->aggregator_identifier);
|
||||
__enable_port(port);
|
||||
/* Slave array needs update */
|
||||
*update_slave_arr = true;
|
||||
|
|
@ -2135,11 +2143,13 @@ static void ad_enable_collecting_distributing(struct port *port,
|
|||
static void ad_disable_collecting_distributing(struct port *port,
|
||||
bool *update_slave_arr)
|
||||
{
|
||||
if (port->aggregator && __agg_has_partner(port->aggregator)) {
|
||||
struct aggregator *aggregator = rcu_dereference(port->aggregator);
|
||||
|
||||
if (aggregator && __agg_has_partner(aggregator)) {
|
||||
slave_dbg(port->slave->bond->dev, port->slave->dev,
|
||||
"Disabling port %d (LAG %d)\n",
|
||||
port->actor_port_number,
|
||||
port->aggregator->aggregator_identifier);
|
||||
aggregator->aggregator_identifier);
|
||||
__disable_port(port);
|
||||
/* Slave array needs an update */
|
||||
*update_slave_arr = true;
|
||||
|
|
@ -2379,7 +2389,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
|
|||
*/
|
||||
for (temp_port = aggregator->lag_ports; temp_port;
|
||||
temp_port = temp_port->next_port_in_aggregator) {
|
||||
temp_port->aggregator = new_aggregator;
|
||||
rcu_assign_pointer(temp_port->aggregator, new_aggregator);
|
||||
temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier;
|
||||
}
|
||||
|
||||
|
|
@ -2848,15 +2858,16 @@ int bond_3ad_set_carrier(struct bonding *bond)
|
|||
int __bond_3ad_get_active_agg_info(struct bonding *bond,
|
||||
struct ad_info *ad_info)
|
||||
{
|
||||
struct aggregator *aggregator = NULL;
|
||||
struct aggregator *aggregator = NULL, *tmp;
|
||||
struct list_head *iter;
|
||||
struct slave *slave;
|
||||
struct port *port;
|
||||
|
||||
bond_for_each_slave_rcu(bond, slave, iter) {
|
||||
port = &(SLAVE_AD_INFO(slave)->port);
|
||||
if (port->aggregator && port->aggregator->is_active) {
|
||||
aggregator = port->aggregator;
|
||||
tmp = rcu_dereference(port->aggregator);
|
||||
if (tmp && tmp->is_active) {
|
||||
aggregator = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1433,7 +1433,7 @@ static void bond_poll_controller(struct net_device *bond_dev)
|
|||
|
||||
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
|
||||
struct aggregator *agg =
|
||||
SLAVE_AD_INFO(slave)->port.aggregator;
|
||||
rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator);
|
||||
|
||||
if (agg &&
|
||||
agg->aggregator_identifier != ad_info.aggregator_id)
|
||||
|
|
@ -5179,15 +5179,16 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
|
|||
spin_unlock_bh(&bond->mode_lock);
|
||||
agg_id = ad_info.aggregator_id;
|
||||
}
|
||||
rcu_read_lock();
|
||||
bond_for_each_slave(bond, slave, iter) {
|
||||
if (skipslave == slave)
|
||||
continue;
|
||||
|
||||
all_slaves->arr[all_slaves->count++] = slave;
|
||||
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
|
||||
struct aggregator *agg;
|
||||
const struct aggregator *agg;
|
||||
|
||||
agg = SLAVE_AD_INFO(slave)->port.aggregator;
|
||||
agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator);
|
||||
if (!agg || agg->aggregator_identifier != agg_id)
|
||||
continue;
|
||||
}
|
||||
|
|
@ -5199,6 +5200,7 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
|
|||
|
||||
usable_slaves->arr[usable_slaves->count++] = slave;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
bond_set_slave_arr(bond, usable_slaves, all_slaves);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -66,27 +66,29 @@ static int bond_fill_slave_info(struct sk_buff *skb,
|
|||
const struct port *ad_port;
|
||||
|
||||
ad_port = &SLAVE_AD_INFO(slave)->port;
|
||||
agg = SLAVE_AD_INFO(slave)->port.aggregator;
|
||||
rcu_read_lock();
|
||||
agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator);
|
||||
if (agg) {
|
||||
if (nla_put_u16(skb, IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
|
||||
agg->aggregator_identifier))
|
||||
goto nla_put_failure;
|
||||
goto nla_put_failure_rcu;
|
||||
if (nla_put_u8(skb,
|
||||
IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
|
||||
ad_port->actor_oper_port_state))
|
||||
goto nla_put_failure;
|
||||
goto nla_put_failure_rcu;
|
||||
if (nla_put_u16(skb,
|
||||
IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
|
||||
ad_port->partner_oper.port_state))
|
||||
goto nla_put_failure;
|
||||
goto nla_put_failure_rcu;
|
||||
|
||||
if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE,
|
||||
ad_port->sm_churn_actor_state))
|
||||
goto nla_put_failure;
|
||||
goto nla_put_failure_rcu;
|
||||
if (nla_put_u8(skb, IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE,
|
||||
ad_port->sm_churn_partner_state))
|
||||
goto nla_put_failure;
|
||||
goto nla_put_failure_rcu;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (nla_put_u16(skb, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO,
|
||||
SLAVE_AD_INFO(slave)->port_priority))
|
||||
|
|
@ -95,6 +97,8 @@ static int bond_fill_slave_info(struct sk_buff *skb,
|
|||
|
||||
return 0;
|
||||
|
||||
nla_put_failure_rcu:
|
||||
rcu_read_unlock();
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ static void bond_info_show_master(struct seq_file *seq)
|
|||
}
|
||||
}
|
||||
|
||||
/* Note: runs under rcu_read_lock() */
|
||||
static void bond_info_show_slave(struct seq_file *seq,
|
||||
const struct slave *slave)
|
||||
{
|
||||
|
|
@ -214,7 +215,7 @@ static void bond_info_show_slave(struct seq_file *seq,
|
|||
|
||||
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
|
||||
const struct port *port = &SLAVE_AD_INFO(slave)->port;
|
||||
const struct aggregator *agg = port->aggregator;
|
||||
const struct aggregator *agg = rcu_dereference(port->aggregator);
|
||||
|
||||
if (agg) {
|
||||
seq_printf(seq, "Aggregator ID: %d\n",
|
||||
|
|
|
|||
|
|
@ -62,10 +62,15 @@ static ssize_t ad_aggregator_id_show(struct slave *slave, char *buf)
|
|||
const struct aggregator *agg;
|
||||
|
||||
if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
|
||||
agg = SLAVE_AD_INFO(slave)->port.aggregator;
|
||||
if (agg)
|
||||
return sysfs_emit(buf, "%d\n",
|
||||
agg->aggregator_identifier);
|
||||
rcu_read_lock();
|
||||
agg = rcu_dereference(SLAVE_AD_INFO(slave)->port.aggregator);
|
||||
if (agg) {
|
||||
ssize_t res = sysfs_emit(buf, "%d\n",
|
||||
agg->aggregator_identifier);
|
||||
rcu_read_unlock();
|
||||
return res;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
return sysfs_emit(buf, "N/A\n");
|
||||
|
|
@ -78,7 +83,7 @@ static ssize_t ad_actor_oper_port_state_show(struct slave *slave, char *buf)
|
|||
|
||||
if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
|
||||
ad_port = &SLAVE_AD_INFO(slave)->port;
|
||||
if (ad_port->aggregator)
|
||||
if (rcu_access_pointer(ad_port->aggregator))
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
ad_port->actor_oper_port_state);
|
||||
}
|
||||
|
|
@ -93,7 +98,7 @@ static ssize_t ad_partner_oper_port_state_show(struct slave *slave, char *buf)
|
|||
|
||||
if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
|
||||
ad_port = &SLAVE_AD_INFO(slave)->port;
|
||||
if (ad_port->aggregator)
|
||||
if (rcu_access_pointer(ad_port->aggregator))
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
ad_port->partner_oper.port_state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ typedef struct port {
|
|||
churn_state_t sm_churn_actor_state;
|
||||
churn_state_t sm_churn_partner_state;
|
||||
struct slave *slave; /* pointer to the bond slave that this port belongs to */
|
||||
struct aggregator *aggregator; /* pointer to an aggregator that this port related to */
|
||||
struct aggregator __rcu *aggregator; /* pointer to an aggregator that this port related to */
|
||||
struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */
|
||||
u32 transaction_id; /* continuous number for identification of Marker PDU's; */
|
||||
struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user