net: ipv4: provide __rcu annotation for ifa_list

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>
This commit is contained in:
Florian Westphal 2019-05-31 18:27:09 +02:00 committed by David S. Miller
parent cb8f1478ce
commit 2638eb8b50
15 changed files with 135 additions and 82 deletions

View File

@ -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);
if (in) {
struct in_ifaddr *ifa;
ifa = rcu_dereference(in->ifa_list);
if (ifa)
local_ipaddr = ntohl(ifa->ifa_address);
}
rcu_read_unlock();
} else {

View File

@ -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;

View File

@ -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]);

View File

@ -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;

View File

@ -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);
@ -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);
}

View File

@ -3651,13 +3651,19 @@ vmxnet3_suspend(struct device *device)
}
if (adapter->wol & WAKE_ARP) {
in_dev = in_dev_get(netdev);
if (!in_dev)
goto skip_arp;
rcu_read_lock();
ifa = (struct in_ifaddr *)in_dev->ifa_list;
if (!ifa)
in_dev = __in_dev_get_rcu(netdev);
if (!in_dev) {
rcu_read_unlock();
goto skip_arp;
}
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 */
@ -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;
@ -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++;

View File

@ -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++;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
@ -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;
@ -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)
{

View File

@ -696,16 +696,22 @@ int netpoll_setup(struct netpoll *np)
if (!np->local_ip.ip) {
if (!np->ipv6) {
in_dev = __in_dev_get_rtnl(ndev);
const struct in_ifaddr *ifa;
if (!in_dev || !in_dev->ifa_list) {
in_dev = __in_dev_get_rtnl(ndev);
if (!in_dev)
goto put_noaddr;
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)

View File

@ -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;
}
}

View File

@ -194,7 +194,8 @@ static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32);
static BLOCKING_NOTIFIER_HEAD(inetaddr_chain);
static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain);
static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
static void inet_del_ifa(struct in_device *in_dev,
struct in_ifaddr __rcu **ifap,
int destroy);
#ifdef CONFIG_SYSCTL
static int devinet_sysctl_register(struct in_device *idev);
@ -300,8 +301,8 @@ static void in_dev_rcu_put(struct rcu_head *head)
static void inetdev_destroy(struct in_device *in_dev)
{
struct in_ifaddr *ifa;
struct net_device *dev;
struct in_ifaddr *ifa;
ASSERT_RTNL();
@ -311,7 +312,7 @@ static void inetdev_destroy(struct in_device *in_dev)
ip_mc_destroy_dev(in_dev);
while ((ifa = in_dev->ifa_list) != NULL) {
while ((ifa = rtnl_dereference(in_dev->ifa_list)) != NULL) {
inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
inet_free_ifa(ifa);
}
@ -342,17 +343,20 @@ int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
return 0;
}
static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
static void __inet_del_ifa(struct in_device *in_dev,
struct in_ifaddr __rcu **ifap,
int destroy, struct nlmsghdr *nlh, u32 portid)
{
struct in_ifaddr *promote = NULL;
struct in_ifaddr *ifa, *ifa1 = *ifap;
struct in_ifaddr *last_prim = in_dev->ifa_list;
struct in_ifaddr *ifa, *ifa1;
struct in_ifaddr *last_prim;
struct in_ifaddr *prev_prom = NULL;
int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
ASSERT_RTNL();
ifa1 = rtnl_dereference(*ifap);
last_prim = rtnl_dereference(in_dev->ifa_list);
if (in_dev->dead)
goto no_promotions;
@ -361,9 +365,9 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
**/
if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
struct in_ifaddr **ifap1 = &ifa1->ifa_next;
struct in_ifaddr __rcu **ifap1 = &ifa1->ifa_next;
while ((ifa = *ifap1) != NULL) {
while ((ifa = rtnl_dereference(*ifap1)) != NULL) {
if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
ifa1->ifa_scope <= ifa->ifa_scope)
last_prim = ifa;
@ -396,7 +400,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
* and later to add them back with new prefsrc. Do this
* while all addresses are on the device list.
*/
for (ifa = promote; ifa; ifa = ifa->ifa_next) {
for (ifa = promote; ifa; ifa = rtnl_dereference(ifa->ifa_next)) {
if (ifa1->ifa_mask == ifa->ifa_mask &&
inet_ifa_match(ifa1->ifa_address, ifa))
fib_del_ifaddr(ifa, ifa1);
@ -422,19 +426,24 @@ no_promotions:
blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
if (promote) {
struct in_ifaddr *next_sec = promote->ifa_next;
struct in_ifaddr *next_sec;
next_sec = rtnl_dereference(promote->ifa_next);
if (prev_prom) {
prev_prom->ifa_next = promote->ifa_next;
promote->ifa_next = last_prim->ifa_next;
last_prim->ifa_next = promote;
struct in_ifaddr *last_sec;
last_sec = rtnl_dereference(last_prim->ifa_next);
rcu_assign_pointer(prev_prom->ifa_next, next_sec);
rcu_assign_pointer(promote->ifa_next, last_sec);
rcu_assign_pointer(last_prim->ifa_next, promote);
}
promote->ifa_flags &= ~IFA_F_SECONDARY;
rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid);
blocking_notifier_call_chain(&inetaddr_chain,
NETDEV_UP, promote);
for (ifa = next_sec; ifa; ifa = ifa->ifa_next) {
for (ifa = next_sec; ifa;
ifa = rtnl_dereference(ifa->ifa_next)) {
if (ifa1->ifa_mask != ifa->ifa_mask ||
!inet_ifa_match(ifa1->ifa_address, ifa))
continue;
@ -446,7 +455,8 @@ no_promotions:
inet_free_ifa(ifa1);
}
static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
static void inet_del_ifa(struct in_device *in_dev,
struct in_ifaddr __rcu **ifap,
int destroy)
{
__inet_del_ifa(in_dev, ifap, destroy, NULL, 0);
@ -459,9 +469,10 @@ static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime);
static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
u32 portid, struct netlink_ext_ack *extack)
{
struct in_ifaddr __rcu **last_primary, **ifap;
struct in_device *in_dev = ifa->ifa_dev;
struct in_ifaddr *ifa1, **ifap, **last_primary;
struct in_validator_info ivi;
struct in_ifaddr *ifa1;
int ret;
ASSERT_RTNL();
@ -474,8 +485,10 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
ifa->ifa_flags &= ~IFA_F_SECONDARY;
last_primary = &in_dev->ifa_list;
for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
ifap = &ifa1->ifa_next) {
ifap = &in_dev->ifa_list;
ifa1 = rtnl_dereference(*ifap);
while (ifa1) {
if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
ifa->ifa_scope <= ifa1->ifa_scope)
last_primary = &ifa1->ifa_next;
@ -491,6 +504,9 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
}
ifa->ifa_flags |= IFA_F_SECONDARY;
}
ifap = &ifa1->ifa_next;
ifa1 = rtnl_dereference(*ifap);
}
/* Allow any devices that wish to register ifaddr validtors to weigh
@ -516,8 +532,8 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
ifap = last_primary;
}
ifa->ifa_next = *ifap;
*ifap = ifa;
rcu_assign_pointer(ifa->ifa_next, *ifap);
rcu_assign_pointer(*ifap, ifa);
inet_hash_insert(dev_net(in_dev->dev), ifa);
@ -617,10 +633,12 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
struct net *net = sock_net(skb->sk);
struct in_ifaddr __rcu **ifap;
struct nlattr *tb[IFA_MAX+1];
struct in_device *in_dev;
struct ifaddrmsg *ifm;
struct in_ifaddr *ifa, **ifap;
struct in_ifaddr *ifa;
int err = -EINVAL;
ASSERT_RTNL();
@ -637,7 +655,7 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
goto errout;
}
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
for (ifap = &in_dev->ifa_list; (ifa = rtnl_dereference(*ifap)) != NULL;
ifap = &ifa->ifa_next) {
if (tb[IFA_LOCAL] &&
ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL]))
@ -725,15 +743,20 @@ static void check_lifetime(struct work_struct *work)
if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
age >= ifa->ifa_valid_lft) {
struct in_ifaddr **ifap;
struct in_ifaddr __rcu **ifap;
struct in_ifaddr *tmp;
for (ifap = &ifa->ifa_dev->ifa_list;
*ifap != NULL; ifap = &(*ifap)->ifa_next) {
if (*ifap == ifa) {
ifap = &ifa->ifa_dev->ifa_list;
tmp = rtnl_dereference(*ifap);
while (tmp) {
tmp = rtnl_dereference(tmp->ifa_next);
if (rtnl_dereference(*ifap) == ifa) {
inet_del_ifa(ifa->ifa_dev,
ifap, 1);
break;
}
ifap = &tmp->ifa_next;
tmp = rtnl_dereference(*ifap);
}
} else if (ifa->ifa_preferred_lft !=
INFINITY_LIFE_TIME &&
@ -977,8 +1000,8 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
{
struct sockaddr_in sin_orig;
struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
struct in_ifaddr __rcu **ifap = NULL;
struct in_device *in_dev;
struct in_ifaddr **ifap = NULL;
struct in_ifaddr *ifa = NULL;
struct net_device *dev;
char *colon;
@ -1049,7 +1072,9 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
/* note: we only do this for a limited set of ioctls
and only if the original address family was AF_INET.
This is checked above. */
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
for (ifap = &in_dev->ifa_list;
(ifa = rtnl_dereference(*ifap)) != NULL;
ifap = &ifa->ifa_next) {
if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
sin_orig.sin_addr.s_addr ==
@ -1062,7 +1087,8 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
4.3BSD-style and passed in junk so we fall back to
comparing just the label */
if (!ifa) {
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
for (ifap = &in_dev->ifa_list;
(ifa = rtnl_dereference(*ifap)) != NULL;
ifap = &ifa->ifa_next)
if (!strcmp(ifr->ifr_name, ifa->ifa_label))
break;

View File

@ -354,11 +354,11 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
sdata_lock(sdata);
/* Copy the addresses to the bss_conf list */
ifa = idev->ifa_list;
ifa = rtnl_dereference(idev->ifa_list);
while (ifa) {
if (c < IEEE80211_BSS_ARP_ADDR_LIST_LEN)
bss_conf->arp_addr_list[c] = ifa->ifa_address;
ifa = ifa->ifa_next;
ifa = rtnl_dereference(ifa->ifa_next);
c++;
}

View File

@ -47,14 +47,16 @@ nf_nat_redirect_ipv4(struct sk_buff *skb,
if (hooknum == NF_INET_LOCAL_OUT) {
newdst = htonl(0x7F000001);
} else {
struct in_device *indev;
struct in_ifaddr *ifa;
const struct in_device *indev;
newdst = 0;
indev = __in_dev_get_rcu(skb->dev);
if (indev && indev->ifa_list) {
ifa = indev->ifa_list;
if (indev) {
const struct in_ifaddr *ifa;
ifa = rcu_dereference(indev->ifa_list);
if (ifa)
newdst = ifa->ifa_local;
}