Skip to content

Commit

Permalink
net: ipv4: provide __rcu annotation for ifa_list
Browse files Browse the repository at this point in the history
ifa_list is protected by rcu, yet code doesn't reflect this.

Add the __rcu annotations and fix up all places that are now reported by
sparse.

I've done this in the same commit to not add intermediate patches that
result in new warnings.

Reported-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Florian Westphal authored and David S. Miller committed Jun 3, 2019
1 parent cb8f147 commit 2638eb8
Show file tree
Hide file tree
Showing 15 changed files with 134 additions and 81 deletions.
12 changes: 8 additions & 4 deletions drivers/infiniband/hw/i40iw/i40iw_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,14 @@ int i40iw_inetaddr_event(struct notifier_block *notifier,
rcu_read_lock();
in = __in_dev_get_rcu(upper_dev);

if (!in->ifa_list)
local_ipaddr = 0;
else
local_ipaddr = ntohl(in->ifa_list->ifa_address);
local_ipaddr = 0;
if (in) {
struct in_ifaddr *ifa;

ifa = rcu_dereference(in->ifa_list);
if (ifa)
local_ipaddr = ntohl(ifa->ifa_address);
}

rcu_read_unlock();
} else {
Expand Down
8 changes: 7 additions & 1 deletion drivers/infiniband/hw/nes/nes.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,13 @@ static int nes_inetaddr_event(struct notifier_block *notifier,

rcu_read_lock();
in = __in_dev_get_rcu(upper_dev);
nesvnic->local_ipaddr = in->ifa_list->ifa_address;
if (in) {
struct in_ifaddr *ifa;

ifa = rcu_dereference(in->ifa_list);
if (ifa)
nesvnic->local_ipaddr = ifa->ifa_address;
}
rcu_read_unlock();
} else {
nesvnic->local_ipaddr = ifa->ifa_address;
Expand Down
15 changes: 10 additions & 5 deletions drivers/infiniband/hw/usnic/usnic_ib_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,11 +427,16 @@ static void *usnic_ib_device_add(struct pci_dev *dev)
if (netif_carrier_ok(us_ibdev->netdev))
usnic_fwd_carrier_up(us_ibdev->ufdev);

ind = in_dev_get(netdev);
if (ind->ifa_list)
usnic_fwd_add_ipaddr(us_ibdev->ufdev,
ind->ifa_list->ifa_address);
in_dev_put(ind);
rcu_read_lock();
ind = __in_dev_get_rcu(netdev);
if (ind) {
const struct in_ifaddr *ifa;

ifa = rcu_dereference(ind->ifa_list);
if (ifa)
usnic_fwd_add_ipaddr(us_ibdev->ufdev, ifa->ifa_address);
}
rcu_read_unlock();

usnic_mac_ip_to_gid(us_ibdev->netdev->perm_addr,
us_ibdev->ufdev->inaddr, &gid.raw[0]);
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/via/via-velocity.h
Original file line number Diff line number Diff line change
Expand Up @@ -1509,7 +1509,7 @@ static inline int velocity_get_ip(struct velocity_info *vptr)
rcu_read_lock();
in_dev = __in_dev_get_rcu(vptr->netdev);
if (in_dev != NULL) {
ifa = (struct in_ifaddr *) in_dev->ifa_list;
ifa = rcu_dereference(in_dev->ifa_list);
if (ifa != NULL) {
memcpy(vptr->ip_addr, &ifa->ifa_address, 4);
res = 0;
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/plip/plip.c
Original file line number Diff line number Diff line change
Expand Up @@ -1012,7 +1012,7 @@ plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth)
in_dev = __in_dev_get_rcu(dev);
if (in_dev) {
/* Any address will do - we take the first */
const struct in_ifaddr *ifa = in_dev->ifa_list;
const struct in_ifaddr *ifa = rcu_dereference(in_dev->ifa_list);
if (ifa) {
memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
memset(eth->h_dest, 0xfc, 2);
Expand Down Expand Up @@ -1107,7 +1107,7 @@ plip_open(struct net_device *dev)
/* Any address will do - we take the first. We already
have the first two bytes filled with 0xfc, from
plip_init_dev(). */
struct in_ifaddr *ifa=in_dev->ifa_list;
const struct in_ifaddr *ifa = rcu_dereference(in_dev->ifa_list);
if (ifa != NULL) {
memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
}
Expand Down
19 changes: 13 additions & 6 deletions drivers/net/vmxnet3/vmxnet3_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -3651,13 +3651,19 @@ vmxnet3_suspend(struct device *device)
}

if (adapter->wol & WAKE_ARP) {
in_dev = in_dev_get(netdev);
if (!in_dev)
rcu_read_lock();

in_dev = __in_dev_get_rcu(netdev);
if (!in_dev) {
rcu_read_unlock();
goto skip_arp;
}

ifa = (struct in_ifaddr *)in_dev->ifa_list;
if (!ifa)
ifa = rcu_dereference(in_dev->ifa_list);
if (!ifa) {
rcu_read_unlock();
goto skip_arp;
}

pmConf->filters[i].patternSize = ETH_HLEN + /* Ethernet header*/
sizeof(struct arphdr) + /* ARP header */
Expand All @@ -3677,7 +3683,9 @@ vmxnet3_suspend(struct device *device)

/* The Unicast IPv4 address in 'tip' field. */
arpreq += 2 * ETH_ALEN + sizeof(u32);
*(u32 *)arpreq = ifa->ifa_address;
*(__be32 *)arpreq = ifa->ifa_address;

rcu_read_unlock();

/* The mask for the relevant bits. */
pmConf->filters[i].mask[0] = 0x00;
Expand All @@ -3686,7 +3694,6 @@ vmxnet3_suspend(struct device *device)
pmConf->filters[i].mask[3] = 0x00;
pmConf->filters[i].mask[4] = 0xC0; /* IPv4 TIP */
pmConf->filters[i].mask[5] = 0x03; /* IPv4 TIP */
in_dev_put(in_dev);

pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_FILTER;
i++;
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/ath/ath6kl/cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -2194,13 +2194,13 @@ static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif,
if (!in_dev)
return 0;

ifa = in_dev->ifa_list;
ifa = rtnl_dereference(in_dev->ifa_list);
memset(&ips, 0, sizeof(ips));

/* Configure IP addr only if IP address count < MAX_IP_ADDRS */
while (index < MAX_IP_ADDRS && ifa) {
ips[index] = ifa->ifa_local;
ifa = ifa->ifa_next;
ifa = rtnl_dereference(ifa->ifa_next);
index++;
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/marvell/mwifiex/cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -3268,7 +3268,7 @@ static void mwifiex_set_auto_arp_mef_entry(struct mwifiex_private *priv,
in_dev = __in_dev_get_rtnl(adapter->priv[i]->netdev);
if (!in_dev)
continue;
ifa = in_dev->ifa_list;
ifa = rtnl_dereference(in_dev->ifa_list);
if (!ifa || !ifa->ifa_local)
continue;
ips[i] = ifa->ifa_local;
Expand Down
6 changes: 5 additions & 1 deletion drivers/staging/isdn/hysdn/hysdn_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,13 @@ net_open(struct net_device *dev)
for (i = 0; i < ETH_ALEN; i++)
dev->dev_addr[i] = 0xfc;
if ((in_dev = dev->ip_ptr) != NULL) {
struct in_ifaddr *ifa = in_dev->ifa_list;
const struct in_ifaddr *ifa;

rcu_read_lock();
ifa = rcu_dereference(in_dev->ifa_list);
if (ifa != NULL)
memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ifa->ifa_local)), &ifa->ifa_local, sizeof(ifa->ifa_local));
rcu_read_unlock();
}
} else
memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN);
Expand Down
21 changes: 6 additions & 15 deletions include/linux/inetdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct in_device {
struct net_device *dev;
refcount_t refcnt;
int dead;
struct in_ifaddr *ifa_list; /* IP ifaddr chain */
struct in_ifaddr __rcu *ifa_list;/* IP ifaddr chain */

struct ip_mc_list __rcu *mc_list; /* IP multicast filter chain */
struct ip_mc_list __rcu * __rcu *mc_hash;
Expand Down Expand Up @@ -136,7 +136,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)

struct in_ifaddr {
struct hlist_node hash;
struct in_ifaddr *ifa_next;
struct in_ifaddr __rcu *ifa_next;
struct in_device *ifa_dev;
struct rcu_head rcu_head;
__be32 ifa_local;
Expand Down Expand Up @@ -206,22 +206,13 @@ static __inline__ bool bad_mask(__be32 mask, __be32 addr)
return false;
}

#define for_primary_ifa(in_dev) { struct in_ifaddr *ifa; \
for (ifa = (in_dev)->ifa_list; ifa && !(ifa->ifa_flags&IFA_F_SECONDARY); ifa = ifa->ifa_next)

#define for_ifa(in_dev) { struct in_ifaddr *ifa; \
for (ifa = (in_dev)->ifa_list; ifa; ifa = ifa->ifa_next)


#define endfor_ifa(in_dev) }

#define in_dev_for_each_ifa_rtnl(ifa, in_dev) \
for (ifa = (in_dev)->ifa_list; ifa; \
ifa = ifa->ifa_next)
for (ifa = rtnl_dereference((in_dev)->ifa_list); ifa; \
ifa = rtnl_dereference(ifa->ifa_next))

#define in_dev_for_each_ifa_rcu(ifa, in_dev) \
for (ifa = (in_dev)->ifa_list; ifa; \
ifa = ifa->ifa_next)
for (ifa = rcu_dereference((in_dev)->ifa_list); ifa; \
ifa = rcu_dereference(ifa->ifa_next))

static inline struct in_device *__in_dev_get_rcu(const struct net_device *dev)
{
Expand Down
10 changes: 8 additions & 2 deletions net/core/netpoll.c
Original file line number Diff line number Diff line change
Expand Up @@ -696,16 +696,22 @@ int netpoll_setup(struct netpoll *np)

if (!np->local_ip.ip) {
if (!np->ipv6) {
const struct in_ifaddr *ifa;

in_dev = __in_dev_get_rtnl(ndev);
if (!in_dev)
goto put_noaddr;

if (!in_dev || !in_dev->ifa_list) {
ifa = rtnl_dereference(in_dev->ifa_list);
if (!ifa) {
put_noaddr:
np_err(np, "no IP address for %s, aborting\n",
np->dev_name);
err = -EDESTADDRREQ;
goto put;
}

np->local_ip.ip = in_dev->ifa_list->ifa_local;
np->local_ip.ip = ifa->ifa_local;
np_info(np, "local IP %pI4\n", &np->local_ip.ip);
} else {
#if IS_ENABLED(CONFIG_IPV6)
Expand Down
8 changes: 5 additions & 3 deletions net/core/pktgen.c
Original file line number Diff line number Diff line change
Expand Up @@ -2125,9 +2125,11 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
rcu_read_lock();
in_dev = __in_dev_get_rcu(pkt_dev->odev);
if (in_dev) {
if (in_dev->ifa_list) {
pkt_dev->saddr_min =
in_dev->ifa_list->ifa_address;
const struct in_ifaddr *ifa;

ifa = rcu_dereference(in_dev->ifa_list);
if (ifa) {
pkt_dev->saddr_min = ifa->ifa_address;
pkt_dev->saddr_max = pkt_dev->saddr_min;
}
}
Expand Down
Loading

0 comments on commit 2638eb8

Please sign in to comment.