* [RFC 2/4] Allow cdc_ncm to set MAC address in hardware
From: Charles.Hyde @ 2019-08-20 22:21 UTC (permalink / raw)
To: linux-usb, linux-acpi; +Cc: gregkh, Mario.Limonciello, oliver, netdev, nic_swsd
This patch adds support for pushing a MAC address out to USB based
ethernet controllers driven by cdc_ncm. With this change, ifconfig can
now set the device's MAC address. For example, the Dell Universal Dock
D6000 is driven by cdc_ncm. The D6000 can now have its MAC address set
by ifconfig, as it can be done in Windows. This was tested with a D6000
using ifconfig.
Signed-off-by: Charles Hyde <charles.hyde@dellteam.com>
Cc: Mario Limonciello <mario.limonciello@dell.com>
Cc: Oliver Neukum <oliver@neukum.org>
Cc: netdev@vger.kernel.org
Cc: linux-usb@vger.kernel.org
---
drivers/net/usb/cdc_ncm.c | 20 +++++++++++++++++++-
drivers/net/usb/usbnet.c | 37 ++++++++++++++++++++++++++++---------
include/linux/usb/usbnet.h | 1 +
3 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 50c05d0f44cb..f77c8672f972 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -750,6 +750,24 @@ int cdc_ncm_change_mtu(struct net_device *net, int new_mtu)
}
EXPORT_SYMBOL_GPL(cdc_ncm_change_mtu);
+/* Provide method to push MAC address to the USB device's ethernet controller.
+ */
+int cdc_ncm_set_mac_addr(struct net_device *net, void *p)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct sockaddr *addr = p;
+
+ memcpy(dev->net->dev_addr, addr->sa_data, ETH_ALEN);
+ /*
+ * Try to push the MAC address out to the device. Ignore any errors,
+ * to be compatible with prior versions of this source.
+ */
+ usbnet_set_ethernet_addr(dev);
+
+ return eth_mac_addr(net, p);
+}
+EXPORT_SYMBOL_GPL(cdc_ncm_set_mac_addr);
+
static const struct net_device_ops cdc_ncm_netdev_ops = {
.ndo_open = usbnet_open,
.ndo_stop = usbnet_stop,
@@ -757,7 +775,7 @@ static const struct net_device_ops cdc_ncm_netdev_ops = {
.ndo_tx_timeout = usbnet_tx_timeout,
.ndo_get_stats64 = usbnet_get_stats64,
.ndo_change_mtu = cdc_ncm_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_mac_address = cdc_ncm_set_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 72514c46b478..72bdac34b0ee 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -149,20 +149,39 @@ int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress)
int tmp = -1, ret;
unsigned char buf [13];
- ret = usb_string(dev->udev, iMACAddress, buf, sizeof buf);
- if (ret == 12)
- tmp = hex2bin(dev->net->dev_addr, buf, 6);
- if (tmp < 0) {
- dev_dbg(&dev->udev->dev,
- "bad MAC string %d fetch, %d\n", iMACAddress, tmp);
- if (ret >= 0)
- ret = -EINVAL;
- return ret;
+ ret = usb_get_address(dev->udev, buf);
+ if (ret == 6)
+ memcpy(dev->net->dev_addr, buf, 6);
+ else if (ret < 0) {
+ ret = usb_string(dev->udev, iMACAddress, buf, sizeof buf);
+ if (ret == 12)
+ tmp = hex2bin(dev->net->dev_addr, buf, 6);
+ if (tmp < 0) {
+ dev_dbg(&dev->udev->dev,
+ "bad MAC string %d fetch, %d\n", iMACAddress,
+ tmp);
+ if (ret >= 0)
+ ret = -EINVAL;
+ return ret;
+ }
}
return 0;
}
EXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr);
+int usbnet_set_ethernet_addr(struct usbnet *dev)
+{
+ int ret;
+
+ ret = usb_set_address(dev->udev, dev->net->dev_addr);
+ if (ret < 0) {
+ dev_dbg(&dev->udev->dev,
+ "bad MAC address put, %d\n", ret);
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usbnet_set_ethernet_addr);
+
static void intr_complete (struct urb *urb)
{
struct usbnet *dev = urb->context;
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index d8860f2d0976..f2b2c5ab5493 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -258,6 +258,7 @@ extern int usbnet_change_mtu(struct net_device *net, int new_mtu);
extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *);
extern int usbnet_get_ethernet_addr(struct usbnet *, int);
+extern int usbnet_set_ethernet_addr(struct usbnet *);
extern void usbnet_defer_kevent(struct usbnet *, int);
extern void usbnet_skb_return(struct usbnet *, struct sk_buff *);
extern void usbnet_unlink_rx_urbs(struct usbnet *);
--
2.20.1
^ permalink raw reply related
* [RFC 3/4] Move ACPI functionality out of r8152 driver
From: Charles.Hyde @ 2019-08-20 22:22 UTC (permalink / raw)
To: linux-usb, linux-acpi; +Cc: gregkh, Mario.Limonciello, oliver, netdev, nic_swsd
This change moves ACPI functionality out of the Realtek r8152 driver to
its own source and header file, making it available to other drivers as
needed now and into the future. At the time this ACPI snippet was
introduced in 2016, only the Realtek driver made use of it in support of
Dell's enterprise IT policy efforts. There comes now a need for this
same support in a different driver, also in support of Dell's enterprise
IT policy efforts.
Signed-off-by: Charles Hyde <charles.hyde@dellteam.com>
Cc: Mario Limonciello <mario.limonciello@dell.com>
Cc: Realtek linux nic maintainers <nic_swsd@realtek.com>
Cc: linux-usb@vger.kernel.org
Cc: linux-acpi@vger.kernel.org
---
drivers/net/usb/r8152.c | 44 ++++-------------------------------------
lib/Makefile | 3 ++-
2 files changed, 6 insertions(+), 41 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 0cc03a9ff545..b1dba3400b74 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -23,6 +23,7 @@
#include <linux/usb/cdc.h>
#include <linux/suspend.h>
#include <linux/acpi.h>
+#include <acpi/acpi_mac_passthru.h>
/* Information for net-next */
#define NETNEXT_VERSION "09"
@@ -1175,12 +1176,7 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
*/
static int vendor_mac_passthru_addr_read(struct r8152 *tp, struct sockaddr *sa)
{
- acpi_status status;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
- int ret = -EINVAL;
u32 ocp_data;
- unsigned char buf[6];
/* test for -AD variant of RTL8153 */
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0);
@@ -1201,39 +1197,7 @@ static int vendor_mac_passthru_addr_read(struct r8152 *tp, struct sockaddr *sa)
return -ENODEV;
}
}
-
- /* returns _AUXMAC_#AABBCCDDEEFF# */
- status = acpi_evaluate_object(NULL, "\\_SB.AMAC", NULL, &buffer);
- obj = (union acpi_object *)buffer.pointer;
- if (!ACPI_SUCCESS(status))
- return -ENODEV;
- if (obj->type != ACPI_TYPE_BUFFER || obj->string.length != 0x17) {
- netif_warn(tp, probe, tp->netdev,
- "Invalid buffer for pass-thru MAC addr: (%d, %d)\n",
- obj->type, obj->string.length);
- goto amacout;
- }
- if (strncmp(obj->string.pointer, "_AUXMAC_#", 9) != 0 ||
- strncmp(obj->string.pointer + 0x15, "#", 1) != 0) {
- netif_warn(tp, probe, tp->netdev,
- "Invalid header when reading pass-thru MAC addr\n");
- goto amacout;
- }
- ret = hex2bin(buf, obj->string.pointer + 9, 6);
- if (!(ret == 0 && is_valid_ether_addr(buf))) {
- netif_warn(tp, probe, tp->netdev,
- "Invalid MAC for pass-thru MAC addr: %d, %pM\n",
- ret, buf);
- ret = -EINVAL;
- goto amacout;
- }
- memcpy(sa->sa_data, buf, 6);
- netif_info(tp, probe, tp->netdev,
- "Using pass-thru MAC addr %pM\n", sa->sa_data);
-
-amacout:
- kfree(obj);
- return ret;
+ return get_acpi_mac_passthru(&tp->intf->dev, sa);
}
static int determine_ethernet_addr(struct r8152 *tp, struct sockaddr *sa)
@@ -4309,10 +4273,10 @@ static int rtl8152_post_reset(struct usb_interface *intf)
if (!tp)
return 0;
- /* reset the MAC adddress in case of policy change */
+ /* reset the MAC address in case of policy change */
if (determine_ethernet_addr(tp, &sa) >= 0) {
rtnl_lock();
- dev_set_mac_address (tp->netdev, &sa, NULL);
+ dev_set_mac_address(tp->netdev, &sa, NULL);
rtnl_unlock();
}
diff --git a/lib/Makefile b/lib/Makefile
index 29c02a924973..a902bec0ac65 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -35,7 +35,8 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
flex_proportions.o ratelimit.o show_mem.o \
is_single_threaded.o plist.o decompress.o kobject_uevent.o \
earlycpio.o seq_buf.o siphash.o dec_and_lock.o \
- nmi_backtrace.o nodemask.o win_minmax.o memcat_p.o
+ nmi_backtrace.o nodemask.o win_minmax.o memcat_p.o \
+ acpi_mac_passthru.o
lib-$(CONFIG_PRINTK) += dump_stack.o
lib-$(CONFIG_MMU) += ioremap.o
--
2.20.1
^ permalink raw reply related
* [RFC 4/4] net: cdc_ncm: Add ACPI MAC address pass through functionality
From: Charles.Hyde @ 2019-08-20 22:23 UTC (permalink / raw)
To: linux-usb, linux-acpi; +Cc: gregkh, Mario.Limonciello, oliver, netdev, nic_swsd
This change adds support to cdc_ncm for ACPI MAC address pass through
functionality that also exists in the Realtek r8152 driver. This is in
support of Dell's Universal Dock D6000, to give it the same feature
capability as is currently available in Windows and advertized on Dell's
product web site.
Signed-off-by: Charles Hyde <charles.hyde@dellteam.com>
Cc: Mario Limonciello <mario.limonciello@dell.com>
Cc: Oliver Neukum <oliver@neukum.org>
Cc: linux-usb@vger.kernel.org
---
drivers/net/usb/cdc_ncm.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index f77c8672f972..1f046acca6fc 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -52,6 +52,7 @@
#include <linux/usb/usbnet.h>
#include <linux/usb/cdc.h>
#include <linux/usb/cdc_ncm.h>
+#include <acpi/acpi_mac_passthru.h>
#if IS_ENABLED(CONFIG_USB_NET_CDC_MBIM)
static bool prefer_mbim = true;
@@ -930,11 +931,18 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
usb_set_intfdata(ctx->control, dev);
if (ctx->ether_desc) {
+ struct sockaddr sa;
+
temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress);
if (temp) {
dev_dbg(&intf->dev, "failed to get mac address\n");
goto error2;
}
+ if (get_acpi_mac_passthru(&intf->dev, &sa) == 0) {
+ memcpy(dev->net->dev_addr, sa.sa_data, ETH_ALEN);
+ if (usbnet_set_ethernet_addr(dev) < 0)
+ usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress);
+ }
dev_info(&intf->dev, "MAC-Address: %pM\n", dev->net->dev_addr);
}
--
2.20.1
^ permalink raw reply related
* Re: [RFC 1/4] Add usb_get_address and usb_set_address support
From: Greg KH @ 2019-08-20 22:26 UTC (permalink / raw)
To: Charles.Hyde
Cc: linux-usb, linux-acpi, Mario.Limonciello, oliver, netdev,
nic_swsd
In-Reply-To: <1566339522507.45056@Dellteam.com>
On Tue, Aug 20, 2019 at 10:18:42PM +0000, Charles.Hyde@dellteam.com wrote:
> The core USB driver message.c is missing get/set address functionality
> that stops ifconfig from being able to push MAC addresses out to USB
> based ethernet devices. Without this functionality, some USB devices
> stop responding to ethernet packets when using ifconfig to change MAC
> addresses. This has been tested with a Dell Universal Dock D6000.
>
> Signed-off-by: Charles Hyde <charles.hyde@dellteam.com>
> Cc: Mario Limonciello <mario.limonciello@dell.com>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: linux-usb@vger.kernel.org
> ---
> drivers/usb/core/message.c | 59 ++++++++++++++++++++++++++++++++++++++
> include/linux/usb.h | 3 ++
> 2 files changed, 62 insertions(+)
>
> diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
> index 5adf489428aa..eea775234b09 100644
> --- a/drivers/usb/core/message.c
> +++ b/drivers/usb/core/message.c
> @@ -1085,6 +1085,65 @@ int usb_clear_halt(struct usb_device *dev, int pipe)
> }
> EXPORT_SYMBOL_GPL(usb_clear_halt);
>
> +/**
> + * usb_get_address -
trailing whitespace?
No description of what the function does?
> + * @dev: device whose endpoint is halted
> + * @mac: buffer for containing
Trailing whitespace?
> + * Context: !in_interrupt ()
> + *
> + * This will attempt to get the six byte MAC address from a USB device's
> + * ethernet controller using GET_NET_ADDRESS command.
> + *
> + * This call is synchronous, and may not be used in an interrupt context.
> + *
> + * Return: Zero on success, or else the status code returned by the
> + * underlying usb_control_msg() call.
> + */
> +int usb_get_address(struct usb_device *dev, unsigned char * mac)
> +{
> + int ret = -ENOMEM;
> + unsigned char *tbuf = kmalloc(256, GFP_NOIO);
> +
> + if (!tbuf)
> + return -ENOMEM;
> +
> + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
> + USB_CDC_GET_NET_ADDRESS,
> + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
> + 0, USB_REQ_SET_ADDRESS, tbuf, 256,
> + USB_CTRL_GET_TIMEOUT);
> + if (ret == 6)
> + memcpy(mac, tbuf, 6);
> +
> + kfree(tbuf);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(usb_get_address);
This is a VERY cdc-net-specific function. It is not a "generic" USB
function at all. Why does it belong in the USB core? Shouldn't it live
in the code that handles the other cdc-net-specific logic?
thanks,
greg k-h
^ permalink raw reply
* RE: [PATCH] net/ncsi: add control packet payload to NC-SI commands from netlink
From: Ben Wei @ 2019-08-20 22:26 UTC (permalink / raw)
To: Justin.Lee1@Dell.com
Cc: netdev@vger.kernel.org, openbmc@lists.ozlabs.org,
linux-kernel@vger.kernel.org, sam@mendozajonas.com,
davem@davemloft.net, dkodihal@linux.vnet.ibm.com
In-Reply-To: <b862e3168f5b4a6eaf005d6b24950795@AUSX13MPS302.AMER.DELL.COM>
> Hi Ben,
>
> > Hi Justin,
> >
> > > Hi Ben,
> > >
> > > I have similar fix locally with different approach as the command handler may have some expectation for those byes.
> > > We can use NCSI_PKT_CMD_OEM handler as it only copies data based on the payload length.
> >
> > Great! Yes I was thinking the same, we just need some way to take data payload sent from netlink message and sent it over NC-SI.
> >
> > >
> > > diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c index 5c3fad8..3b01f65 100644
> > > --- a/net/ncsi/ncsi-cmd.c
> > > +++ b/net/ncsi/ncsi-cmd.c
> > > @@ -309,14 +309,19 @@ static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca)
> > >
> > > int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca) {
> > > + struct ncsi_cmd_handler *nch = NULL;
> > > struct ncsi_request *nr;
> > > + unsigned char type;
> > > struct ethhdr *eh;
> > > - struct ncsi_cmd_handler *nch = NULL;
> > > int i, ret;
> > >
> > > + if (nca->req_flags == NCSI_REQ_FLAG_NETLINK_DRIVEN)
> > > + type = NCSI_PKT_CMD_OEM;
> > > + else
> > > + type = nca->type;
> > > /* Search for the handler */
> > > for (i = 0; i < ARRAY_SIZE(ncsi_cmd_handlers); i++) {
> > > - if (ncsi_cmd_handlers[i].type == nca->type) {
> > > + if (ncsi_cmd_handlers[i].type == type) {
> > > if (ncsi_cmd_handlers[i].handler)
> > > nch = &ncsi_cmd_handlers[i];
> > > else
> > >
> >
> > So in this case NCSI_PKT_CMD_OEM would be the default handler for all NC-SI command over netlink (standard and OEM), correct?
> Yes, that is correct. The handler for NCSI_PKT_CMD_OEM command is generic.
>
> > Should we rename this to something like NCSI_PKT_CMD_GENERIC for clarity perhaps? Do you plan to upstream this patch?
> NCSI_PKT_CMD_OEM is a real command type and it is defined by the NC-SI specific.
> We can add comments to indicate that we use the generic command handler from NCSI_PKT_CMD_OEM command.
>
> Does the change work for you? If so, I will prepare the patch.
Thanks Justin. I verified this change and it works, thanks!
-Ben
^ permalink raw reply
* Re: libbpf distro packaging
From: Julia Kartseva @ 2019-08-20 22:27 UTC (permalink / raw)
To: Andrii Nakryiko, Jiri Olsa
Cc: labbott@redhat.com, acme@kernel.org,
debian-kernel@lists.debian.org, netdev@vger.kernel.org,
Andrii Nakryiko, Andrey Ignatov, Alexei Starovoitov,
Yonghong Song, jolsa@kernel.org
In-Reply-To: <FA139BA4-59E5-43C7-8E72-C7B2FC1C449E@fb.com>
On 8/19/19, 11:08 AM, "Julia Kartseva" <hex@fb.com> wrote:
On 8/13/19, 11:24 AM, "Andrii Nakryiko" <andrii.nakryiko@gmail.com> wrote:
On Tue, Aug 13, 2019 at 5:26 AM Jiri Olsa <jolsa@redhat.com> wrote:
>
> On Mon, Aug 12, 2019 at 07:04:12PM +0000, Julia Kartseva wrote:
> > I would like to bring up libbpf publishing discussion started at [1].
> > The present state of things is that libbpf is built from kernel tree, e.g. [2]
> > For Debian and [3] for Fedora whereas the better way would be having a
> > package built from github mirror. The advantages of the latter:
> > - Consistent, ABI matching versioning across distros
> > - The mirror has integration tests
> > - No need in kernel tree to build a package
> > - Changes can be merged directly to github w/o waiting them to be merged
> > through bpf-next -> net-next -> main
> > There is a PR introducing a libbpf.spec which can be used as a starting point: [4]
> > Any comments regarding the spec itself can be posted there.
> > In the future it may be used as a source of truth.
> > Please consider switching libbpf packaging to the github mirror instead
> > of the kernel tree.
> > Thanks
> >
> > [1] https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.iovisor.org_g_iovisor-2Ddev_message_1521&d=DwIBaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=zUrDY_Sp_5PqcGtRQPNeDA&m=prYVDiu3-aH1o2PWH4ZcP7lEQRCQAcTwcWPrJrtaroQ&s=dYAc2jLhFg0wtCZ_ms2HF5bWANoHzA3UMug5TNCeBtE&e=
> > [2] https://urldefense.proofpoint.com/v2/url?u=https-3A__packages.debian.org_sid_libbpf4.19&d=DwIBaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=zUrDY_Sp_5PqcGtRQPNeDA&m=prYVDiu3-aH1o2PWH4ZcP7lEQRCQAcTwcWPrJrtaroQ&s=lq1MpF-bt6y6ZEtFc57eT-BO_wMBx8uUBACJooWbUYk&e=
> > [3] https://urldefense.proofpoint.com/v2/url?u=http-3A__rpmfind.net_linux_RPM_fedora_devel_rawhide_x86-5F64_l_libbpf-2D5.3.0-2D0.rc2.git0.1.fc31.x86-5F64.html&d=DwIBaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=zUrDY_Sp_5PqcGtRQPNeDA&m=prYVDiu3-aH1o2PWH4ZcP7lEQRCQAcTwcWPrJrtaroQ&s=NoolYHL57G2KhzE768iWdy6v5LD2GfJQyqPmtjy196E&e=
> > [4] https://github.com/libbpf/libbpf/pull/64
>
> hi,
> Fedora has libbpf as kernel-tools subpackage, so I think
> we'd need to create new package and deprecate the current
>
> but I like the ABI stability by using github .. how's actually
> the sync (in both directions) with kernel sources going on?
Sync is always in one direction, from kernel sources into Github repo.
Right now it's triggered by a human (usually me), but we are using a
script that automates entire process (see
https://github.com/libbpf/libbpf/blob/master/scripts/sync-kernel.sh).
It cherry-pick relevant commits from kernel, transforms them to match
Github's file layout and re-applies those changes to Github repo.
There is never a sync from Github back to kernel, but Github repo
contains some extra stuff that's not in kernel. E.g., the script I
mentioned, plus Github's Makefile is different, because it can't rely
on kernel's kbuild setup.
Hi Jiri,
I'm curious if you have any comments regarding sync procedure described
By Andrii. Or if there is anything else you'd like us to address so Fedora
can be switched to libbpf built from the github mirror?
Thank you
>
> thanks,
> jirka
^ permalink raw reply
* Re: [RFC 1/4] Add usb_get_address and usb_set_address support
From: Greg KH @ 2019-08-20 22:28 UTC (permalink / raw)
To: Charles.Hyde
Cc: linux-usb, linux-acpi, Mario.Limonciello, oliver, netdev,
nic_swsd
In-Reply-To: <1566339522507.45056@Dellteam.com>
On Tue, Aug 20, 2019 at 10:18:42PM +0000, Charles.Hyde@dellteam.com wrote:
> +int usb_get_address(struct usb_device *dev, unsigned char * mac)
> +{
> + int ret = -ENOMEM;
> + unsigned char *tbuf = kmalloc(256, GFP_NOIO);
On a technical level, why are you asking for 256 bytes here, and in the
control message, yet assuming you will only get 6 back for a correct
message? Shouldn't you be only asking for 6 bytes?
> +
> + if (!tbuf)
> + return -ENOMEM;
> +
> + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
> + USB_CDC_GET_NET_ADDRESS,
> + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
> + 0, USB_REQ_SET_ADDRESS, tbuf, 256,
> + USB_CTRL_GET_TIMEOUT);
> + if (ret == 6)
> + memcpy(mac, tbuf, 6);
> +
> + kfree(tbuf);
> + return ret;
So if 100 is returned by the device (not likely, but let's say 7), then
you return 7 bytes, yet you did not copy the data into the pointer given
to you.
SHouldn't you report a real error for when this happens (hint, it will.)
thanks,
greg k-h
^ permalink raw reply
* [PATCH 12/38] mwifiex: Convert ack_status_frames to XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Straightforward locking conversion; the only two points of note is that we
can't pass the address of the tx_token_id to xa_alloc() because it's too
small (an unsigned char), and mwifiex_free_ack_frame() becomes inlined
into its caller.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
drivers/net/wireless/marvell/mwifiex/init.c | 4 ++--
drivers/net/wireless/marvell/mwifiex/main.c | 10 ++++------
drivers/net/wireless/marvell/mwifiex/main.h | 4 +---
drivers/net/wireless/marvell/mwifiex/txrx.c | 4 +---
drivers/net/wireless/marvell/mwifiex/wmm.c | 15 ++++++---------
5 files changed, 14 insertions(+), 23 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c
index 6c0e52eb8794..03e43077ae45 100644
--- a/drivers/net/wireless/marvell/mwifiex/init.c
+++ b/drivers/net/wireless/marvell/mwifiex/init.c
@@ -477,8 +477,8 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
spin_lock_init(&priv->tx_ba_stream_tbl_lock);
spin_lock_init(&priv->rx_reorder_tbl_lock);
- spin_lock_init(&priv->ack_status_lock);
- idr_init(&priv->ack_status_frames);
+ xa_init_flags(&priv->ack_status_frames,
+ XA_FLAGS_ALLOC1 | XA_FLAGS_LOCK_BH);
}
return 0;
diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c
index a9657ae6d782..0587bd7c8a13 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.c
+++ b/drivers/net/wireless/marvell/mwifiex/main.c
@@ -822,14 +822,12 @@ mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
skb = skb_clone(skb, GFP_ATOMIC);
if (skb) {
- int id;
+ int err, id;
- spin_lock_bh(&priv->ack_status_lock);
- id = idr_alloc(&priv->ack_status_frames, orig_skb,
- 1, 0x10, GFP_ATOMIC);
- spin_unlock_bh(&priv->ack_status_lock);
+ err = xa_alloc_bh(&priv->ack_status_frames, &id, orig_skb,
+ XA_LIMIT(1, 0xf), GFP_ATOMIC);
- if (id >= 0) {
+ if (err == 0) {
tx_info = MWIFIEX_SKB_TXCB(skb);
tx_info->ack_frame_id = id;
tx_info->flags |= flag;
diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
index 095837fba300..5e06bc9d9519 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
@@ -682,9 +682,7 @@ struct mwifiex_private {
u8 check_tdls_tx;
struct timer_list auto_tdls_timer;
bool auto_tdls_timer_active;
- struct idr ack_status_frames;
- /* spin lock for ack status */
- spinlock_t ack_status_lock;
+ struct xarray ack_status_frames;
/** rx histogram data */
struct mwifiex_histogram_data *hist_data;
struct cfg80211_chan_def dfs_chandef;
diff --git a/drivers/net/wireless/marvell/mwifiex/txrx.c b/drivers/net/wireless/marvell/mwifiex/txrx.c
index e3c1446dd847..b2ef30d9f26d 100644
--- a/drivers/net/wireless/marvell/mwifiex/txrx.c
+++ b/drivers/net/wireless/marvell/mwifiex/txrx.c
@@ -339,9 +339,7 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
if (!tx_status->tx_token_id)
return;
- spin_lock_bh(&priv->ack_status_lock);
- ack_skb = idr_remove(&priv->ack_status_frames, tx_status->tx_token_id);
- spin_unlock_bh(&priv->ack_status_lock);
+ ack_skb = xa_erase_bh(&priv->ack_status_frames, tx_status->tx_token_id);
if (ack_skb) {
tx_info = MWIFIEX_SKB_TXCB(ack_skb);
diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c
index 41f0231376c0..64ff6ac3889b 100644
--- a/drivers/net/wireless/marvell/mwifiex/wmm.c
+++ b/drivers/net/wireless/marvell/mwifiex/wmm.c
@@ -562,13 +562,6 @@ static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv)
}
}
-static int mwifiex_free_ack_frame(int id, void *p, void *data)
-{
- pr_warn("Have pending ack frames!\n");
- kfree_skb(p);
- return 0;
-}
-
/*
* This function cleans up the Tx and Rx queues.
*
@@ -582,6 +575,7 @@ static int mwifiex_free_ack_frame(int id, void *p, void *data)
void
mwifiex_clean_txrx(struct mwifiex_private *priv)
{
+ unsigned long index;
struct sk_buff *skb, *tmp;
mwifiex_11n_cleanup_reorder_tbl(priv);
@@ -612,8 +606,11 @@ mwifiex_clean_txrx(struct mwifiex_private *priv)
}
atomic_set(&priv->adapter->bypass_tx_pending, 0);
- idr_for_each(&priv->ack_status_frames, mwifiex_free_ack_frame, NULL);
- idr_destroy(&priv->ack_status_frames);
+ xa_for_each(&priv->ack_status_frames, index, skb) {
+ WARN_ONCE(1, "Have pending ack frames!\n");
+ kfree_skb(skb);
+ }
+ xa_destroy(&priv->ack_status_frames);
}
/*
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 22/38] sctp: Convert sctp_assocs_id to XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
This is a fairly straightforward conversion. The load side could be
converted to RCU by appropriate handling of races between delete and
lookup (eg RCU-freeing the sctp_association). One point to note is
that sctp_assoc_set_id() will now return 1 if the allocation wrapped;
I have converted the callers to check for an error using '< 0' instead
of '!= 0'.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
include/net/sctp/sctp.h | 5 ++---
net/sctp/associola.c | 34 +++++++++-------------------------
net/sctp/protocol.c | 6 ------
net/sctp/sm_make_chunk.c | 2 +-
net/sctp/socket.c | 6 +++---
5 files changed, 15 insertions(+), 38 deletions(-)
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 5d60f13d2347..4bcce5d052d1 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -47,7 +47,7 @@
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/jiffies.h>
-#include <linux/idr.h>
+#include <linux/xarray.h>
#if IS_ENABLED(CONFIG_IPV6)
#include <net/ipv6.h>
@@ -462,8 +462,7 @@ extern struct proto sctp_prot;
extern struct proto sctpv6_prot;
void sctp_put_port(struct sock *sk);
-extern struct idr sctp_assocs_id;
-extern spinlock_t sctp_assocs_id_lock;
+extern struct xarray sctp_assocs_id;
/* Static inline functions. */
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 5010cce52c93..4d6baecbdb99 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -39,6 +39,9 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
+DEFINE_XARRAY_FLAGS(sctp_assocs_id, XA_FLAGS_ALLOC1 | XA_FLAGS_LOCK_BH);
+static u32 sctp_assocs_next_id;
+
/* Forward declarations for internal functions. */
static void sctp_select_active_and_retran_path(struct sctp_association *asoc);
static void sctp_assoc_bh_rcv(struct work_struct *work);
@@ -412,11 +415,8 @@ static void sctp_association_destroy(struct sctp_association *asoc)
sctp_endpoint_put(asoc->ep);
sock_put(asoc->base.sk);
- if (asoc->assoc_id != 0) {
- spin_lock_bh(&sctp_assocs_id_lock);
- idr_remove(&sctp_assocs_id, asoc->assoc_id);
- spin_unlock_bh(&sctp_assocs_id_lock);
- }
+ if (asoc->assoc_id != 0)
+ xa_erase_bh(&sctp_assocs_id, asoc->assoc_id);
WARN_ON(atomic_read(&asoc->rmem_alloc));
@@ -1177,7 +1177,7 @@ int sctp_assoc_update(struct sctp_association *asoc,
sctp_stream_update(&asoc->stream, &new->stream);
/* get a new assoc id if we don't have one yet. */
- if (sctp_assoc_set_id(asoc, GFP_ATOMIC))
+ if (sctp_assoc_set_id(asoc, GFP_ATOMIC) < 0)
return -ENOMEM;
}
@@ -1624,29 +1624,13 @@ int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
/* Set an association id for a given association */
int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp)
{
- bool preload = gfpflags_allow_blocking(gfp);
- int ret;
-
/* If the id is already assigned, keep it. */
if (asoc->assoc_id)
return 0;
- if (preload)
- idr_preload(gfp);
- spin_lock_bh(&sctp_assocs_id_lock);
- /* 0, 1, 2 are used as SCTP_FUTURE_ASSOC, SCTP_CURRENT_ASSOC and
- * SCTP_ALL_ASSOC, so an available id must be > SCTP_ALL_ASSOC.
- */
- ret = idr_alloc_cyclic(&sctp_assocs_id, asoc, SCTP_ALL_ASSOC + 1, 0,
- GFP_NOWAIT);
- spin_unlock_bh(&sctp_assocs_id_lock);
- if (preload)
- idr_preload_end();
- if (ret < 0)
- return ret;
-
- asoc->assoc_id = (sctp_assoc_t)ret;
- return 0;
+ return xa_alloc_cyclic_bh(&sctp_assocs_id, &asoc->assoc_id, asoc,
+ XA_LIMIT(SCTP_ALL_ASSOC + 1, INT_MAX),
+ &sctp_assocs_next_id, gfp);
}
/* Free the ASCONF queue */
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 2d47adcb4cbe..79ccc786e5c9 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -50,9 +50,6 @@
/* Global data structures. */
struct sctp_globals sctp_globals __read_mostly;
-struct idr sctp_assocs_id;
-DEFINE_SPINLOCK(sctp_assocs_id_lock);
-
static struct sctp_pf *sctp_pf_inet6_specific;
static struct sctp_pf *sctp_pf_inet_specific;
static struct sctp_af *sctp_af_v4_specific;
@@ -1388,9 +1385,6 @@ static __init int sctp_init(void)
sctp_max_instreams = SCTP_DEFAULT_INSTREAMS;
sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS;
- /* Initialize handle used for association ids. */
- idr_init(&sctp_assocs_id);
-
limit = nr_free_buffer_pages() / 8;
limit = max(limit, 128UL);
sysctl_sctp_mem[0] = limit / 4 * 3;
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 36bd8a6e82df..f049cfad6cf8 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -2443,7 +2443,7 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,
/* Update frag_point when stream_interleave may get changed. */
sctp_assoc_update_frag_point(asoc);
- if (!asoc->temp && sctp_assoc_set_id(asoc, gfp))
+ if (!asoc->temp && sctp_assoc_set_id(asoc, gfp) < 0)
goto clean_up;
/* ADDIP Section 4.1 ASCONF Chunk Procedures
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 12503e16fa96..0df05adfd033 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -236,11 +236,11 @@ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
if (id <= SCTP_ALL_ASSOC)
return NULL;
- spin_lock_bh(&sctp_assocs_id_lock);
- asoc = (struct sctp_association *)idr_find(&sctp_assocs_id, (int)id);
+ xa_lock_bh(&sctp_assocs_id);
+ asoc = xa_load(&sctp_assocs_id, id);
if (asoc && (asoc->base.sk != sk || asoc->base.dead))
asoc = NULL;
- spin_unlock_bh(&sctp_assocs_id_lock);
+ xa_unlock_bh(&sctp_assocs_id);
return asoc;
}
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 23/38] cls_api: Convert tcf_net to XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
This module doesn't use the allocating functionality; convert it to a
plain XArray instead of an allocating one. I've left struct tcf_net
in place in case more objects are added to it in future, although
it now only contains an XArray. We don't need to call xa_destroy()
if the array is empty, so I've removed the contents of tcf_net_exit()
-- if it can be called with entries still in place, then it shoud call
xa_destroy() instead.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
net/sched/cls_api.c | 27 ++++++---------------------
1 file changed, 6 insertions(+), 21 deletions(-)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index e0d8b456e9f5..8392a7ef0ed4 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -19,7 +19,7 @@
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/slab.h>
-#include <linux/idr.h>
+#include <linux/xarray.h>
#include <linux/rhashtable.h>
#include <net/net_namespace.h>
#include <net/sock.h>
@@ -777,8 +777,7 @@ tcf_chain0_head_change_cb_del(struct tcf_block *block,
}
struct tcf_net {
- spinlock_t idr_lock; /* Protects idr */
- struct idr idr;
+ struct xarray blocks;
};
static unsigned int tcf_net_id;
@@ -787,25 +786,15 @@ static int tcf_block_insert(struct tcf_block *block, struct net *net,
struct netlink_ext_ack *extack)
{
struct tcf_net *tn = net_generic(net, tcf_net_id);
- int err;
-
- idr_preload(GFP_KERNEL);
- spin_lock(&tn->idr_lock);
- err = idr_alloc_u32(&tn->idr, block, &block->index, block->index,
- GFP_NOWAIT);
- spin_unlock(&tn->idr_lock);
- idr_preload_end();
- return err;
+ return xa_insert(&tn->blocks, block->index, block, GFP_KERNEL);
}
static void tcf_block_remove(struct tcf_block *block, struct net *net)
{
struct tcf_net *tn = net_generic(net, tcf_net_id);
- spin_lock(&tn->idr_lock);
- idr_remove(&tn->idr, block->index);
- spin_unlock(&tn->idr_lock);
+ xa_erase(&tn->blocks, block->index);
}
static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
@@ -839,7 +828,7 @@ static struct tcf_block *tcf_block_lookup(struct net *net, u32 block_index)
{
struct tcf_net *tn = net_generic(net, tcf_net_id);
- return idr_find(&tn->idr, block_index);
+ return xa_load(&tn->blocks, block_index);
}
static struct tcf_block *tcf_block_refcnt_get(struct net *net, u32 block_index)
@@ -3164,16 +3153,12 @@ static __net_init int tcf_net_init(struct net *net)
{
struct tcf_net *tn = net_generic(net, tcf_net_id);
- spin_lock_init(&tn->idr_lock);
- idr_init(&tn->idr);
+ xa_init(&tn->blocks);
return 0;
}
static void __net_exit tcf_net_exit(struct net *net)
{
- struct tcf_net *tn = net_generic(net, tcf_net_id);
-
- idr_destroy(&tn->idr);
}
static struct pernet_operations tcf_net_ops = {
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 29/38] cls_flower: Convert handle_idr to XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Inline __fl_get() into fl_get(). Use the RCU lock explicitly for
lookups and walks instead of relying on RTNL. The xa_lock protects us,
but remains nested under the RTNL for now.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
net/sched/cls_flower.c | 54 ++++++++++++++++++++----------------------
1 file changed, 26 insertions(+), 28 deletions(-)
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index 054123742e32..54026c9e9b05 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -91,7 +91,7 @@ struct cls_fl_head {
struct list_head masks;
struct list_head hw_filters;
struct rcu_work rwork;
- struct idr handle_idr;
+ struct xarray filters;
};
struct cls_fl_filter {
@@ -334,7 +334,7 @@ static int fl_init(struct tcf_proto *tp)
INIT_LIST_HEAD_RCU(&head->masks);
INIT_LIST_HEAD(&head->hw_filters);
rcu_assign_pointer(tp->root, head);
- idr_init(&head->handle_idr);
+ xa_init_flags(&head->filters, XA_FLAGS_ALLOC1);
return rhashtable_init(&head->ht, &mask_ht_params);
}
@@ -530,19 +530,6 @@ static void __fl_put(struct cls_fl_filter *f)
__fl_destroy_filter(f);
}
-static struct cls_fl_filter *__fl_get(struct cls_fl_head *head, u32 handle)
-{
- struct cls_fl_filter *f;
-
- rcu_read_lock();
- f = idr_find(&head->handle_idr, handle);
- if (f && !refcount_inc_not_zero(&f->refcnt))
- f = NULL;
- rcu_read_unlock();
-
- return f;
-}
-
static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
bool *last, bool rtnl_held,
struct netlink_ext_ack *extack)
@@ -560,7 +547,7 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
f->deleted = true;
rhashtable_remove_fast(&f->mask->ht, &f->ht_node,
f->mask->filter_ht_params);
- idr_remove(&head->handle_idr, f->handle);
+ xa_erase(&head->filters, f->handle);
list_del_rcu(&f->list);
spin_unlock(&tp->lock);
@@ -599,7 +586,7 @@ static void fl_destroy(struct tcf_proto *tp, bool rtnl_held,
break;
}
}
- idr_destroy(&head->handle_idr);
+ xa_destroy(&head->filters);
__module_get(THIS_MODULE);
tcf_queue_work(&head->rwork, fl_destroy_sleepable);
@@ -615,8 +602,15 @@ static void fl_put(struct tcf_proto *tp, void *arg)
static void *fl_get(struct tcf_proto *tp, u32 handle)
{
struct cls_fl_head *head = fl_head_dereference(tp);
+ struct cls_fl_filter *f;
+
+ rcu_read_lock();
+ f = xa_load(&head->filters, handle);
+ if (f && !refcount_inc_not_zero(&f->refcnt))
+ f = NULL;
+ rcu_read_unlock();
- return __fl_get(head, handle);
+ return f;
}
static const struct nla_policy fl_policy[TCA_FLOWER_MAX + 1] = {
@@ -1663,7 +1657,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
rhashtable_remove_fast(&fold->mask->ht,
&fold->ht_node,
fold->mask->filter_ht_params);
- idr_replace(&head->handle_idr, fnew, fnew->handle);
+ xa_store(&head->filters, fnew->handle, fnew, 0);
list_replace_rcu(&fold->list, &fnew->list);
fold->deleted = true;
@@ -1681,8 +1675,9 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
} else {
if (handle) {
/* user specifies a handle and it doesn't exist */
- err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
- handle, GFP_ATOMIC);
+ fnew->handle = handle;
+ err = xa_insert(&head->filters, handle, fnew,
+ GFP_ATOMIC);
/* Filter with specified handle was concurrently
* inserted after initial check in cls_api. This is not
@@ -1690,18 +1685,16 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
* message flags. Returning EAGAIN will cause cls_api to
* try to update concurrently inserted rule.
*/
- if (err == -ENOSPC)
+ if (err == -EBUSY)
err = -EAGAIN;
} else {
- handle = 1;
- err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
- INT_MAX, GFP_ATOMIC);
+ err = xa_alloc(&head->filters, &fnew->handle, fnew,
+ xa_limit_31b, GFP_ATOMIC);
}
if (err)
goto errout_hw;
refcount_inc(&fnew->refcnt);
- fnew->handle = handle;
list_add_tail_rcu(&fnew->list, &fnew->mask->filters);
spin_unlock(&tp->lock);
}
@@ -1755,23 +1748,28 @@ static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg,
bool rtnl_held)
{
struct cls_fl_head *head = fl_head_dereference(tp);
- unsigned long id = arg->cookie, tmp;
+ unsigned long id;
struct cls_fl_filter *f;
arg->count = arg->skip;
- idr_for_each_entry_continue_ul(&head->handle_idr, f, tmp, id) {
+ rcu_read_lock();
+ xa_for_each_start(&head->filters, id, f, arg->cookie) {
/* don't return filters that are being deleted */
if (!refcount_inc_not_zero(&f->refcnt))
continue;
+ rcu_read_unlock();
if (arg->fn(tp, f, arg) < 0) {
__fl_put(f);
arg->stop = 1;
+ rcu_read_lock();
break;
}
__fl_put(f);
arg->count++;
+ rcu_read_lock();
}
+ rcu_read_unlock();
arg->cookie = id;
}
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 33/38] act_api: Convert action_idr to XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Replace the mutex protecting the IDR with the XArray spinlock.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
include/net/act_api.h | 6 +-
net/sched/act_api.c | 127 +++++++++++++++++-------------------------
2 files changed, 53 insertions(+), 80 deletions(-)
diff --git a/include/net/act_api.h b/include/net/act_api.h
index c61a1bf4e3de..da1a515fd94d 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -13,8 +13,7 @@
#include <net/netns/generic.h>
struct tcf_idrinfo {
- struct mutex lock;
- struct idr action_idr;
+ struct xarray actions;
};
struct tc_action_ops;
@@ -117,8 +116,7 @@ int tc_action_net_init(struct tc_action_net *tn,
if (!tn->idrinfo)
return -ENOMEM;
tn->ops = ops;
- mutex_init(&tn->idrinfo->lock);
- idr_init(&tn->idrinfo->action_idr);
+ xa_init_flags(&tn->idrinfo->actions, XA_FLAGS_ALLOC1);
return err;
}
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 339712296164..4039ad8c686c 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -126,11 +126,12 @@ static int __tcf_action_put(struct tc_action *p, bool bind)
{
struct tcf_idrinfo *idrinfo = p->idrinfo;
- if (refcount_dec_and_mutex_lock(&p->tcfa_refcnt, &idrinfo->lock)) {
+ if (refcount_dec_and_lock(&p->tcfa_refcnt,
+ &idrinfo->actions.xa_lock)) {
if (bind)
atomic_dec(&p->tcfa_bindcnt);
- idr_remove(&idrinfo->action_idr, p->tcfa_index);
- mutex_unlock(&idrinfo->lock);
+ __xa_erase(&idrinfo->actions, p->tcfa_index);
+ xa_unlock(&idrinfo->actions);
tcf_action_cleanup(p);
return 1;
@@ -214,24 +215,17 @@ static size_t tcf_action_fill_size(const struct tc_action *act)
static int tcf_dump_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
struct netlink_callback *cb)
{
- int err = 0, index = -1, s_i = 0, n_i = 0;
+ int err = 0, n_i = 0;
u32 act_flags = cb->args[2];
unsigned long jiffy_since = cb->args[3];
struct nlattr *nest;
- struct idr *idr = &idrinfo->action_idr;
+ struct xarray *xa = &idrinfo->actions;
struct tc_action *p;
- unsigned long id = 1;
- unsigned long tmp;
+ unsigned long index;
- mutex_lock(&idrinfo->lock);
-
- s_i = cb->args[0];
-
- idr_for_each_entry_ul(idr, p, tmp, id) {
- index++;
- if (index < s_i)
- continue;
+ xa_lock(xa);
+ xa_for_each_start(&idrinfo->actions, index, p, cb->args[0]) {
if (jiffy_since &&
time_after(jiffy_since,
(unsigned long)p->tcfa_tm.lastuse))
@@ -255,10 +249,9 @@ static int tcf_dump_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
goto done;
}
done:
- if (index >= 0)
- cb->args[0] = index + 1;
+ cb->args[0] = index + 1;
+ xa_unlock(xa);
- mutex_unlock(&idrinfo->lock);
if (n_i) {
if (act_flags & TCA_FLAG_LARGE_DUMP_ON)
cb->args[1] = n_i;
@@ -276,7 +269,7 @@ static int tcf_idr_release_unsafe(struct tc_action *p)
return -EPERM;
if (refcount_dec_and_test(&p->tcfa_refcnt)) {
- idr_remove(&p->idrinfo->action_idr, p->tcfa_index);
+ xa_erase(&p->idrinfo->actions, p->tcfa_index);
tcf_action_cleanup(p);
return ACT_P_DELETED;
}
@@ -290,10 +283,8 @@ static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
struct nlattr *nest;
int n_i = 0;
int ret = -EINVAL;
- struct idr *idr = &idrinfo->action_idr;
struct tc_action *p;
- unsigned long id = 1;
- unsigned long tmp;
+ unsigned long index;
nest = nla_nest_start_noflag(skb, 0);
if (nest == NULL)
@@ -301,18 +292,18 @@ static int tcf_del_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
if (nla_put_string(skb, TCA_KIND, ops->kind))
goto nla_put_failure;
- mutex_lock(&idrinfo->lock);
- idr_for_each_entry_ul(idr, p, tmp, id) {
+ xa_lock(&idrinfo->actions);
+ xa_for_each(&idrinfo->actions, index, p) {
ret = tcf_idr_release_unsafe(p);
if (ret == ACT_P_DELETED) {
module_put(ops->owner);
n_i++;
} else if (ret < 0) {
- mutex_unlock(&idrinfo->lock);
+ xa_unlock(&idrinfo->actions);
goto nla_put_failure;
}
}
- mutex_unlock(&idrinfo->lock);
+ xa_unlock(&idrinfo->actions);
if (nla_put_u32(skb, TCA_FCNT, n_i))
goto nla_put_failure;
@@ -348,13 +339,11 @@ int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index)
struct tcf_idrinfo *idrinfo = tn->idrinfo;
struct tc_action *p;
- mutex_lock(&idrinfo->lock);
- p = idr_find(&idrinfo->action_idr, index);
- if (IS_ERR(p))
- p = NULL;
- else if (p)
+ xa_lock(&idrinfo->actions);
+ p = xa_load(&idrinfo->actions, index);
+ if (p)
refcount_inc(&p->tcfa_refcnt);
- mutex_unlock(&idrinfo->lock);
+ xa_unlock(&idrinfo->actions);
if (p) {
*a = p;
@@ -369,10 +358,10 @@ static int tcf_idr_delete_index(struct tcf_idrinfo *idrinfo, u32 index)
struct tc_action *p;
int ret = 0;
- mutex_lock(&idrinfo->lock);
- p = idr_find(&idrinfo->action_idr, index);
+ xa_lock(&idrinfo->actions);
+ p = xa_load(&idrinfo->actions, index);
if (!p) {
- mutex_unlock(&idrinfo->lock);
+ xa_unlock(&idrinfo->actions);
return -ENOENT;
}
@@ -380,9 +369,8 @@ static int tcf_idr_delete_index(struct tcf_idrinfo *idrinfo, u32 index)
if (refcount_dec_and_test(&p->tcfa_refcnt)) {
struct module *owner = p->ops->owner;
- WARN_ON(p != idr_remove(&idrinfo->action_idr,
- p->tcfa_index));
- mutex_unlock(&idrinfo->lock);
+ __xa_erase(&idrinfo->actions, p->tcfa_index);
+ xa_unlock(&idrinfo->actions);
tcf_action_cleanup(p);
module_put(owner);
@@ -393,7 +381,7 @@ static int tcf_idr_delete_index(struct tcf_idrinfo *idrinfo, u32 index)
ret = -EPERM;
}
- mutex_unlock(&idrinfo->lock);
+ xa_unlock(&idrinfo->actions);
return ret;
}
@@ -455,10 +443,7 @@ void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a)
{
struct tcf_idrinfo *idrinfo = tn->idrinfo;
- mutex_lock(&idrinfo->lock);
- /* Replace ERR_PTR(-EBUSY) allocated by tcf_idr_check_alloc */
- WARN_ON(!IS_ERR(idr_replace(&idrinfo->action_idr, a, a->tcfa_index)));
- mutex_unlock(&idrinfo->lock);
+ xa_store(&idrinfo->actions, a->tcfa_index, a, GFP_KERNEL);
}
EXPORT_SYMBOL(tcf_idr_insert);
@@ -468,10 +453,7 @@ void tcf_idr_cleanup(struct tc_action_net *tn, u32 index)
{
struct tcf_idrinfo *idrinfo = tn->idrinfo;
- mutex_lock(&idrinfo->lock);
- /* Remove ERR_PTR(-EBUSY) allocated by tcf_idr_check_alloc */
- WARN_ON(!IS_ERR(idr_remove(&idrinfo->action_idr, index)));
- mutex_unlock(&idrinfo->lock);
+ xa_erase(&idrinfo->actions, index);
}
EXPORT_SYMBOL(tcf_idr_cleanup);
@@ -489,41 +471,36 @@ int tcf_idr_check_alloc(struct tc_action_net *tn, u32 *index,
int ret;
again:
- mutex_lock(&idrinfo->lock);
+ xa_lock(&idrinfo->actions);
if (*index) {
- p = idr_find(&idrinfo->action_idr, *index);
- if (IS_ERR(p)) {
- /* This means that another process allocated
- * index but did not assign the pointer yet.
- */
- mutex_unlock(&idrinfo->lock);
- goto again;
- }
-
+ p = xa_load(&idrinfo->actions, *index);
if (p) {
refcount_inc(&p->tcfa_refcnt);
if (bind)
atomic_inc(&p->tcfa_bindcnt);
- *a = p;
ret = 1;
} else {
*a = NULL;
- ret = idr_alloc_u32(&idrinfo->action_idr, NULL, index,
- *index, GFP_KERNEL);
- if (!ret)
- idr_replace(&idrinfo->action_idr,
- ERR_PTR(-EBUSY), *index);
+ ret = __xa_insert(&idrinfo->actions, *index, NULL,
+ GFP_KERNEL);
+ if (ret == -EBUSY) {
+ /*
+ * Another process has allocated this index,
+ * but has not yet assigned a pointer.
+ */
+ xa_unlock(&idrinfo->actions);
+ cpu_relax();
+ goto again;
+ }
}
} else {
- *index = 1;
- *a = NULL;
- ret = idr_alloc_u32(&idrinfo->action_idr, NULL, index,
- UINT_MAX, GFP_KERNEL);
- if (!ret)
- idr_replace(&idrinfo->action_idr, ERR_PTR(-EBUSY),
- *index);
+ ret = __xa_alloc(&idrinfo->actions, index, NULL, xa_limit_32b,
+ GFP_KERNEL);
+ p = NULL;
}
- mutex_unlock(&idrinfo->lock);
+
+ *a = p;
+ xa_unlock(&idrinfo->actions);
return ret;
}
EXPORT_SYMBOL(tcf_idr_check_alloc);
@@ -531,20 +508,18 @@ EXPORT_SYMBOL(tcf_idr_check_alloc);
void tcf_idrinfo_destroy(const struct tc_action_ops *ops,
struct tcf_idrinfo *idrinfo)
{
- struct idr *idr = &idrinfo->action_idr;
struct tc_action *p;
int ret;
- unsigned long id = 1;
- unsigned long tmp;
+ unsigned long index;
- idr_for_each_entry_ul(idr, p, tmp, id) {
+ xa_for_each(&idrinfo->actions, index, p) {
ret = __tcf_idr_release(p, false, true);
if (ret == ACT_P_DELETED)
module_put(ops->owner);
else if (ret < 0)
return;
}
- idr_destroy(&idrinfo->action_idr);
+ xa_destroy(&idrinfo->actions);
}
EXPORT_SYMBOL(tcf_idrinfo_destroy);
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 38/38] mac80211: Convert function_inst_ids to XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Replae the func_lock with the internal XArray spinlock. Ensuring that
nan_func is fully initialised before dropping the lock allows us to
iterate the array while not holding the lock, avoiding the awkward dance
in ieee80211_reconfig_nan().
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
net/mac80211/cfg.c | 57 ++++++++++++++------------------------
net/mac80211/ieee80211_i.h | 9 ++----
net/mac80211/iface.c | 16 +++++------
net/mac80211/util.c | 30 ++++----------------
4 files changed, 37 insertions(+), 75 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 47d7670094a9..2ea45b7007db 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -266,7 +266,7 @@ static int ieee80211_add_nan_func(struct wiphy *wiphy,
struct cfg80211_nan_func *nan_func)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
- int ret;
+ int ret, id;
if (sdata->vif.type != NL80211_IFTYPE_NAN)
return -EOPNOTSUPP;
@@ -274,27 +274,22 @@ static int ieee80211_add_nan_func(struct wiphy *wiphy,
if (!ieee80211_sdata_running(sdata))
return -ENETDOWN;
- spin_lock_bh(&sdata->u.nan.func_lock);
-
- ret = idr_alloc(&sdata->u.nan.function_inst_ids,
- nan_func, 1, sdata->local->hw.max_nan_de_entries + 1,
- GFP_ATOMIC);
- spin_unlock_bh(&sdata->u.nan.func_lock);
+ xa_lock_bh(&sdata->u.nan.functions);
+ ret = __xa_alloc(&sdata->u.nan.functions, &id, nan_func,
+ XA_LIMIT(0, sdata->local->hw.max_nan_de_entries),
+ GFP_KERNEL);
+ if (ret == 0)
+ nan_func->instance_id = id;
+ xa_unlock_bh(&sdata->u.nan.functions);
if (ret < 0)
return ret;
- nan_func->instance_id = ret;
-
WARN_ON(nan_func->instance_id == 0);
ret = drv_add_nan_func(sdata->local, sdata, nan_func);
- if (ret) {
- spin_lock_bh(&sdata->u.nan.func_lock);
- idr_remove(&sdata->u.nan.function_inst_ids,
- nan_func->instance_id);
- spin_unlock_bh(&sdata->u.nan.func_lock);
- }
+ if (ret)
+ xa_erase_bh(&sdata->u.nan.functions, nan_func->instance_id);
return ret;
}
@@ -304,11 +299,11 @@ ieee80211_find_nan_func_by_cookie(struct ieee80211_sub_if_data *sdata,
u64 cookie)
{
struct cfg80211_nan_func *func;
- int id;
+ unsigned long id;
- lockdep_assert_held(&sdata->u.nan.func_lock);
+ lockdep_assert_held(&sdata->u.nan.functions.xa_lock);
- idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id) {
+ xa_for_each(&sdata->u.nan.functions, id, func) {
if (func->cookie == cookie)
return func;
}
@@ -327,13 +322,13 @@ static void ieee80211_del_nan_func(struct wiphy *wiphy,
!ieee80211_sdata_running(sdata))
return;
- spin_lock_bh(&sdata->u.nan.func_lock);
+ xa_lock_bh(&sdata->u.nan.functions);
func = ieee80211_find_nan_func_by_cookie(sdata, cookie);
if (func)
instance_id = func->instance_id;
- spin_unlock_bh(&sdata->u.nan.func_lock);
+ xa_unlock_bh(&sdata->u.nan.functions);
if (instance_id)
drv_del_nan_func(sdata->local, sdata, instance_id);
@@ -3766,19 +3761,11 @@ void ieee80211_nan_func_terminated(struct ieee80211_vif *vif,
if (WARN_ON(vif->type != NL80211_IFTYPE_NAN))
return;
- spin_lock_bh(&sdata->u.nan.func_lock);
-
- func = idr_find(&sdata->u.nan.function_inst_ids, inst_id);
- if (WARN_ON(!func)) {
- spin_unlock_bh(&sdata->u.nan.func_lock);
+ func = xa_erase_bh(&sdata->u.nan.functions, inst_id);
+ if (WARN_ON(!func))
return;
- }
cookie = func->cookie;
- idr_remove(&sdata->u.nan.function_inst_ids, inst_id);
-
- spin_unlock_bh(&sdata->u.nan.func_lock);
-
cfg80211_free_nan_func(func);
cfg80211_nan_func_terminated(ieee80211_vif_to_wdev(vif), inst_id,
@@ -3796,16 +3783,14 @@ void ieee80211_nan_func_match(struct ieee80211_vif *vif,
if (WARN_ON(vif->type != NL80211_IFTYPE_NAN))
return;
- spin_lock_bh(&sdata->u.nan.func_lock);
-
- func = idr_find(&sdata->u.nan.function_inst_ids, match->inst_id);
+ xa_lock_bh(&sdata->u.nan.functions);
+ func = xa_load(&sdata->u.nan.functions, match->inst_id);
if (WARN_ON(!func)) {
- spin_unlock_bh(&sdata->u.nan.func_lock);
+ xa_unlock_bh(&sdata->u.nan.functions);
return;
}
match->cookie = func->cookie;
-
- spin_unlock_bh(&sdata->u.nan.func_lock);
+ xa_unlock_bh(&sdata->u.nan.functions);
cfg80211_nan_match(ieee80211_vif_to_wdev(vif), match, gfp);
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ade005892099..7be25939a6bf 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -23,7 +23,7 @@
#include <linux/spinlock.h>
#include <linux/etherdevice.h>
#include <linux/leds.h>
-#include <linux/idr.h>
+#include <linux/xarray.h>
#include <linux/rhashtable.h>
#include <net/ieee80211_radiotap.h>
#include <net/cfg80211.h>
@@ -862,14 +862,11 @@ struct ieee80211_if_mntr {
* struct ieee80211_if_nan - NAN state
*
* @conf: current NAN configuration
- * @func_ids: a bitmap of available instance_id's
+ * @functions: NAN function pointers
*/
struct ieee80211_if_nan {
struct cfg80211_nan_conf conf;
-
- /* protects function_inst_ids */
- spinlock_t func_lock;
- struct idr function_inst_ids;
+ struct xarray functions;
};
struct ieee80211_sub_if_data {
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 8dc6580e1787..022e2eb6a46c 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -802,6 +802,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
struct cfg80211_chan_def chandef;
bool cancel_scan;
struct cfg80211_nan_func *func;
+ unsigned long index;
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
@@ -961,15 +962,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
break;
case NL80211_IFTYPE_NAN:
/* clean all the functions */
- spin_lock_bh(&sdata->u.nan.func_lock);
-
- idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, i) {
- idr_remove(&sdata->u.nan.function_inst_ids, i);
+ xa_lock_bh(&sdata->u.nan.functions);
+ xa_for_each(&sdata->u.nan.functions, index, func) {
+ __xa_erase(&sdata->u.nan.functions, index);
cfg80211_free_nan_func(func);
}
- idr_destroy(&sdata->u.nan.function_inst_ids);
-
- spin_unlock_bh(&sdata->u.nan.func_lock);
+ xa_unlock_bh(&sdata->u.nan.functions);
break;
case NL80211_IFTYPE_P2P_DEVICE:
/* relies on synchronize_rcu() below */
@@ -1463,8 +1461,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
sdata->vif.bss_conf.bssid = NULL;
break;
case NL80211_IFTYPE_NAN:
- idr_init(&sdata->u.nan.function_inst_ids);
- spin_lock_init(&sdata->u.nan.func_lock);
+ xa_init_flags(&sdata->u.nan.functions,
+ XA_FLAGS_ALLOC1 | XA_FLAGS_LOCK_BH);
sdata->vif.bss_conf.bssid = sdata->vif.addr;
break;
case NL80211_IFTYPE_AP_VLAN:
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 286c7ee35e63..4996a3c01205 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2082,42 +2082,24 @@ static void ieee80211_reconfig_stations(struct ieee80211_sub_if_data *sdata)
static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata)
{
- struct cfg80211_nan_func *func, **funcs;
- int res, id, i = 0;
+ struct cfg80211_nan_func *func;
+ unsigned long id;
+ int res;
res = drv_start_nan(sdata->local, sdata,
&sdata->u.nan.conf);
if (WARN_ON(res))
return res;
- funcs = kcalloc(sdata->local->hw.max_nan_de_entries + 1,
- sizeof(*funcs),
- GFP_KERNEL);
- if (!funcs)
- return -ENOMEM;
-
- /* Add all the functions:
- * This is a little bit ugly. We need to call a potentially sleeping
- * callback for each NAN function, so we can't hold the spinlock.
- */
- spin_lock_bh(&sdata->u.nan.func_lock);
-
- idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id)
- funcs[i++] = func;
-
- spin_unlock_bh(&sdata->u.nan.func_lock);
-
- for (i = 0; funcs[i]; i++) {
- res = drv_add_nan_func(sdata->local, sdata, funcs[i]);
+ xa_for_each(&sdata->u.nan.functions, id, func) {
+ res = drv_add_nan_func(sdata->local, sdata, func);
if (WARN_ON(res))
ieee80211_nan_func_terminated(&sdata->vif,
- funcs[i]->instance_id,
+ func->instance_id,
NL80211_NAN_FUNC_TERM_REASON_ERROR,
GFP_KERNEL);
}
- kfree(funcs);
-
return 0;
}
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 05/38] mlx5: Convert mlx5_qp_table to XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Fix the locking in destroy_resource_common() to be irq-disable rather
than irq-save. wait_for_completion() can sleep, so this function must
not be callable from interrupt context.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
drivers/net/ethernet/mellanox/mlx5/core/qp.c | 38 ++++++--------------
include/linux/mlx5/driver.h | 8 ++---
include/linux/mlx5/qp.h | 2 +-
3 files changed, 13 insertions(+), 35 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c
index b8ba74de9555..e3367290b5ce 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c
@@ -49,13 +49,11 @@ mlx5_get_rsc(struct mlx5_qp_table *table, u32 rsn)
struct mlx5_core_rsc_common *common;
unsigned long flags;
- spin_lock_irqsave(&table->lock, flags);
-
- common = radix_tree_lookup(&table->tree, rsn);
+ xa_lock_irqsave(&table->array, flags);
+ common = xa_load(&table->array, rsn);
if (common)
atomic_inc(&common->refcount);
-
- spin_unlock_irqrestore(&table->lock, flags);
+ xa_unlock_irqrestore(&table->array, flags);
return common;
}
@@ -197,35 +195,22 @@ static int create_resource_common(struct mlx5_core_dev *dev,
struct mlx5_core_qp *qp,
int rsc_type)
{
- struct mlx5_qp_table *table = &dev->priv.qp_table;
- int err;
-
- qp->common.res = rsc_type;
- spin_lock_irq(&table->lock);
- err = radix_tree_insert(&table->tree,
- qp->qpn | (rsc_type << MLX5_USER_INDEX_LEN),
- qp);
- spin_unlock_irq(&table->lock);
- if (err)
- return err;
-
atomic_set(&qp->common.refcount, 1);
init_completion(&qp->common.free);
qp->pid = current->pid;
- return 0;
+ qp->common.res = rsc_type;
+ return xa_err(xa_store_irq(&dev->priv.qp_table.array,
+ qp->qpn | (rsc_type << MLX5_USER_INDEX_LEN),
+ qp, GFP_KERNEL));
}
static void destroy_resource_common(struct mlx5_core_dev *dev,
struct mlx5_core_qp *qp)
{
- struct mlx5_qp_table *table = &dev->priv.qp_table;
- unsigned long flags;
+ struct xarray *xa = &dev->priv.qp_table.array;
- spin_lock_irqsave(&table->lock, flags);
- radix_tree_delete(&table->tree,
- qp->qpn | (qp->common.res << MLX5_USER_INDEX_LEN));
- spin_unlock_irqrestore(&table->lock, flags);
+ xa_erase_irq(xa, qp->qpn | (qp->common.res << MLX5_USER_INDEX_LEN));
mlx5_core_put_rsc((struct mlx5_core_rsc_common *)qp);
wait_for_completion(&qp->common.free);
}
@@ -524,10 +509,7 @@ EXPORT_SYMBOL_GPL(mlx5_core_qp_modify);
void mlx5_init_qp_table(struct mlx5_core_dev *dev)
{
struct mlx5_qp_table *table = &dev->priv.qp_table;
-
- memset(table, 0, sizeof(*table));
- spin_lock_init(&table->lock);
- INIT_RADIX_TREE(&table->tree, GFP_ATOMIC);
+ xa_init_flags(&table->array, XA_FLAGS_LOCK_IRQ);
mlx5_qp_debugfs_init(dev);
table->nb.notifier_call = rsc_event_notifier;
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index df23f17eed64..ba8f59b11920 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -448,12 +448,8 @@ struct mlx5_core_health {
};
struct mlx5_qp_table {
- struct notifier_block nb;
-
- /* protect radix tree
- */
- spinlock_t lock;
- struct radix_tree_root tree;
+ struct notifier_block nb;
+ struct xarray array;
};
struct mlx5_vf_context {
diff --git a/include/linux/mlx5/qp.h b/include/linux/mlx5/qp.h
index ae63b1ae9004..6d1577a1ca41 100644
--- a/include/linux/mlx5/qp.h
+++ b/include/linux/mlx5/qp.h
@@ -555,7 +555,7 @@ struct mlx5_qp_context {
static inline struct mlx5_core_qp *__mlx5_qp_lookup(struct mlx5_core_dev *dev, u32 qpn)
{
- return radix_tree_lookup(&dev->priv.qp_table.tree, qpn);
+ return xa_load(&dev->priv.qp_table.array, qpn);
}
int mlx5_core_create_dct(struct mlx5_core_dev *dev,
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 02/38] mlx4: Convert srq_table->tree to XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Adjust the locking to not disable interrupts; this isn't needed as all
accesses are either writes from process context or reads protected
by the RCU lock.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
drivers/infiniband/hw/mlx4/cq.c | 2 +-
drivers/net/ethernet/mellanox/mlx4/mlx4.h | 3 +--
drivers/net/ethernet/mellanox/mlx4/srq.c | 33 +++++++----------------
3 files changed, 11 insertions(+), 27 deletions(-)
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index a7d238d312f0..0d7709823b9f 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -728,7 +728,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
u32 srq_num;
g_mlpath_rqpn = be32_to_cpu(cqe->g_mlpath_rqpn);
srq_num = g_mlpath_rqpn & 0xffffff;
- /* SRQ is also in the radix tree */
+ /* SRQ is also in the xarray */
msrq = mlx4_srq_lookup(to_mdev(cq->ibcq.device)->dev,
srq_num);
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index a40a9a259adb..b6fe22bee9f4 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -698,8 +698,7 @@ struct mlx4_eq_table {
struct mlx4_srq_table {
struct mlx4_bitmap bitmap;
- spinlock_t lock;
- struct radix_tree_root tree;
+ struct xarray array;
struct mlx4_icm_table table;
struct mlx4_icm_table cmpt_table;
};
diff --git a/drivers/net/ethernet/mellanox/mlx4/srq.c b/drivers/net/ethernet/mellanox/mlx4/srq.c
index cbe4d9746ddf..b7c4007fbc85 100644
--- a/drivers/net/ethernet/mellanox/mlx4/srq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/srq.c
@@ -45,9 +45,7 @@ void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type)
struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
struct mlx4_srq *srq;
- rcu_read_lock();
- srq = radix_tree_lookup(&srq_table->tree, srqn & (dev->caps.num_srqs - 1));
- rcu_read_unlock();
+ srq = xa_load(&srq_table->array, srqn & (dev->caps.num_srqs - 1));
if (srq)
refcount_inc(&srq->refcount);
else {
@@ -172,16 +170,14 @@ int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd,
if (err)
return err;
- spin_lock_irq(&srq_table->lock);
- err = radix_tree_insert(&srq_table->tree, srq->srqn, srq);
- spin_unlock_irq(&srq_table->lock);
+ err = xa_err(xa_store(&srq_table->array, srq->srqn, srq, GFP_KERNEL));
if (err)
goto err_icm;
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox)) {
err = PTR_ERR(mailbox);
- goto err_radix;
+ goto err_xa;
}
srq_context = mailbox->buf;
@@ -201,17 +197,15 @@ int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, u32 cqn, u16 xrcd,
err = mlx4_SW2HW_SRQ(dev, mailbox, srq->srqn);
mlx4_free_cmd_mailbox(dev, mailbox);
if (err)
- goto err_radix;
+ goto err_xa;
refcount_set(&srq->refcount, 1);
init_completion(&srq->free);
return 0;
-err_radix:
- spin_lock_irq(&srq_table->lock);
- radix_tree_delete(&srq_table->tree, srq->srqn);
- spin_unlock_irq(&srq_table->lock);
+err_xa:
+ xa_erase(&srq_table->array, srq->srqn);
err_icm:
mlx4_srq_free_icm(dev, srq->srqn);
@@ -228,9 +222,7 @@ void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq)
if (err)
mlx4_warn(dev, "HW2SW_SRQ failed (%d) for SRQN %06x\n", err, srq->srqn);
- spin_lock_irq(&srq_table->lock);
- radix_tree_delete(&srq_table->tree, srq->srqn);
- spin_unlock_irq(&srq_table->lock);
+ xa_erase(&srq_table->array, srq->srqn);
if (refcount_dec_and_test(&srq->refcount))
complete(&srq->free);
@@ -274,8 +266,7 @@ int mlx4_init_srq_table(struct mlx4_dev *dev)
struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
int err;
- spin_lock_init(&srq_table->lock);
- INIT_RADIX_TREE(&srq_table->tree, GFP_ATOMIC);
+ xa_init(&srq_table->array);
if (mlx4_is_slave(dev))
return 0;
@@ -297,13 +288,7 @@ void mlx4_cleanup_srq_table(struct mlx4_dev *dev)
struct mlx4_srq *mlx4_srq_lookup(struct mlx4_dev *dev, u32 srqn)
{
struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
- struct mlx4_srq *srq;
-
- rcu_read_lock();
- srq = radix_tree_lookup(&srq_table->tree,
- srqn & (dev->caps.num_srqs - 1));
- rcu_read_unlock();
- return srq;
+ return xa_load(&srq_table->array, srqn & (dev->caps.num_srqs - 1));
}
EXPORT_SYMBOL_GPL(mlx4_srq_lookup);
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 00/38] Convert networking to use the XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Hello good networking folks,
I am attempting to convert all IDR and radix tree users over to the
XArray API so we can remove the radix tree code from the kernel. This
process is already underway, and you can see all the conversions in a
git tree [1].
The set of conversions I am submitting to you today are only compile
tested. I would appreciate it if those who are responsible for each
module could take on the job of making sure I didn't break anything.
Review is, of course, also welcome.
The primary difference between the IDR/radix tree and XArray APIs is that
the XArray embeds a spinlock. This enables the ability to defragment
the slabs which contain XArray nodes, and for most users results in an
easier-to-use API.
There are a lot of smaller tweaks in the XArray API compared to the radix
tree or IDR APIs. For example, there is no more preallocation of memory;
instead the XArray will drop the lock if needed to allocate memory.
Ideally, you'd include the patch for your module into your next pull
request to Dave and they'd land upstream in 5.4. These patches are
against current net-next. If you'd like to change whitespace or comments
or so on, please just do that; this is your code and I've got a lot of
other patches I need to whip into shape.
[1] http://git.infradead.org/users/willy/linux-dax.git/shortlog/refs/heads/xarray-conv
Some of these conversions are known to be buggy, so I would not recommend
actually running this tree.
Matthew Wilcox (Oracle) (38):
mlx4: Convert cq_table->tree to XArray
mlx4: Convert srq_table->tree to XArray
mlx4: Convert qp_table_tree to XArray
mlx5: Convert cq_table to XArray
mlx5: Convert mlx5_qp_table to XArray
mlx5: Convert counters_idr to XArray
mlx5: Convert fpga IDRs to XArray
nfp: Convert to XArray
ath10k: Convert pending_tx to XArray
ath10k: Convert mgmt_pending_tx IDR to XArray
mt76: Convert token IDR to XArray
mwifiex: Convert ack_status_frames to XArray
ppp: Convert units_idr to XArray
tap: Convert minor_idr to XArray
nfp: Convert internal ports to XArray
qrtr: Convert qrtr_nodes to XArray
qrtr: Convert qrtr_ports to XArray
rxrpc: Convert to XArray
9p: Convert reqs IDR to XArray
9p: Convert fids IDR to XArray
9p: Move lock from client to trans_fd
sctp: Convert sctp_assocs_id to XArray
cls_api: Convert tcf_net to XArray
cls_u32: Convert tc_u_common->handle_idr to XArray
cls_u32: Convert tc_u_hnode->handle_idr to XArray
cls_bpf: Convert handle_idr to XArray
cls_bpf: Remove list of programs
cls_bpf: Use XArray marks to accelerate re-offload
cls_flower: Convert handle_idr to XArray
cls_flower: Use XArray list of filters in fl_walk
cls_flower: Use XArray marks instead of separate list
cls_basic: Convert handle_idr to XArray
act_api: Convert action_idr to XArray
net_namespace: Convert netns_ids to XArray
tipc: Convert conn_idr to XArray
netlink: Convert genl_fam_idr to XArray
mac80211: Convert ack_status_frames to XArray
mac80211: Convert function_inst_ids to XArray
drivers/infiniband/hw/mlx4/cq.c | 2 +-
drivers/net/ethernet/mellanox/mlx4/cq.c | 30 ++---
drivers/net/ethernet/mellanox/mlx4/mlx4.h | 9 +-
drivers/net/ethernet/mellanox/mlx4/qp.c | 37 ++---
drivers/net/ethernet/mellanox/mlx4/srq.c | 33 ++---
drivers/net/ethernet/mellanox/mlx5/core/eq.c | 27 +---
.../ethernet/mellanox/mlx5/core/fpga/tls.c | 54 +++-----
.../ethernet/mellanox/mlx5/core/fpga/tls.h | 6 +-
.../ethernet/mellanox/mlx5/core/fs_counters.c | 31 ++---
.../net/ethernet/mellanox/mlx5/core/lib/eq.h | 7 +-
drivers/net/ethernet/mellanox/mlx5/core/qp.c | 38 ++----
drivers/net/ethernet/netronome/nfp/abm/main.c | 4 +-
drivers/net/ethernet/netronome/nfp/abm/main.h | 4 +-
.../net/ethernet/netronome/nfp/abm/qdisc.c | 33 ++---
.../net/ethernet/netronome/nfp/flower/main.c | 44 +++---
.../net/ethernet/netronome/nfp/flower/main.h | 12 +-
drivers/net/ppp/ppp_generic.c | 73 +++-------
drivers/net/tap.c | 32 ++---
drivers/net/wireless/ath/ath10k/core.h | 2 +-
drivers/net/wireless/ath/ath10k/htt.h | 2 +-
drivers/net/wireless/ath/ath10k/htt_tx.c | 31 ++---
drivers/net/wireless/ath/ath10k/mac.c | 4 +-
drivers/net/wireless/ath/ath10k/txrx.c | 2 +-
drivers/net/wireless/ath/ath10k/wmi-tlv.c | 8 +-
drivers/net/wireless/ath/ath10k/wmi.c | 43 +++---
drivers/net/wireless/marvell/mwifiex/init.c | 4 +-
drivers/net/wireless/marvell/mwifiex/main.c | 10 +-
drivers/net/wireless/marvell/mwifiex/main.h | 4 +-
drivers/net/wireless/marvell/mwifiex/txrx.c | 4 +-
drivers/net/wireless/marvell/mwifiex/wmm.c | 15 +--
.../net/wireless/mediatek/mt76/mt7615/init.c | 11 +-
.../net/wireless/mediatek/mt76/mt7615/mac.c | 24 ++--
.../wireless/mediatek/mt76/mt7615/mt7615.h | 4 +-
include/linux/mlx4/device.h | 4 +-
include/linux/mlx4/qp.h | 2 +-
include/linux/mlx5/driver.h | 11 +-
include/linux/mlx5/qp.h | 2 +-
include/net/9p/client.h | 11 +-
include/net/act_api.h | 6 +-
include/net/net_namespace.h | 2 +-
include/net/sctp/sctp.h | 5 +-
net/9p/client.c | 65 ++++-----
net/9p/trans_fd.c | 37 ++---
net/9p/trans_rdma.c | 1 -
net/9p/trans_virtio.c | 1 -
net/core/net_namespace.c | 65 ++++-----
net/mac80211/cfg.c | 70 ++++------
net/mac80211/ieee80211_i.h | 12 +-
net/mac80211/iface.c | 16 +--
net/mac80211/main.c | 20 ++-
net/mac80211/status.c | 6 +-
net/mac80211/tx.c | 16 +--
net/mac80211/util.c | 30 +----
net/netlink/genetlink.c | 46 +++----
net/qrtr/qrtr.c | 66 ++++-----
net/rxrpc/af_rxrpc.c | 2 +-
net/rxrpc/ar-internal.h | 3 +-
net/rxrpc/conn_client.c | 49 +++----
net/rxrpc/conn_object.c | 2 +-
net/sched/act_api.c | 127 +++++++-----------
net/sched/cls_api.c | 27 +---
net/sched/cls_basic.c | 56 +++-----
net/sched/cls_bpf.c | 74 +++++-----
net/sched/cls_flower.c | 114 ++++++----------
net/sched/cls_u32.c | 63 ++++-----
net/sctp/associola.c | 34 ++---
net/sctp/protocol.c | 6 -
net/sctp/sm_make_chunk.c | 2 +-
net/sctp/socket.c | 6 +-
net/tipc/topsrv.c | 49 ++-----
70 files changed, 650 insertions(+), 1102 deletions(-)
--
2.23.0.rc1
^ permalink raw reply
* [PATCH 32/38] cls_basic: Convert handle_idr to XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
The flist is redundant with the XArray, so remove it and use XArray
operations to iterate & look up filters by ID. Locking is unadjusted,
so most XArray operations continue to be protected by both the rtnl
lock and the XArray spinlock. Lookups remain under the rtnl lock,
but could be switched to pure RCU protection.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
net/sched/cls_basic.c | 56 ++++++++++++++++---------------------------
1 file changed, 21 insertions(+), 35 deletions(-)
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
index 4aafbe3d435c..66efad664a92 100644
--- a/net/sched/cls_basic.c
+++ b/net/sched/cls_basic.c
@@ -13,15 +13,14 @@
#include <linux/errno.h>
#include <linux/rtnetlink.h>
#include <linux/skbuff.h>
-#include <linux/idr.h>
#include <linux/percpu.h>
+#include <linux/xarray.h>
#include <net/netlink.h>
#include <net/act_api.h>
#include <net/pkt_cls.h>
struct basic_head {
- struct list_head flist;
- struct idr handle_idr;
+ struct xarray filters;
struct rcu_head rcu;
};
@@ -31,7 +30,6 @@ struct basic_filter {
struct tcf_ematch_tree ematches;
struct tcf_result res;
struct tcf_proto *tp;
- struct list_head link;
struct tc_basic_pcnt __percpu *pf;
struct rcu_work rwork;
};
@@ -42,8 +40,9 @@ static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp,
int r;
struct basic_head *head = rcu_dereference_bh(tp->root);
struct basic_filter *f;
+ unsigned long index;
- list_for_each_entry_rcu(f, &head->flist, link) {
+ xa_for_each(&head->filters, index, f) {
__this_cpu_inc(f->pf->rcnt);
if (!tcf_em_tree_match(skb, &f->ematches, NULL))
continue;
@@ -60,15 +59,8 @@ static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp,
static void *basic_get(struct tcf_proto *tp, u32 handle)
{
struct basic_head *head = rtnl_dereference(tp->root);
- struct basic_filter *f;
-
- list_for_each_entry(f, &head->flist, link) {
- if (f->handle == handle) {
- return f;
- }
- }
- return NULL;
+ return xa_load(&head->filters, handle);
}
static int basic_init(struct tcf_proto *tp)
@@ -78,8 +70,7 @@ static int basic_init(struct tcf_proto *tp)
head = kzalloc(sizeof(*head), GFP_KERNEL);
if (head == NULL)
return -ENOBUFS;
- INIT_LIST_HEAD(&head->flist);
- idr_init(&head->handle_idr);
+ xa_init_flags(&head->filters, XA_FLAGS_ALLOC1);
rcu_assign_pointer(tp->root, head);
return 0;
}
@@ -107,18 +98,17 @@ static void basic_destroy(struct tcf_proto *tp, bool rtnl_held,
struct netlink_ext_ack *extack)
{
struct basic_head *head = rtnl_dereference(tp->root);
- struct basic_filter *f, *n;
+ struct basic_filter *f;
+ unsigned long index;
- list_for_each_entry_safe(f, n, &head->flist, link) {
- list_del_rcu(&f->link);
+ xa_for_each(&head->filters, index, f) {
tcf_unbind_filter(tp, &f->res);
- idr_remove(&head->handle_idr, f->handle);
+ xa_erase(&head->filters, index);
if (tcf_exts_get_net(&f->exts))
tcf_queue_work(&f->rwork, basic_delete_filter_work);
else
__basic_delete_filter(f);
}
- idr_destroy(&head->handle_idr);
kfree_rcu(head, rcu);
}
@@ -128,12 +118,11 @@ static int basic_delete(struct tcf_proto *tp, void *arg, bool *last,
struct basic_head *head = rtnl_dereference(tp->root);
struct basic_filter *f = arg;
- list_del_rcu(&f->link);
tcf_unbind_filter(tp, &f->res);
- idr_remove(&head->handle_idr, f->handle);
+ xa_erase(&head->filters, f->handle);
tcf_exts_get_net(&f->exts);
tcf_queue_work(&f->rwork, basic_delete_filter_work);
- *last = list_empty(&head->flist);
+ *last = xa_empty(&head->filters);
return 0;
}
@@ -199,17 +188,16 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
if (err < 0)
goto errout;
+ fnew->handle = handle;
if (!handle) {
- handle = 1;
- err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
- INT_MAX, GFP_KERNEL);
+ err = xa_alloc(&head->filters, &fnew->handle, fnew,
+ xa_limit_32b, GFP_KERNEL);
} else if (!fold) {
- err = idr_alloc_u32(&head->handle_idr, fnew, &handle,
- handle, GFP_KERNEL);
+ err = xa_insert(&head->filters, handle, fnew, GFP_KERNEL);
}
if (err)
goto errout;
- fnew->handle = handle;
+
fnew->pf = alloc_percpu(struct tc_basic_pcnt);
if (!fnew->pf) {
err = -ENOMEM;
@@ -220,20 +208,17 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
extack);
if (err < 0) {
if (!fold)
- idr_remove(&head->handle_idr, fnew->handle);
+ xa_erase(&head->filters, fnew->handle);
goto errout;
}
*arg = fnew;
if (fold) {
- idr_replace(&head->handle_idr, fnew, fnew->handle);
- list_replace_rcu(&fold->link, &fnew->link);
+ xa_store(&head->filters, fnew->handle, fnew, GFP_KERNEL);
tcf_unbind_filter(tp, &fold->res);
tcf_exts_get_net(&fold->exts);
tcf_queue_work(&fold->rwork, basic_delete_filter_work);
- } else {
- list_add_rcu(&fnew->link, &head->flist);
}
return 0;
@@ -249,8 +234,9 @@ static void basic_walk(struct tcf_proto *tp, struct tcf_walker *arg,
{
struct basic_head *head = rtnl_dereference(tp->root);
struct basic_filter *f;
+ unsigned long index;
- list_for_each_entry(f, &head->flist, link) {
+ xa_for_each(&head->filters, index, f) {
if (arg->count < arg->skip)
goto skip;
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 34/38] net_namespace: Convert netns_ids to XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
This is a straightforward conversion; it should be possible to eliminate
nsid_lock as it seems to only be used to protect netns_ids. The tricky
part is that dropping the lock (eg to allocate memory) could end up
allowing two networks which are equal to each other being allocated.
So stick with the GFP_ATOMIC allocations and double locking until
someone who's more savvy wants to try their hand at eliminating it.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
include/net/net_namespace.h | 2 +-
net/core/net_namespace.c | 65 +++++++++++++++++--------------------
2 files changed, 30 insertions(+), 37 deletions(-)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 4a9da951a794..6c80cadc6396 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -78,7 +78,7 @@ struct net {
struct user_namespace *user_ns; /* Owning user namespace */
struct ucounts *ucounts;
spinlock_t nsid_lock;
- struct idr netns_ids;
+ struct xarray netns_ids;
struct ns_common ns;
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index a0e0d298c991..c9b16e1b4a7e 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -188,27 +188,18 @@ static void ops_free_list(const struct pernet_operations *ops,
/* should be called with nsid_lock held */
static int alloc_netid(struct net *net, struct net *peer, int reqid)
{
- int min = 0, max = 0;
+ int ret;
if (reqid >= 0) {
- min = reqid;
- max = reqid + 1;
+ ret = xa_insert(&net->netns_ids, reqid, peer, GFP_ATOMIC);
+ } else {
+ ret = xa_alloc(&net->netns_ids, &reqid, peer, xa_limit_31b,
+ GFP_ATOMIC);
}
- return idr_alloc(&net->netns_ids, peer, min, max, GFP_ATOMIC);
-}
-
-/* This function is used by idr_for_each(). If net is equal to peer, the
- * function returns the id so that idr_for_each() stops. Because we cannot
- * returns the id 0 (idr_for_each() will not stop), we return the magic value
- * NET_ID_ZERO (-1) for it.
- */
-#define NET_ID_ZERO -1
-static int net_eq_idr(int id, void *net, void *peer)
-{
- if (net_eq(net, peer))
- return id ? : NET_ID_ZERO;
- return 0;
+ if (ret)
+ return ret;
+ return reqid;
}
/* Should be called with nsid_lock held. If a new id is assigned, the bool alloc
@@ -217,16 +208,17 @@ static int net_eq_idr(int id, void *net, void *peer)
*/
static int __peernet2id_alloc(struct net *net, struct net *peer, bool *alloc)
{
- int id = idr_for_each(&net->netns_ids, net_eq_idr, peer);
+ int id;
+ struct net *tmp;
+ unsigned long index;
bool alloc_it = *alloc;
- *alloc = false;
-
- /* Magic value for id 0. */
- if (id == NET_ID_ZERO)
- return 0;
- if (id > 0)
- return id;
+ xa_for_each(&net->netns_ids, index, tmp) {
+ if (net_eq(tmp, peer)) {
+ *alloc = false;
+ return index;
+ }
+ }
if (alloc_it) {
id = alloc_netid(net, peer, -1);
@@ -261,7 +253,7 @@ int peernet2id_alloc(struct net *net, struct net *peer)
* When peer is obtained from RCU lists, we may race with
* its cleanup. Check whether it's alive, and this guarantees
* we never hash a peer back to net->netns_ids, after it has
- * just been idr_remove()'d from there in cleanup_net().
+ * just been removed from there in cleanup_net().
*/
if (maybe_get_net(peer))
alive = alloc = true;
@@ -303,7 +295,7 @@ struct net *get_net_ns_by_id(struct net *net, int id)
return NULL;
rcu_read_lock();
- peer = idr_find(&net->netns_ids, id);
+ peer = xa_load(&net->netns_ids, id);
if (peer)
peer = maybe_get_net(peer);
rcu_read_unlock();
@@ -326,7 +318,7 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
get_random_bytes(&net->hash_mix, sizeof(u32));
net->dev_base_seq = 1;
net->user_ns = user_ns;
- idr_init(&net->netns_ids);
+ xa_init_flags(&net->netns_ids, XA_FLAGS_ALLOC);
spin_lock_init(&net->nsid_lock);
mutex_init(&net->ipv4.ra_mutex);
@@ -529,16 +521,14 @@ static void unhash_nsid(struct net *net, struct net *last)
spin_lock_bh(&tmp->nsid_lock);
id = __peernet2id(tmp, net);
if (id >= 0)
- idr_remove(&tmp->netns_ids, id);
+ xa_erase(&tmp->netns_ids, id);
spin_unlock_bh(&tmp->nsid_lock);
if (id >= 0)
rtnl_net_notifyid(tmp, RTM_DELNSID, id);
if (tmp == last)
break;
}
- spin_lock_bh(&net->nsid_lock);
- idr_destroy(&net->netns_ids);
- spin_unlock_bh(&net->nsid_lock);
+ BUG_ON(!xa_empty(&net->netns_ids));
}
static LLIST_HEAD(cleanup_list);
@@ -766,7 +756,7 @@ static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err >= 0) {
rtnl_net_notifyid(net, RTM_NEWNSID, err);
err = 0;
- } else if (err == -ENOSPC && nsid >= 0) {
+ } else if (err == -EBUSY && nsid >= 0) {
err = -EEXIST;
NL_SET_BAD_ATTR(extack, tb[NETNSA_NSID]);
NL_SET_ERR_MSG(extack, "The specified nsid is already used");
@@ -946,9 +936,9 @@ struct rtnl_net_dump_cb {
int s_idx;
};
-static int rtnl_net_dumpid_one(int id, void *peer, void *data)
+static int rtnl_net_dumpid_one(int id, struct net *peer,
+ struct rtnl_net_dump_cb *net_cb)
{
- struct rtnl_net_dump_cb *net_cb = (struct rtnl_net_dump_cb *)data;
int ret;
if (net_cb->idx < net_cb->s_idx)
@@ -1022,6 +1012,8 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
.idx = 0,
.s_idx = cb->args[0],
};
+ struct net *peer;
+ unsigned long index;
int err = 0;
if (cb->strict_check) {
@@ -1038,7 +1030,8 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
err = -EAGAIN;
goto end;
}
- idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
+ xa_for_each(&net_cb.tgt_net->netns_ids, index, peer)
+ rtnl_net_dumpid_one(index, peer, &net_cb);
if (net_cb.fillargs.add_ref &&
!net_eq(net_cb.ref_net, net_cb.tgt_net))
spin_unlock_bh(&net_cb.ref_net->nsid_lock);
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 30/38] cls_flower: Use XArray list of filters in fl_walk
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Instead of iterating over every filter attached to every mark, just
iterate over each filter.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
net/sched/cls_flower.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index 54026c9e9b05..2a1999d2b507 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -575,18 +575,15 @@ static void fl_destroy(struct tcf_proto *tp, bool rtnl_held,
struct netlink_ext_ack *extack)
{
struct cls_fl_head *head = fl_head_dereference(tp);
- struct fl_flow_mask *mask, *next_mask;
- struct cls_fl_filter *f, *next;
+ struct cls_fl_filter *f;
+ unsigned long handle;
bool last;
- list_for_each_entry_safe(mask, next_mask, &head->masks, list) {
- list_for_each_entry_safe(f, next, &mask->filters, list) {
- __fl_delete(tp, f, &last, rtnl_held, extack);
- if (last)
- break;
- }
+ xa_for_each(&head->filters, handle, f) {
+ __fl_delete(tp, f, &last, rtnl_held, extack);
+ if (last)
+ break;
}
- xa_destroy(&head->filters);
__module_get(THIS_MODULE);
tcf_queue_work(&head->rwork, fl_destroy_sleepable);
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 36/38] netlink: Convert genl_fam_idr to XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Straightforward conversion without touching the locking.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
net/netlink/genetlink.c | 46 +++++++++++++++++------------------------
1 file changed, 19 insertions(+), 27 deletions(-)
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index efccd1ac9a66..02f5c7453f84 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -18,7 +18,7 @@
#include <linux/mutex.h>
#include <linux/bitmap.h>
#include <linux/rwsem.h>
-#include <linux/idr.h>
+#include <linux/xarray.h>
#include <net/sock.h>
#include <net/genetlink.h>
@@ -60,7 +60,8 @@ static void genl_unlock_all(void)
up_write(&cb_lock);
}
-static DEFINE_IDR(genl_fam_idr);
+static unsigned int genl_families_next;
+static DEFINE_XARRAY_ALLOC(genl_families);
/*
* Bitmap of multicast groups that are currently in use.
@@ -92,15 +93,15 @@ static int genl_ctrl_event(int event, const struct genl_family *family,
static const struct genl_family *genl_family_find_byid(unsigned int id)
{
- return idr_find(&genl_fam_idr, id);
+ return xa_load(&genl_families, id);
}
static const struct genl_family *genl_family_find_byname(char *name)
{
const struct genl_family *family;
- unsigned int id;
+ unsigned long id;
- idr_for_each_entry(&genl_fam_idr, family, id)
+ xa_for_each(&genl_families, id, family)
if (strcmp(family->name, name) == 0)
return family;
@@ -362,12 +363,10 @@ int genl_register_family(struct genl_family *family)
} else
family->attrbuf = NULL;
- family->id = idr_alloc_cyclic(&genl_fam_idr, family,
- start, end + 1, GFP_KERNEL);
- if (family->id < 0) {
- err = family->id;
+ err = xa_alloc_cyclic(&genl_families, &family->id, family,
+ XA_LIMIT(start, end), &genl_families_next, GFP_KERNEL);
+ if (err < 0)
goto errout_free;
- }
err = genl_validate_assign_mc_groups(family);
if (err)
@@ -384,7 +383,7 @@ int genl_register_family(struct genl_family *family)
return 0;
errout_remove:
- idr_remove(&genl_fam_idr, family->id);
+ xa_erase(&genl_families, family->id);
errout_free:
kfree(family->attrbuf);
errout_locked:
@@ -412,7 +411,7 @@ int genl_unregister_family(const struct genl_family *family)
genl_unregister_mc_groups(family);
- idr_remove(&genl_fam_idr, family->id);
+ xa_erase(&genl_families, family->id);
up_write(&cb_lock);
wait_event(genl_sk_destructing_waitq,
@@ -802,28 +801,21 @@ static int ctrl_fill_mcgrp_info(const struct genl_family *family,
static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
{
- int n = 0;
struct genl_family *rt;
struct net *net = sock_net(skb->sk);
- int fams_to_skip = cb->args[0];
- unsigned int id;
+ unsigned long id;
- idr_for_each_entry(&genl_fam_idr, rt, id) {
+ xa_for_each_start(&genl_families, id, rt, cb->args[0]) {
if (!rt->netnsok && !net_eq(net, &init_net))
continue;
- if (n++ < fams_to_skip)
- continue;
-
if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
- skb, CTRL_CMD_NEWFAMILY) < 0) {
- n--;
+ skb, CTRL_CMD_NEWFAMILY) < 0)
break;
- }
}
- cb->args[0] = n;
+ cb->args[0] = id;
return skb->len;
}
@@ -993,11 +985,11 @@ static int genl_bind(struct net *net, int group)
{
struct genl_family *f;
int err = -ENOENT;
- unsigned int id;
+ unsigned long id;
down_read(&cb_lock);
- idr_for_each_entry(&genl_fam_idr, f, id) {
+ xa_for_each(&genl_families, id, f) {
if (group >= f->mcgrp_offset &&
group < f->mcgrp_offset + f->n_mcgrps) {
int fam_grp = group - f->mcgrp_offset;
@@ -1019,11 +1011,11 @@ static int genl_bind(struct net *net, int group)
static void genl_unbind(struct net *net, int group)
{
struct genl_family *f;
- unsigned int id;
+ unsigned long id;
down_read(&cb_lock);
- idr_for_each_entry(&genl_fam_idr, f, id) {
+ xa_for_each(&genl_families, id, f) {
if (group >= f->mcgrp_offset &&
group < f->mcgrp_offset + f->n_mcgrps) {
int fam_grp = group - f->mcgrp_offset;
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 35/38] tipc: Convert conn_idr to XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Replace idr_lock with the internal XArray lock. The idr_in_use
counter isn't needed as we can free all the elements in the array
without it.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
net/tipc/topsrv.c | 49 ++++++++++++++---------------------------------
1 file changed, 14 insertions(+), 35 deletions(-)
diff --git a/net/tipc/topsrv.c b/net/tipc/topsrv.c
index 3a12fc18239b..72b3180e0ea5 100644
--- a/net/tipc/topsrv.c
+++ b/net/tipc/topsrv.c
@@ -54,9 +54,7 @@
/**
* struct tipc_topsrv - TIPC server structure
- * @conn_idr: identifier set of connection
- * @idr_lock: protect the connection identifier set
- * @idr_in_use: amount of allocated identifier entry
+ * @conns: identifier set of connection
* @net: network namspace instance
* @awork: accept work item
* @rcv_wq: receive workqueue
@@ -65,9 +63,7 @@
* @name: server name
*/
struct tipc_topsrv {
- struct idr conn_idr;
- spinlock_t idr_lock; /* for idr list */
- int idr_in_use;
+ struct xarray conns;
struct net *net;
struct work_struct awork;
struct workqueue_struct *rcv_wq;
@@ -127,10 +123,7 @@ static void tipc_conn_kref_release(struct kref *kref)
struct tipc_topsrv *s = con->server;
struct outqueue_entry *e, *safe;
- spin_lock_bh(&s->idr_lock);
- idr_remove(&s->conn_idr, con->conid);
- s->idr_in_use--;
- spin_unlock_bh(&s->idr_lock);
+ xa_erase_bh(&s->conns, con->conid);
if (con->sock)
sock_release(con->sock);
@@ -194,16 +187,12 @@ static struct tipc_conn *tipc_conn_alloc(struct tipc_topsrv *s)
INIT_WORK(&con->swork, tipc_conn_send_work);
INIT_WORK(&con->rwork, tipc_conn_recv_work);
- spin_lock_bh(&s->idr_lock);
- ret = idr_alloc(&s->conn_idr, con, 0, 0, GFP_ATOMIC);
+ ret = xa_alloc_bh(&s->conns, &con->conid, con, xa_limit_32b,
+ GFP_ATOMIC);
if (ret < 0) {
kfree(con);
- spin_unlock_bh(&s->idr_lock);
return ERR_PTR(-ENOMEM);
}
- con->conid = ret;
- s->idr_in_use++;
- spin_unlock_bh(&s->idr_lock);
set_bit(CF_CONNECTED, &con->flags);
con->server = s;
@@ -215,11 +204,11 @@ static struct tipc_conn *tipc_conn_lookup(struct tipc_topsrv *s, int conid)
{
struct tipc_conn *con;
- spin_lock_bh(&s->idr_lock);
- con = idr_find(&s->conn_idr, conid);
+ xa_lock_bh(&s->conns);
+ con = xa_load(&s->conns, conid);
if (!connected(con) || !kref_get_unless_zero(&con->kref))
con = NULL;
- spin_unlock_bh(&s->idr_lock);
+ xa_unlock_bh(&s->conns);
return con;
}
@@ -655,9 +644,7 @@ static int tipc_topsrv_start(struct net *net)
tn->topsrv = srv;
atomic_set(&tn->subscription_count, 0);
- spin_lock_init(&srv->idr_lock);
- idr_init(&srv->conn_idr);
- srv->idr_in_use = 0;
+ xa_init_flags(&srv->conns, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_BH);
ret = tipc_topsrv_work_start(srv);
if (ret < 0)
@@ -675,24 +662,16 @@ static void tipc_topsrv_stop(struct net *net)
struct tipc_topsrv *srv = tipc_topsrv(net);
struct socket *lsock = srv->listener;
struct tipc_conn *con;
- int id;
-
- spin_lock_bh(&srv->idr_lock);
- for (id = 0; srv->idr_in_use; id++) {
- con = idr_find(&srv->conn_idr, id);
- if (con) {
- spin_unlock_bh(&srv->idr_lock);
- tipc_conn_close(con);
- spin_lock_bh(&srv->idr_lock);
- }
- }
+ unsigned long id;
+
+ xa_for_each(&srv->conns, id, con)
+ tipc_conn_close(con);
+
__module_get(lsock->ops->owner);
__module_get(lsock->sk->sk_prot_creator->owner);
srv->listener = NULL;
- spin_unlock_bh(&srv->idr_lock);
sock_release(lsock);
tipc_topsrv_work_stop(srv);
- idr_destroy(&srv->conn_idr);
kfree(srv);
}
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 37/38] mac80211: Convert ack_status_frames to XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Replace the ack_status_lock with the XArray internal lock. Using the
xa_for_each() iterator lets us inline ieee80211_free_ack_frame().
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
net/mac80211/cfg.c | 13 ++++++-------
net/mac80211/ieee80211_i.h | 3 +--
net/mac80211/main.c | 20 ++++++++------------
net/mac80211/status.c | 6 +++---
net/mac80211/tx.c | 16 ++++++++--------
5 files changed, 26 insertions(+), 32 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index ed56b0c6fe19..47d7670094a9 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3425,24 +3425,23 @@ int ieee80211_attach_ack_skb(struct ieee80211_local *local, struct sk_buff *skb,
{
unsigned long spin_flags;
struct sk_buff *ack_skb;
- int id;
+ int err, id;
ack_skb = skb_copy(skb, gfp);
if (!ack_skb)
return -ENOMEM;
- spin_lock_irqsave(&local->ack_status_lock, spin_flags);
- id = idr_alloc(&local->ack_status_frames, ack_skb,
- 1, 0x10000, GFP_ATOMIC);
- spin_unlock_irqrestore(&local->ack_status_lock, spin_flags);
+ xa_lock_irqsave(&local->ack_status_frames, spin_flags);
+ err = __xa_alloc(&local->ack_status_frames, &id, ack_skb,
+ XA_LIMIT(0, 0xffff), GFP_ATOMIC);
+ xa_unlock_irqrestore(&local->ack_status_frames, spin_flags);
- if (id < 0) {
+ if (err < 0) {
kfree_skb(ack_skb);
return -ENOMEM;
}
IEEE80211_SKB_CB(skb)->ack_frame_id = id;
-
*cookie = ieee80211_mgmt_tx_cookie(local);
IEEE80211_SKB_CB(ack_skb)->ack.cookie = *cookie;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 791ce58d0f09..ade005892099 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1393,8 +1393,7 @@ struct ieee80211_local {
unsigned long hw_roc_start_time;
u64 roc_cookie_counter;
- struct idr ack_status_frames;
- spinlock_t ack_status_lock;
+ struct xarray ack_status_frames;
struct ieee80211_sub_if_data __rcu *p2p_sdata;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 29b9d57df1a3..0d46aa52368a 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -693,8 +693,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
INIT_WORK(&local->tdls_chsw_work, ieee80211_tdls_chsw_work);
- spin_lock_init(&local->ack_status_lock);
- idr_init(&local->ack_status_frames);
+ xa_init_flags(&local->ack_status_frames, XA_FLAGS_ALLOC1);
for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
skb_queue_head_init(&local->pending[i]);
@@ -1353,16 +1352,11 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(ieee80211_unregister_hw);
-static int ieee80211_free_ack_frame(int id, void *p, void *data)
-{
- WARN_ONCE(1, "Have pending ack frames!\n");
- kfree_skb(p);
- return 0;
-}
-
void ieee80211_free_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
+ struct sk_buff *skb;
+ unsigned long index;
enum nl80211_band band;
mutex_destroy(&local->iflist_mtx);
@@ -1371,9 +1365,11 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
if (local->wiphy_ciphers_allocated)
kfree(local->hw.wiphy->cipher_suites);
- idr_for_each(&local->ack_status_frames,
- ieee80211_free_ack_frame, NULL);
- idr_destroy(&local->ack_status_frames);
+ xa_for_each(&local->ack_status_frames, index, skb) {
+ WARN_ONCE(1, "Have pending ack frames!\n");
+ kfree_skb(skb);
+ }
+ xa_destroy(&local->ack_status_frames);
sta_info_stop(local);
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index f03aa8924d23..8f38af968941 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -619,9 +619,9 @@ static void ieee80211_report_ack_skb(struct ieee80211_local *local,
struct sk_buff *skb;
unsigned long flags;
- spin_lock_irqsave(&local->ack_status_lock, flags);
- skb = idr_remove(&local->ack_status_frames, info->ack_frame_id);
- spin_unlock_irqrestore(&local->ack_status_lock, flags);
+ xa_lock_irqsave(&local->ack_status_frames, flags);
+ skb = __xa_erase(&local->ack_status_frames, info->ack_frame_id);
+ xa_unlock_irqrestore(&local->ack_status_frames, flags);
if (!skb)
return;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 235c6377a203..a7c0e3a0dbfb 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2459,7 +2459,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
bool wme_sta = false, authorized = false;
bool tdls_peer;
bool multicast;
- u16 info_id = 0;
+ u32 info_id = 0;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_sub_if_data *ap_sdata;
enum nl80211_band band;
@@ -2721,15 +2721,15 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
if (ack_skb) {
unsigned long flags;
- int id;
+ int err;
- spin_lock_irqsave(&local->ack_status_lock, flags);
- id = idr_alloc(&local->ack_status_frames, ack_skb,
- 1, 0x10000, GFP_ATOMIC);
- spin_unlock_irqrestore(&local->ack_status_lock, flags);
+ xa_lock_irqsave(&local->ack_status_frames, flags);
+ err = __xa_alloc(&local->ack_status_frames, &info_id,
+ ack_skb, XA_LIMIT(0, 0xffff),
+ GFP_ATOMIC);
+ xa_unlock_irqrestore(&local->ack_status_frames, flags);
- if (id >= 0) {
- info_id = id;
+ if (!err) {
info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
} else {
kfree_skb(ack_skb);
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 31/38] cls_flower: Use XArray marks instead of separate list
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Remove the hw_filter list in favour of using one of the XArray mark
bits which lets us iterate more efficiently than walking a linked list.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
net/sched/cls_flower.c | 47 ++++++++++--------------------------------
1 file changed, 11 insertions(+), 36 deletions(-)
diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index 2a1999d2b507..4625de5e29a7 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -85,11 +85,12 @@ struct fl_flow_tmplt {
struct tcf_chain *chain;
};
+#define HW_FILTER XA_MARK_1
+
struct cls_fl_head {
struct rhashtable ht;
spinlock_t masks_lock; /* Protect masks list */
struct list_head masks;
- struct list_head hw_filters;
struct rcu_work rwork;
struct xarray filters;
};
@@ -102,7 +103,6 @@ struct cls_fl_filter {
struct tcf_result res;
struct fl_flow_key key;
struct list_head list;
- struct list_head hw_list;
u32 handle;
u32 flags;
u32 in_hw_count;
@@ -332,7 +332,6 @@ static int fl_init(struct tcf_proto *tp)
spin_lock_init(&head->masks_lock);
INIT_LIST_HEAD_RCU(&head->masks);
- INIT_LIST_HEAD(&head->hw_filters);
rcu_assign_pointer(tp->root, head);
xa_init_flags(&head->filters, XA_FLAGS_ALLOC1);
@@ -421,7 +420,6 @@ static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f,
tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false);
spin_lock(&tp->lock);
- list_del_init(&f->hw_list);
tcf_block_offload_dec(block, &f->flags);
spin_unlock(&tp->lock);
@@ -433,7 +431,6 @@ static int fl_hw_replace_filter(struct tcf_proto *tp,
struct cls_fl_filter *f, bool rtnl_held,
struct netlink_ext_ack *extack)
{
- struct cls_fl_head *head = fl_head_dereference(tp);
struct tcf_block *block = tp->chain->block;
struct flow_cls_offload cls_flower = {};
bool skip_sw = tc_skip_sw(f->flags);
@@ -485,9 +482,6 @@ static int fl_hw_replace_filter(struct tcf_proto *tp,
goto errout;
}
- spin_lock(&tp->lock);
- list_add(&f->hw_list, &head->hw_filters);
- spin_unlock(&tp->lock);
errout:
if (!rtnl_held)
rtnl_unlock();
@@ -1581,7 +1575,6 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
err = -ENOBUFS;
goto errout_tb;
}
- INIT_LIST_HEAD(&fnew->hw_list);
refcount_set(&fnew->refcnt, 1);
err = tcf_exts_init(&fnew->exts, net, TCA_FLOWER_ACT, 0);
@@ -1698,6 +1691,11 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
*arg = fnew;
+ if (!tc_skip_hw(fnew->flags))
+ xa_set_mark(&head->filters, fnew->handle, HW_FILTER);
+ else if (fold)
+ xa_clear_mark(&head->filters, fnew->handle, HW_FILTER);
+
kfree(tb);
tcf_queue_work(&mask->rwork, fl_uninit_mask_free_work);
return 0;
@@ -1770,37 +1768,14 @@ static void fl_walk(struct tcf_proto *tp, struct tcf_walker *arg,
arg->cookie = id;
}
-static struct cls_fl_filter *
-fl_get_next_hw_filter(struct tcf_proto *tp, struct cls_fl_filter *f, bool add)
-{
- struct cls_fl_head *head = fl_head_dereference(tp);
-
- spin_lock(&tp->lock);
- if (list_empty(&head->hw_filters)) {
- spin_unlock(&tp->lock);
- return NULL;
- }
-
- if (!f)
- f = list_entry(&head->hw_filters, struct cls_fl_filter,
- hw_list);
- list_for_each_entry_continue(f, &head->hw_filters, hw_list) {
- if (!(add && f->deleted) && refcount_inc_not_zero(&f->refcnt)) {
- spin_unlock(&tp->lock);
- return f;
- }
- }
-
- spin_unlock(&tp->lock);
- return NULL;
-}
-
static int fl_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb,
void *cb_priv, struct netlink_ext_ack *extack)
{
+ struct cls_fl_head *head = fl_head_dereference(tp);
struct tcf_block *block = tp->chain->block;
struct flow_cls_offload cls_flower = {};
- struct cls_fl_filter *f = NULL;
+ struct cls_fl_filter *f;
+ unsigned long handle;
int err;
/* hw_filters list can only be changed by hw offload functions after
@@ -1809,7 +1784,7 @@ static int fl_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb,
*/
ASSERT_RTNL();
- while ((f = fl_get_next_hw_filter(tp, f, add))) {
+ xa_for_each_marked(&head->filters, handle, f, HW_FILTER) {
cls_flower.rule =
flow_rule_alloc(tcf_exts_num_actions(&f->exts));
if (!cls_flower.rule) {
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 26/38] cls_bpf: Convert handle_idr to XArray
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Rename it to 'progs' as this is what's stored there. The locking is
unchanged, so access to this XArray is protected by both the rtnl lock
and the XArray spinlock.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
net/sched/cls_bpf.c | 28 +++++++++++++---------------
1 file changed, 13 insertions(+), 15 deletions(-)
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
index 3f7a9c02b70c..9a794f557861 100644
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -14,7 +14,7 @@
#include <linux/skbuff.h>
#include <linux/filter.h>
#include <linux/bpf.h>
-#include <linux/idr.h>
+#include <linux/xarray.h>
#include <net/rtnetlink.h>
#include <net/pkt_cls.h>
@@ -30,7 +30,7 @@ MODULE_DESCRIPTION("TC BPF based classifier");
struct cls_bpf_head {
struct list_head plist;
- struct idr handle_idr;
+ struct xarray progs;
struct rcu_head rcu;
};
@@ -242,7 +242,7 @@ static int cls_bpf_init(struct tcf_proto *tp)
return -ENOBUFS;
INIT_LIST_HEAD_RCU(&head->plist);
- idr_init(&head->handle_idr);
+ xa_init_flags(&head->progs, XA_FLAGS_ALLOC1);
rcu_assign_pointer(tp->root, head);
return 0;
@@ -283,7 +283,7 @@ static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog,
{
struct cls_bpf_head *head = rtnl_dereference(tp->root);
- idr_remove(&head->handle_idr, prog->handle);
+ xa_erase(&head->progs, prog->handle);
cls_bpf_stop_offload(tp, prog, extack);
list_del_rcu(&prog->link);
tcf_unbind_filter(tp, &prog->res);
@@ -312,7 +312,7 @@ static void cls_bpf_destroy(struct tcf_proto *tp, bool rtnl_held,
list_for_each_entry_safe(prog, tmp, &head->plist, link)
__cls_bpf_delete(tp, prog, extack);
- idr_destroy(&head->handle_idr);
+ xa_destroy(&head->progs);
kfree_rcu(head, rcu);
}
@@ -484,23 +484,21 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
}
}
+ prog->handle = handle;
if (handle == 0) {
- handle = 1;
- ret = idr_alloc_u32(&head->handle_idr, prog, &handle,
- INT_MAX, GFP_KERNEL);
+ ret = xa_alloc(&head->progs, &prog->handle, prog, xa_limit_31b,
+ GFP_KERNEL);
} else if (!oldprog) {
- ret = idr_alloc_u32(&head->handle_idr, prog, &handle,
- handle, GFP_KERNEL);
+ ret = xa_insert(&head->progs, handle, prog, GFP_KERNEL);
}
if (ret)
goto errout;
- prog->handle = handle;
ret = cls_bpf_set_parms(net, tp, prog, base, tb, tca[TCA_RATE], ovr,
extack);
if (ret < 0)
- goto errout_idr;
+ goto errout_prog;
ret = cls_bpf_offload(tp, prog, oldprog, extack);
if (ret)
@@ -510,7 +508,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
prog->gen_flags |= TCA_CLS_FLAGS_NOT_IN_HW;
if (oldprog) {
- idr_replace(&head->handle_idr, prog, handle);
+ xa_store(&head->progs, handle, prog, 0);
list_replace_rcu(&oldprog->link, &prog->link);
tcf_unbind_filter(tp, &oldprog->res);
tcf_exts_get_net(&oldprog->exts);
@@ -524,9 +522,9 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
errout_parms:
cls_bpf_free_parms(prog);
-errout_idr:
+errout_prog:
if (!oldprog)
- idr_remove(&head->handle_idr, prog->handle);
+ xa_erase(&head->progs, prog->handle);
errout:
tcf_exts_destroy(&prog->exts);
kfree(prog);
--
2.23.0.rc1
^ permalink raw reply related
* [PATCH 27/38] cls_bpf: Remove list of programs
From: Matthew Wilcox @ 2019-08-20 22:32 UTC (permalink / raw)
To: netdev; +Cc: Matthew Wilcox (Oracle)
In-Reply-To: <20190820223259.22348-1-willy@infradead.org>
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Use the XArray for all this functionality. Saves two pointers per
program and it's faster to iterate over an XArray than a linked list.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
net/sched/cls_bpf.c | 38 ++++++++++++++------------------------
1 file changed, 14 insertions(+), 24 deletions(-)
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
index 9a794f557861..295baabdc683 100644
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -29,14 +29,12 @@ MODULE_DESCRIPTION("TC BPF based classifier");
(TCA_CLS_FLAGS_SKIP_HW | TCA_CLS_FLAGS_SKIP_SW)
struct cls_bpf_head {
- struct list_head plist;
struct xarray progs;
struct rcu_head rcu;
};
struct cls_bpf_prog {
struct bpf_prog *filter;
- struct list_head link;
struct tcf_result res;
bool exts_integrated;
u32 gen_flags;
@@ -81,13 +79,14 @@ static int cls_bpf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
struct tcf_result *res)
{
struct cls_bpf_head *head = rcu_dereference_bh(tp->root);
+ XA_STATE(xas, &head->progs, 0);
bool at_ingress = skb_at_tc_ingress(skb);
struct cls_bpf_prog *prog;
int ret = -1;
/* Needed here for accessing maps. */
rcu_read_lock();
- list_for_each_entry_rcu(prog, &head->plist, link) {
+ xas_for_each(&xas, prog, ULONG_MAX) {
int filter_res;
qdisc_skb_cb(skb)->tc_classid = prog->res.classid;
@@ -241,7 +240,6 @@ static int cls_bpf_init(struct tcf_proto *tp)
if (head == NULL)
return -ENOBUFS;
- INIT_LIST_HEAD_RCU(&head->plist);
xa_init_flags(&head->progs, XA_FLAGS_ALLOC1);
rcu_assign_pointer(tp->root, head);
@@ -285,7 +283,6 @@ static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog,
xa_erase(&head->progs, prog->handle);
cls_bpf_stop_offload(tp, prog, extack);
- list_del_rcu(&prog->link);
tcf_unbind_filter(tp, &prog->res);
if (tcf_exts_get_net(&prog->exts))
tcf_queue_work(&prog->rwork, cls_bpf_delete_prog_work);
@@ -299,7 +296,7 @@ static int cls_bpf_delete(struct tcf_proto *tp, void *arg, bool *last,
struct cls_bpf_head *head = rtnl_dereference(tp->root);
__cls_bpf_delete(tp, arg, extack);
- *last = list_empty(&head->plist);
+ *last = xa_empty(&head->progs);
return 0;
}
@@ -307,26 +304,20 @@ static void cls_bpf_destroy(struct tcf_proto *tp, bool rtnl_held,
struct netlink_ext_ack *extack)
{
struct cls_bpf_head *head = rtnl_dereference(tp->root);
- struct cls_bpf_prog *prog, *tmp;
+ struct cls_bpf_prog *prog;
+ unsigned long handle;
- list_for_each_entry_safe(prog, tmp, &head->plist, link)
+ xa_for_each(&head->progs, handle, prog)
__cls_bpf_delete(tp, prog, extack);
- xa_destroy(&head->progs);
kfree_rcu(head, rcu);
}
static void *cls_bpf_get(struct tcf_proto *tp, u32 handle)
{
struct cls_bpf_head *head = rtnl_dereference(tp->root);
- struct cls_bpf_prog *prog;
- list_for_each_entry(prog, &head->plist, link) {
- if (prog->handle == handle)
- return prog;
- }
-
- return NULL;
+ return xa_load(&head->progs, handle);
}
static int cls_bpf_prog_from_ops(struct nlattr **tb, struct cls_bpf_prog *prog)
@@ -509,12 +500,9 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
if (oldprog) {
xa_store(&head->progs, handle, prog, 0);
- list_replace_rcu(&oldprog->link, &prog->link);
tcf_unbind_filter(tp, &oldprog->res);
tcf_exts_get_net(&oldprog->exts);
tcf_queue_work(&oldprog->rwork, cls_bpf_delete_prog_work);
- } else {
- list_add_rcu(&prog->link, &head->plist);
}
*arg = prog;
@@ -636,15 +624,16 @@ static void cls_bpf_walk(struct tcf_proto *tp, struct tcf_walker *arg,
{
struct cls_bpf_head *head = rtnl_dereference(tp->root);
struct cls_bpf_prog *prog;
+ unsigned long handle;
+
+ arg->count = arg->skip;
- list_for_each_entry(prog, &head->plist, link) {
- if (arg->count < arg->skip)
- goto skip;
+ xa_for_each_start(&head->progs, handle, prog, arg->cookie) {
if (arg->fn(tp, prog, arg) < 0) {
arg->stop = 1;
break;
}
-skip:
+ arg->cookie = handle + 1;
arg->count++;
}
}
@@ -656,9 +645,10 @@ static int cls_bpf_reoffload(struct tcf_proto *tp, bool add, flow_setup_cb_t *cb
struct tcf_block *block = tp->chain->block;
struct tc_cls_bpf_offload cls_bpf = {};
struct cls_bpf_prog *prog;
+ unsigned long handle;
int err;
- list_for_each_entry(prog, &head->plist, link) {
+ xa_for_each(&head->progs, handle, prog) {
if (tc_skip_hw(prog->gen_flags))
continue;
--
2.23.0.rc1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox