br_timer_value() can be called locklessly, the expires field could be changed concurrently. Signed-off-by: Eric Dumazet Reviewed-by: Ido Schimmel Acked-by: Nikolay Aleksandrov --- net/bridge/br_stp_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c index e5d453305381baa34225a144ac99e98f2a62d810..83cc9c6a3943508eb94d20ddc1b7e737a58d7abb 100644 --- a/net/bridge/br_stp_timer.c +++ b/net/bridge/br_stp_timer.c @@ -160,5 +160,5 @@ void br_stp_port_timer_init(struct net_bridge_port *p) unsigned long br_timer_value(const struct timer_list *timer) { return timer_pending(timer) - ? jiffies_delta_to_clock_t(timer->expires - jiffies) : 0; + ? jiffies_delta_to_clock_t(READ_ONCE(timer->expires) - jiffies) : 0; } -- 2.54.0.1032.g2f8565e1d1-goog We want to use atomic operations for lockless p->flags changes and reads. Add definitions for bits in addition of masks so that we can use test_bit(), clear_bit() and set_bit() in subsequent patches. Signed-off-by: Eric Dumazet Reviewed-by: Ido Schimmel Acked-by: Nikolay Aleksandrov --- include/linux/if_bridge.h | 78 ++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index ec9ffea1e46ede3762f108f6e7085ebb1bf1d2e1..75673b8bffcb8ad6396e6a05b8af8150208fb6fe 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -36,32 +36,60 @@ struct br_ip_list { struct br_ip addr; }; -#define BR_HAIRPIN_MODE BIT(0) -#define BR_BPDU_GUARD BIT(1) -#define BR_ROOT_BLOCK BIT(2) -#define BR_MULTICAST_FAST_LEAVE BIT(3) -#define BR_ADMIN_COST BIT(4) -#define BR_LEARNING BIT(5) -#define BR_FLOOD BIT(6) +enum bridge_flags_bit { + BR_HAIRPIN_MODE_BIT, + BR_BPDU_GUARD_BIT, + BR_ROOT_BLOCK_BIT, + BR_MULTICAST_FAST_LEAVE_BIT, + BR_ADMIN_COST_BIT, + BR_LEARNING_BIT, + BR_FLOOD_BIT, + BR_PROMISC_BIT, + BR_PROXYARP_BIT, + BR_LEARNING_SYNC_BIT, + BR_PROXYARP_WIFI_BIT, + BR_MCAST_FLOOD_BIT, + BR_MULTICAST_TO_UNICAST_BIT, + BR_VLAN_TUNNEL_BIT, + BR_BCAST_FLOOD_BIT, + BR_NEIGH_SUPPRESS_BIT, + BR_ISOLATED_BIT, + BR_MRP_AWARE_BIT, + BR_MRP_LOST_CONT_BIT, + BR_MRP_LOST_IN_CONT_BIT, + BR_TX_FWD_OFFLOAD_BIT, + BR_PORT_LOCKED_BIT, + BR_PORT_MAB_BIT, + BR_NEIGH_VLAN_SUPPRESS_BIT, + BR_NEIGH_FORWARD_GRAT_BIT, +}; + +#define BR_HAIRPIN_MODE BIT(BR_HAIRPIN_MODE_BIT) +#define BR_BPDU_GUARD BIT(BR_BPDU_GUARD_BIT) +#define BR_ROOT_BLOCK BIT(BR_ROOT_BLOCK_BIT) +#define BR_MULTICAST_FAST_LEAVE BIT(BR_MULTICAST_FAST_LEAVE_BIT) +#define BR_ADMIN_COST BIT(BR_ADMIN_COST_BIT) +#define BR_LEARNING BIT(BR_LEARNING_BIT) +#define BR_FLOOD BIT(BR_FLOOD_BIT) #define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING) -#define BR_PROMISC BIT(7) -#define BR_PROXYARP BIT(8) -#define BR_LEARNING_SYNC BIT(9) -#define BR_PROXYARP_WIFI BIT(10) -#define BR_MCAST_FLOOD BIT(11) -#define BR_MULTICAST_TO_UNICAST BIT(12) -#define BR_VLAN_TUNNEL BIT(13) -#define BR_BCAST_FLOOD BIT(14) -#define BR_NEIGH_SUPPRESS BIT(15) -#define BR_ISOLATED BIT(16) -#define BR_MRP_AWARE BIT(17) -#define BR_MRP_LOST_CONT BIT(18) -#define BR_MRP_LOST_IN_CONT BIT(19) -#define BR_TX_FWD_OFFLOAD BIT(20) -#define BR_PORT_LOCKED BIT(21) -#define BR_PORT_MAB BIT(22) -#define BR_NEIGH_VLAN_SUPPRESS BIT(23) -#define BR_NEIGH_FORWARD_GRAT BIT(24) +#define BR_PROMISC BIT(BR_PROMISC_BIT) +#define BR_PROXYARP BIT(BR_PROXYARP_BIT) +#define BR_LEARNING_SYNC BIT(BR_LEARNING_SYNC_BIT) +#define BR_PROXYARP_WIFI BIT(BR_PROXYARP_WIFI_BIT) +#define BR_MCAST_FLOOD BIT(BR_MCAST_FLOOD_BIT) +#define BR_MULTICAST_TO_UNICAST BIT(BR_MULTICAST_TO_UNICAST_BIT) +#define BR_VLAN_TUNNEL BIT(BR_VLAN_TUNNEL_BIT) +#define BR_BCAST_FLOOD BIT(BR_BCAST_FLOOD_BIT) +#define BR_NEIGH_SUPPRESS BIT(BR_NEIGH_SUPPRESS_BIT) +#define BR_ISOLATED BIT(BR_ISOLATED_BIT) +#define BR_MRP_AWARE BIT(BR_MRP_AWARE_BIT) +#define BR_MRP_LOST_CONT BIT(BR_MRP_LOST_CONT_BIT) +#define BR_MRP_LOST_IN_CONT BIT(BR_MRP_LOST_IN_CONT_BIT) +#define BR_TX_FWD_OFFLOAD BIT(BR_TX_FWD_OFFLOAD_BIT) +#define BR_PORT_LOCKED BIT(BR_PORT_LOCKED_BIT) +#define BR_PORT_MAB BIT(BR_PORT_MAB_BIT) +#define BR_NEIGH_VLAN_SUPPRESS BIT(BR_NEIGH_VLAN_SUPPRESS_BIT) +#define BR_NEIGH_FORWARD_GRAT BIT(BR_NEIGH_FORWARD_GRAT_BIT) #define BR_DEFAULT_AGEING_TIME (300 * HZ) -- 2.54.0.1032.g2f8565e1d1-goog Use BR_PROMISC_BIT and set_bit(), clear_bit() and test_bit() lockless functions. Signed-off-by: Eric Dumazet Reviewed-by: Ido Schimmel Acked-by: Nikolay Aleksandrov --- net/bridge/br_if.c | 4 ++-- net/bridge/br_private.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index d39571e13744431f5e4c67f34ee7de34eb8bb6b0..3169fab686a534cf2a6458ff228eee2b6fc7e7e4 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -110,7 +110,7 @@ static void br_port_set_promisc(struct net_bridge_port *p) return; br_fdb_unsync_static(p->br, p); - p->flags |= BR_PROMISC; + set_bit(BR_PROMISC_BIT, &p->flags); } static void br_port_clear_promisc(struct net_bridge_port *p) @@ -133,7 +133,7 @@ static void br_port_clear_promisc(struct net_bridge_port *p) return; dev_set_promiscuity(p->dev, -1); - p->flags &= ~BR_PROMISC; + clear_bit(BR_PROMISC_BIT, &p->flags); } /* When a port is added or removed or when certain port flags diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 02671e648dac7ab6fd59b80e044f62b00a8e4a8a..d55ea9516e3e369bb9e0045fca5b8d034ef5a45f 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -452,7 +452,7 @@ struct net_bridge_port { #define kobj_to_brport(obj) container_of(obj, struct net_bridge_port, kobj) #define br_auto_port(p) ((p)->flags & BR_AUTO_MASK) -#define br_promisc_port(p) ((p)->flags & BR_PROMISC) +#define br_promisc_port(p) test_bit(BR_PROMISC_BIT, &(p)->flags) static inline struct net_bridge_port *br_port_get_rcu(const struct net_device *dev) { -- 2.54.0.1032.g2f8565e1d1-goog Use set_bit() and test_bit() lockless functions. Signed-off-by: Eric Dumazet Reviewed-by: Ido Schimmel Acked-by: Nikolay Aleksandrov --- net/bridge/br_if.c | 2 +- net/bridge/br_stp_if.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 3169fab686a534cf2a6458ff228eee2b6fc7e7e4..0bd5cf925fa321b785e3578d6e99d8d7003fa89f 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -75,7 +75,7 @@ void br_port_carrier_check(struct net_bridge_port *p, bool *notified) struct net_device *dev = p->dev; struct net_bridge *br = p->br; - if (!(p->flags & BR_ADMIN_COST) && + if (!test_bit(BR_ADMIN_COST_BIT, &p->flags) && netif_running(dev) && netif_oper_up(dev)) p->path_cost = port_cost(dev); diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 28c1d3f7e22f6e0a0edd8b3b3f501ea7acc31394..b29dc97b9ad8a5b5c56517d34fe426abd00e2ad6 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -340,7 +340,7 @@ int br_stp_set_path_cost(struct net_bridge_port *p, unsigned long path_cost) path_cost > BR_MAX_PATH_COST) return -ERANGE; - p->flags |= BR_ADMIN_COST; + set_bit(BR_ADMIN_COST_BIT, &p->flags); p->path_cost = path_cost; br_configuration_update(p->br); br_port_state_selection(p->br); -- 2.54.0.1032.g2f8565e1d1-goog Add READ_ONCE()/WRITE_ONCE() annotations around p->path_cost. This is needed at least for sysfs show_path_cost(), BRCTL_GET_PORT_INFO and upcoming RTNL avoidance in "ip link" dumps (cf br_port_fill_attrs()). Signed-off-by: Eric Dumazet Acked-by: Nikolay Aleksandrov Reviewed-by: Ido Schimmel --- net/bridge/br_if.c | 2 +- net/bridge/br_ioctl.c | 2 +- net/bridge/br_netlink.c | 2 +- net/bridge/br_stp.c | 17 +++++++++++------ net/bridge/br_stp_if.c | 2 +- net/bridge/br_sysfs_if.c | 2 +- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 0bd5cf925fa321b785e3578d6e99d8d7003fa89f..ab012e4762998fe8a133dd551e7f4f0efc6718c6 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -77,7 +77,7 @@ void br_port_carrier_check(struct net_bridge_port *p, bool *notified) if (!test_bit(BR_ADMIN_COST_BIT, &p->flags) && netif_running(dev) && netif_oper_up(dev)) - p->path_cost = port_cost(dev); + WRITE_ONCE(p->path_cost, port_cost(dev)); *notified = false; if (!netif_running(br->dev)) diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index 766c43b327af830a80fba11c940ba34eb03c50c9..07cfcb821e27ebcb72901a365a3f06491f8b0bc3 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -259,7 +259,7 @@ int br_dev_siocdevprivate(struct net_device *dev, struct ifreq *rq, memcpy(&p.designated_bridge, &pt->designated_bridge, 8); p.port_id = pt->port_id; p.designated_port = pt->designated_port; - p.path_cost = pt->path_cost; + p.path_cost = READ_ONCE(pt->path_cost); p.designated_cost = pt->designated_cost; p.state = pt->state; p.top_change_ack = pt->topology_change_ack; diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index a104b25c871d263e4b5701f1be05cb17fbfce28f..08718ebe282aa1d089a127cdc7c24fda5a0a38a5 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -240,7 +240,7 @@ static int br_port_fill_attrs(struct sk_buff *skb, if (nla_put_u8(skb, IFLA_BRPORT_STATE, p->state) || nla_put_u16(skb, IFLA_BRPORT_PRIORITY, p->priority) || - nla_put_u32(skb, IFLA_BRPORT_COST, p->path_cost) || + nla_put_u32(skb, IFLA_BRPORT_COST, READ_ONCE(p->path_cost)) || nla_put_u8(skb, IFLA_BRPORT_MODE, mode) || nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) || nla_put_u8(skb, IFLA_BRPORT_PROTECT, diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index 024210f95468308066827ac2ae71f68f99fa77f5..2d9d0823aa56b63a62ed51c49df54055294e82ad 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -102,8 +102,9 @@ struct net_bridge_port *br_get_port(struct net_bridge *br, u16 port_no) static int br_should_become_root_port(const struct net_bridge_port *p, u16 root_port) { - struct net_bridge *br; + u32 p_path_cost, rp_path_cost; struct net_bridge_port *rp; + struct net_bridge *br; int t; br = p->br; @@ -125,11 +126,14 @@ static int br_should_become_root_port(const struct net_bridge_port *p, else if (t > 0) return 0; - if (p->designated_cost + p->path_cost < - rp->designated_cost + rp->path_cost) + p_path_cost = READ_ONCE(p->path_cost); + rp_path_cost = READ_ONCE(rp->path_cost); + + if (p->designated_cost + p_path_cost < + rp->designated_cost + rp_path_cost) return 1; - else if (p->designated_cost + p->path_cost > - rp->designated_cost + rp->path_cost) + else if (p->designated_cost + p_path_cost > + rp->designated_cost + rp_path_cost) return 0; t = memcmp(&p->designated_bridge, &rp->designated_bridge, 8); @@ -187,7 +191,8 @@ static void br_root_selection(struct net_bridge *br) } else { p = br_get_port(br, root_port); br->designated_root = p->designated_root; - br->root_path_cost = p->designated_cost + p->path_cost; + br->root_path_cost = p->designated_cost + + READ_ONCE(p->path_cost); } } diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index b29dc97b9ad8a5b5c56517d34fe426abd00e2ad6..e5d43492d2dcf0615ee984bc190d7ce2264aaab0 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -341,7 +341,7 @@ int br_stp_set_path_cost(struct net_bridge_port *p, unsigned long path_cost) return -ERANGE; set_bit(BR_ADMIN_COST_BIT, &p->flags); - p->path_cost = path_cost; + WRITE_ONCE(p->path_cost, path_cost); br_configuration_update(p->br); br_port_state_selection(p->br); return 0; diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index d6df81fa0d13fe7e732b69f881b947da2066d9ef..23574476d7f701080452777ab2c23a42b4defba4 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -83,7 +83,7 @@ static int store_flag(struct net_bridge_port *p, unsigned long v, static ssize_t show_path_cost(struct net_bridge_port *p, char *buf) { - return sysfs_emit(buf, "%d\n", p->path_cost); + return sysfs_emit(buf, "%d\n", READ_ONCE(p->path_cost)); } static int store_path_cost(struct net_bridge_port *p, unsigned long v) -- 2.54.0.1032.g2f8565e1d1-goog Add READ_ONCE()/WRITE_ONCE() annotations around p->designated_cost This is needed at least for sysfs show_designated_cost(), BRCTL_GET_PORT_INFO and upcoming RTNL avoidance in "ip link" dumps (cf br_port_fill_attrs()). Signed-off-by: Eric Dumazet Acked-by: Nikolay Aleksandrov --- net/bridge/br_ioctl.c | 2 +- net/bridge/br_netlink.c | 3 ++- net/bridge/br_stp.c | 30 ++++++++++++++++++------------ net/bridge/br_sysfs_if.c | 2 +- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index 07cfcb821e27ebcb72901a365a3f06491f8b0bc3..a507c7b369ac49803019cdca7836c7fb9ef4459e 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -260,7 +260,7 @@ int br_dev_siocdevprivate(struct net_device *dev, struct ifreq *rq, p.port_id = pt->port_id; p.designated_port = pt->designated_port; p.path_cost = READ_ONCE(pt->path_cost); - p.designated_cost = pt->designated_cost; + p.designated_cost = READ_ONCE(pt->designated_cost); p.state = pt->state; p.top_change_ack = pt->topology_change_ack; p.config_pending = pt->config_pending; diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 08718ebe282aa1d089a127cdc7c24fda5a0a38a5..296f62ebdd4a6f3d404b5902fe661995bd1ca0f5 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -264,7 +264,8 @@ static int br_port_fill_attrs(struct sk_buff *skb, nla_put(skb, IFLA_BRPORT_BRIDGE_ID, sizeof(struct ifla_bridge_id), &p->designated_bridge) || nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_PORT, p->designated_port) || - nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_COST, p->designated_cost) || + nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_COST, + READ_ONCE(p->designated_cost)) || nla_put_u16(skb, IFLA_BRPORT_ID, p->port_id) || nla_put_u16(skb, IFLA_BRPORT_NO, p->port_no) || nla_put_u8(skb, IFLA_BRPORT_TOPOLOGY_CHANGE_ACK, diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index 2d9d0823aa56b63a62ed51c49df54055294e82ad..ced8d23f05d1ee262d1760c768e5c88868f13178 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -102,7 +102,7 @@ struct net_bridge_port *br_get_port(struct net_bridge *br, u16 port_no) static int br_should_become_root_port(const struct net_bridge_port *p, u16 root_port) { - u32 p_path_cost, rp_path_cost; + u32 p_path_cost, rp_path_cost, p_designated_cost, rp_designated_cost; struct net_bridge_port *rp; struct net_bridge *br; int t; @@ -128,12 +128,14 @@ static int br_should_become_root_port(const struct net_bridge_port *p, p_path_cost = READ_ONCE(p->path_cost); rp_path_cost = READ_ONCE(rp->path_cost); + p_designated_cost = READ_ONCE(p->designated_cost); + rp_designated_cost = READ_ONCE(rp->designated_cost); - if (p->designated_cost + p_path_cost < - rp->designated_cost + rp_path_cost) + if (p_designated_cost + p_path_cost < + rp_designated_cost + rp_path_cost) return 1; - else if (p->designated_cost + p_path_cost > - rp->designated_cost + rp_path_cost) + else if (p_designated_cost + p_path_cost > + rp_designated_cost + rp_path_cost) return 0; t = memcmp(&p->designated_bridge, &rp->designated_bridge, 8); @@ -191,7 +193,7 @@ static void br_root_selection(struct net_bridge *br) } else { p = br_get_port(br, root_port); br->designated_root = p->designated_root; - br->root_path_cost = p->designated_cost + + br->root_path_cost = READ_ONCE(p->designated_cost) + READ_ONCE(p->path_cost); } } @@ -257,7 +259,7 @@ static void br_record_config_information(struct net_bridge_port *p, const struct br_config_bpdu *bpdu) { p->designated_root = bpdu->root; - p->designated_cost = bpdu->root_path_cost; + WRITE_ONCE(p->designated_cost, bpdu->root_path_cost); p->designated_bridge = bpdu->bridge_id; p->designated_port = bpdu->port_id; p->designated_age = jiffies - bpdu->message_age; @@ -293,6 +295,7 @@ void br_transmit_tcn(struct net_bridge *br) static int br_should_become_designated_port(const struct net_bridge_port *p) { struct net_bridge *br; + u32 p_designated_cost; int t; br = p->br; @@ -302,9 +305,10 @@ static int br_should_become_designated_port(const struct net_bridge_port *p) if (memcmp(&p->designated_root, &br->designated_root, 8)) return 1; - if (br->root_path_cost < p->designated_cost) + p_designated_cost = READ_ONCE(p->designated_cost); + if (br->root_path_cost < p_designated_cost) return 1; - else if (br->root_path_cost > p->designated_cost) + else if (br->root_path_cost > p_designated_cost) return 0; t = memcmp(&br->bridge_id, &p->designated_bridge, 8); @@ -336,6 +340,7 @@ static void br_designated_port_selection(struct net_bridge *br) static int br_supersedes_port_info(const struct net_bridge_port *p, const struct br_config_bpdu *bpdu) { + u32 p_designated_cost; int t; t = memcmp(&bpdu->root, &p->designated_root, 8); @@ -344,9 +349,10 @@ static int br_supersedes_port_info(const struct net_bridge_port *p, else if (t > 0) return 0; - if (bpdu->root_path_cost < p->designated_cost) + p_designated_cost = READ_ONCE(p->designated_cost); + if (bpdu->root_path_cost < p_designated_cost) return 1; - else if (bpdu->root_path_cost > p->designated_cost) + else if (bpdu->root_path_cost > p_designated_cost) return 0; t = memcmp(&bpdu->bridge_id, &p->designated_bridge, 8); @@ -426,7 +432,7 @@ void br_become_designated_port(struct net_bridge_port *p) br = p->br; p->designated_root = br->designated_root; - p->designated_cost = br->root_path_cost; + WRITE_ONCE(p->designated_cost, br->root_path_cost); p->designated_bridge = br->bridge_id; p->designated_port = p->port_id; } diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 23574476d7f701080452777ab2c23a42b4defba4..36b832902d33a492e91d53a4248778b3ee2322ca 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -135,7 +135,7 @@ static BRPORT_ATTR(designated_port, 0444, show_designated_port, NULL); static ssize_t show_designated_cost(struct net_bridge_port *p, char *buf) { - return sysfs_emit(buf, "%d\n", p->designated_cost); + return sysfs_emit(buf, "%d\n", READ_ONCE(p->designated_cost)); } static BRPORT_ATTR(designated_cost, 0444, show_designated_cost, NULL); -- 2.54.0.1032.g2f8565e1d1-goog Add READ_ONCE()/WRITE_ONCE() annotations around p->designated_port This is needed at least for sysfs show_designated_port(), BRCTL_GET_PORT_INFO and upcoming RTNL avoidance in "ip link" dumps (cf br_port_fill_attrs()). Signed-off-by: Eric Dumazet Reviewed-by: Ido Schimmel Acked-by: Nikolay Aleksandrov --- net/bridge/br_ioctl.c | 2 +- net/bridge/br_netlink.c | 3 ++- net/bridge/br_stp.c | 4 ++-- net/bridge/br_stp_if.c | 2 +- net/bridge/br_sysfs_if.c | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index a507c7b369ac49803019cdca7836c7fb9ef4459e..2be802991f70ab3ce48ade5da6d1488e072dbec6 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -258,7 +258,7 @@ int br_dev_siocdevprivate(struct net_device *dev, struct ifreq *rq, memcpy(&p.designated_root, &pt->designated_root, 8); memcpy(&p.designated_bridge, &pt->designated_bridge, 8); p.port_id = pt->port_id; - p.designated_port = pt->designated_port; + p.designated_port = READ_ONCE(pt->designated_port); p.path_cost = READ_ONCE(pt->path_cost); p.designated_cost = READ_ONCE(pt->designated_cost); p.state = pt->state; diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 296f62ebdd4a6f3d404b5902fe661995bd1ca0f5..a722db89aef6bbb6ecc77c7e0f173dc79418797f 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -263,7 +263,8 @@ static int br_port_fill_attrs(struct sk_buff *skb, &p->designated_root) || nla_put(skb, IFLA_BRPORT_BRIDGE_ID, sizeof(struct ifla_bridge_id), &p->designated_bridge) || - nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_PORT, p->designated_port) || + nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_PORT, + READ_ONCE(p->designated_port)) || nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_COST, READ_ONCE(p->designated_cost)) || nla_put_u16(skb, IFLA_BRPORT_ID, p->port_id) || diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index ced8d23f05d1ee262d1760c768e5c88868f13178..cbc48197c3db5e225ead7425b2cee46acc9768f3 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -261,7 +261,7 @@ static void br_record_config_information(struct net_bridge_port *p, p->designated_root = bpdu->root; WRITE_ONCE(p->designated_cost, bpdu->root_path_cost); p->designated_bridge = bpdu->bridge_id; - p->designated_port = bpdu->port_id; + WRITE_ONCE(p->designated_port, bpdu->port_id); p->designated_age = jiffies - bpdu->message_age; mod_timer(&p->message_age_timer, jiffies @@ -434,7 +434,7 @@ void br_become_designated_port(struct net_bridge_port *p) p->designated_root = br->designated_root; WRITE_ONCE(p->designated_cost, br->root_path_cost); p->designated_bridge = br->bridge_id; - p->designated_port = p->port_id; + WRITE_ONCE(p->designated_port, p->port_id); } diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index e5d43492d2dcf0615ee984bc190d7ce2264aaab0..7b0d1a334785047905a00694fd65e3212b160e5d 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -320,7 +320,7 @@ int br_stp_set_port_priority(struct net_bridge_port *p, unsigned long newprio) new_port_id = br_make_port_id(newprio, p->port_no); if (br_is_designated_port(p)) - p->designated_port = new_port_id; + WRITE_ONCE(p->designated_port, new_port_id); p->port_id = new_port_id; p->priority = newprio; diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 36b832902d33a492e91d53a4248778b3ee2322ca..1023f97b1c9a22a1f79c3c734aef9bd41832ea39 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -129,7 +129,7 @@ static BRPORT_ATTR(designated_bridge, 0444, show_designated_bridge, NULL); static ssize_t show_designated_port(struct net_bridge_port *p, char *buf) { - return sysfs_emit(buf, "%d\n", p->designated_port); + return sysfs_emit(buf, "%d\n", READ_ONCE(p->designated_port)); } static BRPORT_ATTR(designated_port, 0444, show_designated_port, NULL); -- 2.54.0.1032.g2f8565e1d1-goog sysfs show_priority() needs this. Also br_port_fill_attrs() might in the future run without RTNL. Signed-off-by: Eric Dumazet Reviewed-by: Ido Schimmel Acked-by: Nikolay Aleksandrov --- net/bridge/br_netlink.c | 2 +- net/bridge/br_stp_if.c | 2 +- net/bridge/br_sysfs_if.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index a722db89aef6bbb6ecc77c7e0f173dc79418797f..fc25c6b6cc9713080873976f443da1fbd764aafe 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -239,7 +239,7 @@ static int br_port_fill_attrs(struct sk_buff *skb, u64 timerval; if (nla_put_u8(skb, IFLA_BRPORT_STATE, p->state) || - nla_put_u16(skb, IFLA_BRPORT_PRIORITY, p->priority) || + nla_put_u16(skb, IFLA_BRPORT_PRIORITY, READ_ONCE(p->priority)) || nla_put_u32(skb, IFLA_BRPORT_COST, READ_ONCE(p->path_cost)) || nla_put_u8(skb, IFLA_BRPORT_MODE, mode) || nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) || diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 7b0d1a334785047905a00694fd65e3212b160e5d..3524bb7e87f0586774a883720be9fa8eb60f0370 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -323,7 +323,7 @@ int br_stp_set_port_priority(struct net_bridge_port *p, unsigned long newprio) WRITE_ONCE(p->designated_port, new_port_id); p->port_id = new_port_id; - p->priority = newprio; + WRITE_ONCE(p->priority, newprio); if (!memcmp(&p->br->bridge_id, &p->designated_bridge, 8) && p->port_id < p->designated_port) { br_become_designated_port(p); diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 1023f97b1c9a22a1f79c3c734aef9bd41832ea39..3f666d4fef42324a4751779153ecc48bdb44b85a 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -100,7 +100,7 @@ static BRPORT_ATTR(path_cost, 0644, show_path_cost, store_path_cost); static ssize_t show_priority(struct net_bridge_port *p, char *buf) { - return sysfs_emit(buf, "%d\n", p->priority); + return sysfs_emit(buf, "%d\n", READ_ONCE(p->priority)); } static int store_priority(struct net_bridge_port *p, unsigned long v) -- 2.54.0.1032.g2f8565e1d1-goog sysfs show_port_id() and BRCTL_GET_PORT_INFO need this. This will be needed for upcoming RTNL avoidance in "ip link" dumps (cf br_port_fill_attrs()). Signed-off-by: Eric Dumazet Reviewed-by: Ido Schimmel Acked-by: Nikolay Aleksandrov --- net/bridge/br_ioctl.c | 2 +- net/bridge/br_netlink.c | 2 +- net/bridge/br_stp_if.c | 4 ++-- net/bridge/br_sysfs_if.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index 2be802991f70ab3ce48ade5da6d1488e072dbec6..a017374c6e659498d98c6af3f8d8e46a8b93570e 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -257,7 +257,7 @@ int br_dev_siocdevprivate(struct net_device *dev, struct ifreq *rq, memset(&p, 0, sizeof(struct __port_info)); memcpy(&p.designated_root, &pt->designated_root, 8); memcpy(&p.designated_bridge, &pt->designated_bridge, 8); - p.port_id = pt->port_id; + p.port_id = READ_ONCE(pt->port_id); p.designated_port = READ_ONCE(pt->designated_port); p.path_cost = READ_ONCE(pt->path_cost); p.designated_cost = READ_ONCE(pt->designated_cost); diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index fc25c6b6cc9713080873976f443da1fbd764aafe..f8266a7a9e2b910f1b4e08792b2940ae0fd2bba2 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -267,7 +267,7 @@ static int br_port_fill_attrs(struct sk_buff *skb, READ_ONCE(p->designated_port)) || nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_COST, READ_ONCE(p->designated_cost)) || - nla_put_u16(skb, IFLA_BRPORT_ID, p->port_id) || + nla_put_u16(skb, IFLA_BRPORT_ID, READ_ONCE(p->port_id)) || nla_put_u16(skb, IFLA_BRPORT_NO, p->port_no) || nla_put_u8(skb, IFLA_BRPORT_TOPOLOGY_CHANGE_ACK, p->topology_change_ack) || diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 3524bb7e87f0586774a883720be9fa8eb60f0370..8a418f6af423ccba88fae57d2254e35e1ae4a1a0 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -34,7 +34,7 @@ void br_init_port(struct net_bridge_port *p) { int err; - p->port_id = br_make_port_id(p->priority, p->port_no); + WRITE_ONCE(p->port_id, br_make_port_id(p->priority, p->port_no)); br_become_designated_port(p); br_set_state(p, BR_STATE_BLOCKING); p->topology_change_ack = 0; @@ -322,7 +322,7 @@ int br_stp_set_port_priority(struct net_bridge_port *p, unsigned long newprio) if (br_is_designated_port(p)) WRITE_ONCE(p->designated_port, new_port_id); - p->port_id = new_port_id; + WRITE_ONCE(p->port_id, new_port_id); WRITE_ONCE(p->priority, newprio); if (!memcmp(&p->br->bridge_id, &p->designated_bridge, 8) && p->port_id < p->designated_port) { diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 3f666d4fef42324a4751779153ecc48bdb44b85a..1cc474ed0fdc02234a9f9d6b936247c34cbb127d 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -141,7 +141,7 @@ static BRPORT_ATTR(designated_cost, 0444, show_designated_cost, NULL); static ssize_t show_port_id(struct net_bridge_port *p, char *buf) { - return sysfs_emit(buf, "0x%x\n", p->port_id); + return sysfs_emit(buf, "0x%x\n", READ_ONCE(p->port_id)); } static BRPORT_ATTR(port_id, 0444, show_port_id, NULL); -- 2.54.0.1032.g2f8565e1d1-goog Needed for sysfs show_config_pending(), BRCTL_GET_PORT_INFO and upcoming RTNL avoidance in "ip link" dumps (cf br_port_fill_attrs()). Signed-off-by: Eric Dumazet Reviewed-by: Ido Schimmel Acked-by: Nikolay Aleksandrov --- net/bridge/br_ioctl.c | 2 +- net/bridge/br_netlink.c | 2 +- net/bridge/br_stp.c | 8 ++++---- net/bridge/br_stp_if.c | 4 ++-- net/bridge/br_sysfs_if.c | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index a017374c6e659498d98c6af3f8d8e46a8b93570e..39f3ffcfa2d33f15cec6e61490100925eefc7e68 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -263,7 +263,7 @@ int br_dev_siocdevprivate(struct net_device *dev, struct ifreq *rq, p.designated_cost = READ_ONCE(pt->designated_cost); p.state = pt->state; p.top_change_ack = pt->topology_change_ack; - p.config_pending = pt->config_pending; + p.config_pending = READ_ONCE(pt->config_pending); p.message_age_timer_value = br_timer_value(&pt->message_age_timer); p.forward_delay_timer_value = br_timer_value(&pt->forward_delay_timer); p.hold_timer_value = br_timer_value(&pt->hold_timer); diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index f8266a7a9e2b910f1b4e08792b2940ae0fd2bba2..ead66dbe1bb7679af18d5f0c2fdea6be2574727d 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -271,7 +271,7 @@ static int br_port_fill_attrs(struct sk_buff *skb, nla_put_u16(skb, IFLA_BRPORT_NO, p->port_no) || nla_put_u8(skb, IFLA_BRPORT_TOPOLOGY_CHANGE_ACK, p->topology_change_ack) || - nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, p->config_pending) || + nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, READ_ONCE(p->config_pending)) || nla_put_u8(skb, IFLA_BRPORT_VLAN_TUNNEL, !!(p->flags & BR_VLAN_TUNNEL)) || nla_put_u16(skb, IFLA_BRPORT_GROUP_FWD_MASK, p->group_fwd_mask) || diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index cbc48197c3db5e225ead7425b2cee46acc9768f3..b33eb085d9b6cb4cd4f3aff2aa4793d027bbc0f8 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -220,7 +220,7 @@ void br_transmit_config(struct net_bridge_port *p) struct net_bridge *br; if (timer_pending(&p->hold_timer)) { - p->config_pending = 1; + WRITE_ONCE(p->config_pending, 1); return; } @@ -247,7 +247,7 @@ void br_transmit_config(struct net_bridge_port *p) if (bpdu.message_age < br->max_age) { br_send_config_bpdu(p, &bpdu); p->topology_change_ack = 0; - p->config_pending = 0; + WRITE_ONCE(p->config_pending, 0); if (p->br->stp_enabled == BR_KERNEL_STP) mod_timer(&p->hold_timer, round_jiffies(jiffies + BR_HOLD_TIME)); @@ -490,14 +490,14 @@ void br_port_state_selection(struct net_bridge *br) /* Don't change port states if userspace is handling STP */ if (br->stp_enabled != BR_USER_STP) { if (p->port_no == br->root_port) { - p->config_pending = 0; + WRITE_ONCE(p->config_pending, 0); p->topology_change_ack = 0; br_make_forwarding(p); } else if (br_is_designated_port(p)) { timer_delete(&p->message_age_timer); br_make_forwarding(p); } else { - p->config_pending = 0; + WRITE_ONCE(p->config_pending, 0); p->topology_change_ack = 0; br_make_blocking(p); } diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 8a418f6af423ccba88fae57d2254e35e1ae4a1a0..a7e5422eb5d140b501a7dcebf0238d5a77c5f4a1 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -38,7 +38,7 @@ void br_init_port(struct net_bridge_port *p) br_become_designated_port(p); br_set_state(p, BR_STATE_BLOCKING); p->topology_change_ack = 0; - p->config_pending = 0; + WRITE_ONCE(p->config_pending, 0); err = __set_ageing_time(p->dev, p->br->ageing_time); if (err) @@ -105,7 +105,7 @@ void br_stp_disable_port(struct net_bridge_port *p) br_become_designated_port(p); br_set_state(p, BR_STATE_DISABLED); p->topology_change_ack = 0; - p->config_pending = 0; + WRITE_ONCE(p->config_pending, 0); br_ifinfo_notify(RTM_NEWLINK, NULL, p); diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 1cc474ed0fdc02234a9f9d6b936247c34cbb127d..1923c004f0d2b746902f5b6de1bbb72f7f824125 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -160,7 +160,7 @@ static BRPORT_ATTR(change_ack, 0444, show_change_ack, NULL); static ssize_t show_config_pending(struct net_bridge_port *p, char *buf) { - return sysfs_emit(buf, "%d\n", p->config_pending); + return sysfs_emit(buf, "%d\n", READ_ONCE(p->config_pending)); } static BRPORT_ATTR(config_pending, 0444, show_config_pending, NULL); -- 2.54.0.1032.g2f8565e1d1-goog We might run br_port_fill_attrs() locklessly in the future. Signed-off-by: Eric Dumazet Reviewed-by: Ido Schimmel Acked-by: Nikolay Aleksandrov --- net/bridge/br_netlink.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index ead66dbe1bb7679af18d5f0c2fdea6be2574727d..7cb24de9c77d3d15892723f77288c27a15a6a0ad 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -234,7 +234,8 @@ static inline size_t br_nlmsg_size(struct net_device *dev, u32 filter_mask) static int br_port_fill_attrs(struct sk_buff *skb, const struct net_bridge_port *p) { - u8 mode = !!(p->flags & BR_HAIRPIN_MODE); + unsigned long flags = READ_ONCE(p->flags); + u8 mode = !!(flags & BR_HAIRPIN_MODE); struct net_bridge_port *backup_p; u64 timerval; @@ -242,23 +243,23 @@ static int br_port_fill_attrs(struct sk_buff *skb, nla_put_u16(skb, IFLA_BRPORT_PRIORITY, READ_ONCE(p->priority)) || nla_put_u32(skb, IFLA_BRPORT_COST, READ_ONCE(p->path_cost)) || nla_put_u8(skb, IFLA_BRPORT_MODE, mode) || - nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) || + nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(flags & BR_BPDU_GUARD)) || nla_put_u8(skb, IFLA_BRPORT_PROTECT, - !!(p->flags & BR_ROOT_BLOCK)) || + !!(flags & BR_ROOT_BLOCK)) || nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, - !!(p->flags & BR_MULTICAST_FAST_LEAVE)) || + !!(flags & BR_MULTICAST_FAST_LEAVE)) || nla_put_u8(skb, IFLA_BRPORT_MCAST_TO_UCAST, - !!(p->flags & BR_MULTICAST_TO_UNICAST)) || - nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) || + !!(flags & BR_MULTICAST_TO_UNICAST)) || + nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(flags & BR_LEARNING)) || nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, - !!(p->flags & BR_FLOOD)) || + !!(flags & BR_FLOOD)) || nla_put_u8(skb, IFLA_BRPORT_MCAST_FLOOD, - !!(p->flags & BR_MCAST_FLOOD)) || + !!(flags & BR_MCAST_FLOOD)) || nla_put_u8(skb, IFLA_BRPORT_BCAST_FLOOD, - !!(p->flags & BR_BCAST_FLOOD)) || - nla_put_u8(skb, IFLA_BRPORT_PROXYARP, !!(p->flags & BR_PROXYARP)) || + !!(flags & BR_BCAST_FLOOD)) || + nla_put_u8(skb, IFLA_BRPORT_PROXYARP, !!(flags & BR_PROXYARP)) || nla_put_u8(skb, IFLA_BRPORT_PROXYARP_WIFI, - !!(p->flags & BR_PROXYARP_WIFI)) || + !!(flags & BR_PROXYARP_WIFI)) || nla_put(skb, IFLA_BRPORT_ROOT_ID, sizeof(struct ifla_bridge_id), &p->designated_root) || nla_put(skb, IFLA_BRPORT_BRIDGE_ID, sizeof(struct ifla_bridge_id), @@ -272,22 +273,22 @@ static int br_port_fill_attrs(struct sk_buff *skb, nla_put_u8(skb, IFLA_BRPORT_TOPOLOGY_CHANGE_ACK, p->topology_change_ack) || nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, READ_ONCE(p->config_pending)) || - nla_put_u8(skb, IFLA_BRPORT_VLAN_TUNNEL, !!(p->flags & + nla_put_u8(skb, IFLA_BRPORT_VLAN_TUNNEL, !!(flags & BR_VLAN_TUNNEL)) || nla_put_u16(skb, IFLA_BRPORT_GROUP_FWD_MASK, p->group_fwd_mask) || nla_put_u8(skb, IFLA_BRPORT_NEIGH_SUPPRESS, - !!(p->flags & BR_NEIGH_SUPPRESS)) || - nla_put_u8(skb, IFLA_BRPORT_MRP_RING_OPEN, !!(p->flags & + !!(flags & BR_NEIGH_SUPPRESS)) || + nla_put_u8(skb, IFLA_BRPORT_MRP_RING_OPEN, !!(flags & BR_MRP_LOST_CONT)) || nla_put_u8(skb, IFLA_BRPORT_MRP_IN_OPEN, - !!(p->flags & BR_MRP_LOST_IN_CONT)) || - nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED)) || - nla_put_u8(skb, IFLA_BRPORT_LOCKED, !!(p->flags & BR_PORT_LOCKED)) || - nla_put_u8(skb, IFLA_BRPORT_MAB, !!(p->flags & BR_PORT_MAB)) || + !!(flags & BR_MRP_LOST_IN_CONT)) || + nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(flags & BR_ISOLATED)) || + nla_put_u8(skb, IFLA_BRPORT_LOCKED, !!(flags & BR_PORT_LOCKED)) || + nla_put_u8(skb, IFLA_BRPORT_MAB, !!(flags & BR_PORT_MAB)) || nla_put_u8(skb, IFLA_BRPORT_NEIGH_VLAN_SUPPRESS, - !!(p->flags & BR_NEIGH_VLAN_SUPPRESS)) || + !!(flags & BR_NEIGH_VLAN_SUPPRESS)) || nla_put_u8(skb, IFLA_BRPORT_NEIGH_FORWARD_GRAT, - !!(p->flags & BR_NEIGH_FORWARD_GRAT))) + !!(flags & BR_NEIGH_FORWARD_GRAT))) return -EMSGSIZE; timerval = br_timer_value(&p->message_age_timer); -- 2.54.0.1032.g2f8565e1d1-goog