The in_dev_for_each_ifa_rcu helper gets used so sparse won't complain when we add the proper __rcu annotation to the ifa_list member in struct in_device later.
While doing this I realized the helper only has one call site, so move it to where its needed. This then revealed that we allocate a temporary buffer needlessly and pass an always-false bool argument. So fold this into the calling function and fill dst buffer directly. Compile tested only. Cc: David Howells <dhowe...@redhat.com> Cc: linux-...@lists.infradead.org Signed-off-by: Florian Westphal <f...@strlen.de> --- fs/afs/Makefile | 1 - fs/afs/cmservice.c | 49 +++++++++++++++++++++++++++------------------ fs/afs/internal.h | 15 -------------- fs/afs/netdevices.c | 48 -------------------------------------------- 4 files changed, 29 insertions(+), 84 deletions(-) delete mode 100644 fs/afs/netdevices.c diff --git a/fs/afs/Makefile b/fs/afs/Makefile index cbf31f6cd177..10359bea7070 100644 --- a/fs/afs/Makefile +++ b/fs/afs/Makefile @@ -29,7 +29,6 @@ kafs-y := \ server.o \ server_list.o \ super.o \ - netdevices.o \ vlclient.o \ vl_list.o \ vl_probe.o \ diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index 01437cfe5432..054590a6b1e2 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c @@ -14,6 +14,8 @@ #include <linux/slab.h> #include <linux/sched.h> #include <linux/ip.h> +#include <linux/netdevice.h> +#include <linux/inetdevice.h> #include "internal.h" #include "afs_cm.h" #include "protocol_yfs.h" @@ -584,9 +586,10 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call) */ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work) { - struct afs_interface *ifs; + struct net_device *dev; + struct in_device *idev; struct afs_call *call = container_of(work, struct afs_call, work); - int loop, nifs; + int loop, nifs = 0; struct { struct /* InterfaceAddr */ { @@ -604,19 +607,7 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work) _enter(""); - nifs = 0; - ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL); - if (ifs) { - nifs = afs_get_ipv4_interfaces(call->net, ifs, 32, false); - if (nifs < 0) { - kfree(ifs); - ifs = NULL; - nifs = 0; - } - } - memset(&reply, 0, sizeof(reply)); - reply.ia.nifs = htonl(nifs); reply.ia.uuid[0] = call->net->uuid.time_low; reply.ia.uuid[1] = htonl(ntohs(call->net->uuid.time_mid)); @@ -626,15 +617,33 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work) for (loop = 0; loop < 6; loop++) reply.ia.uuid[loop + 5] = htonl((s8) call->net->uuid.node[loop]); - if (ifs) { - for (loop = 0; loop < nifs; loop++) { - reply.ia.ifaddr[loop] = ifs[loop].address.s_addr; - reply.ia.netmask[loop] = ifs[loop].netmask.s_addr; - reply.ia.mtu[loop] = htonl(ifs[loop].mtu); + rcu_read_lock(); + for_each_netdev_rcu(call->net->net, dev) { + const struct in_ifaddr *ifa; + + if (dev->flags & IFF_LOOPBACK) + continue; + + idev = __in_dev_get_rcu(dev); + if (!idev) + continue; + + in_dev_for_each_ifa_rcu(ifa, idev) { + if (ifa->ifa_flags & IFA_F_SECONDARY) + break; + + reply.ia.ifaddr[nifs] = ifa->ifa_address; + reply.ia.netmask[nifs] = ifa->ifa_mask; + reply.ia.mtu[nifs] = htonl(dev->mtu); + nifs++; + break; } - kfree(ifs); + if (nifs >= 32) + break; } + rcu_read_unlock(); + reply.ia.nifs = htonl(nifs); reply.cap.capcount = htonl(1); reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION); afs_send_simple_reply(call, &reply, sizeof(reply)); diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 2073c1a3ab4b..a22fa3b77b3c 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -724,15 +724,6 @@ struct afs_permits { struct afs_permit permits[]; /* List of permits sorted by key pointer */ }; -/* - * record of one of a system's set of network interfaces - */ -struct afs_interface { - struct in_addr address; /* IPv4 address bound to interface */ - struct in_addr netmask; /* netmask applied to address */ - unsigned mtu; /* MTU of interface */ -}; - /* * Error prioritisation and accumulation. */ @@ -1095,12 +1086,6 @@ extern const struct file_operations afs_mntpt_file_operations; extern struct vfsmount *afs_d_automount(struct path *); extern void afs_mntpt_kill_timer(void); -/* - * netdevices.c - */ -extern int afs_get_ipv4_interfaces(struct afs_net *, struct afs_interface *, - size_t, bool); - /* * proc.c */ diff --git a/fs/afs/netdevices.c b/fs/afs/netdevices.c deleted file mode 100644 index 2a009d1939d7..000000000000 --- a/fs/afs/netdevices.c +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* AFS network device helpers - * - * Copyright (c) 2007 Patrick McHardy <ka...@trash.net> - */ - -#include <linux/string.h> -#include <linux/rtnetlink.h> -#include <linux/inetdevice.h> -#include <linux/netdevice.h> -#include <linux/if_arp.h> -#include <net/net_namespace.h> -#include "internal.h" - -/* - * get a list of this system's interface IPv4 addresses, netmasks and MTUs - * - maxbufs must be at least 1 - * - returns the number of interface records in the buffer - */ -int afs_get_ipv4_interfaces(struct afs_net *net, struct afs_interface *bufs, - size_t maxbufs, bool wantloopback) -{ - struct net_device *dev; - struct in_device *idev; - int n = 0; - - ASSERT(maxbufs > 0); - - rtnl_lock(); - for_each_netdev(net->net, dev) { - if (dev->type == ARPHRD_LOOPBACK && !wantloopback) - continue; - idev = __in_dev_get_rtnl(dev); - if (!idev) - continue; - for_primary_ifa(idev) { - bufs[n].address.s_addr = ifa->ifa_address; - bufs[n].netmask.s_addr = ifa->ifa_mask; - bufs[n].mtu = dev->mtu; - n++; - if (n >= maxbufs) - goto out; - } endfor_ifa(idev); - } -out: - rtnl_unlock(); - return n; -} -- 2.21.0