* DSA driver kernel extension for dsa mv88e6190 switch
From: Zoran Stojsavljevic @ 2019-09-23 18:38 UTC (permalink / raw)
To: netdev
Hello Community,
We have interesting problem to solve using our HW platform. And I hope
somebody has the similar example, and some patches, which need to be
applied to the kernel (directory .../drivers/net/dsa/) to make this
application to work.
We have the configuration problem with the Marvell 88E6190 switch.
What the our problem is... Is the switch is NOT configured with the
EEPROM (24C512), which does not exist on the board. It is put in
autoconfig by HW straps (NOCPU mode). Once the MDIO command, issued to
probe the switch and read the make of it, the switch jumps out of the
autoconfig mode. There are some commands issued from the DSA to
configure the switch (to apply to switch TXC and RXC RGMII delays -
RGMII-ID mode), but this is not enough to make it work properly.
Once the configuration is not properly applied (NOT configured via
EEPROM 24C512). We have problems when the Linux booting phase comes to
LIBPHY. Since switch should be transparent to the PHYs at that time,
but my best guess, it is not!
Once LIBPHY starts writing to the switch (since MDIO commands are not
reaching PHYs), switch blocks. Exists from auto config mode and
refuses to respond (my best guess). So no ping possible on the
MV88E61890 MACs and through after Linux boots.
If we physically cut the MDIO line and put the switch in autoconfig
mode, then switch stays in autoconfig mode (by HW straps), but then it
is impossible to do RGMII TxC and RxC clock skew, since i.MX6 has the
silicon bug which does NOT allow this skew to be applied to i.MX6 (1.5
ns skew MUST be applied to the both clocks). If this done from the
DSA, (having MDIO fully in effect), the switch goes out of autoconfig
and does not finish the proper config.
I have here three questions, I hope there are some educated suggestions?
[1] Does this, what I wrote here, sound resonable (Google has very
little on it)?
[2] Does this problem with MV88E6190 switch could be solved
introducing some MV88E6190 configuration via RGMII mode in U-Boot
(setting the switch in U-boot and letting kernel do what it does, at
the end everything works seamlessly)?
[3] Does anybody have pointer to some similar patches for the DSA
driver addendum (NO U-boot involved), how to properly deal with this
problem and fully configure the switch from Linux DSA driver (chip.c
as switch config, and port.c files)??
Any advice is appreciated!
Thank you in advance,
Zoran
_______
^ permalink raw reply
* [PATCH bpf v2] selftests/bpf: test_progs: fix client/server race in tcp_rtt
From: Stanislav Fomichev @ 2019-09-23 18:41 UTC (permalink / raw)
To: netdev, bpf; +Cc: davem, ast, daniel, Stanislav Fomichev
This is the same problem I found earlier in test_sockopt_inherit:
there is a race between server thread doing accept() and client
thread doing connect(). Let's explicitly synchronize them via
pthread conditional variable.
v2:
* don't exit from server_thread without signaling condvar,
fixes possible issue where main() would wait forever (Andrii Nakryiko)
Fixes: b55873984dab ("selftests/bpf: test BPF_SOCK_OPS_RTT_CB")
Signed-off-by: Stanislav Fomichev <sdf@google.com>
---
.../selftests/bpf/prog_tests/tcp_rtt.c | 21 +++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/tcp_rtt.c b/tools/testing/selftests/bpf/prog_tests/tcp_rtt.c
index fdc0b3614a9e..a82da555b1b0 100644
--- a/tools/testing/selftests/bpf/prog_tests/tcp_rtt.c
+++ b/tools/testing/selftests/bpf/prog_tests/tcp_rtt.c
@@ -203,14 +203,24 @@ static int start_server(void)
return fd;
}
+static pthread_mutex_t server_started_mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t server_started = PTHREAD_COND_INITIALIZER;
+
static void *server_thread(void *arg)
{
struct sockaddr_storage addr;
socklen_t len = sizeof(addr);
int fd = *(int *)arg;
int client_fd;
+ int err;
+
+ err = listen(fd, 1);
+
+ pthread_mutex_lock(&server_started_mtx);
+ pthread_cond_signal(&server_started);
+ pthread_mutex_unlock(&server_started_mtx);
- if (CHECK_FAIL(listen(fd, 1)) < 0) {
+ if (CHECK_FAIL(err < 0)) {
perror("Failed to listed on socket");
return NULL;
}
@@ -248,7 +258,14 @@ void test_tcp_rtt(void)
if (CHECK_FAIL(server_fd < 0))
goto close_cgroup_fd;
- pthread_create(&tid, NULL, server_thread, (void *)&server_fd);
+ if (CHECK_FAIL(pthread_create(&tid, NULL, server_thread,
+ (void *)&server_fd)))
+ goto close_cgroup_fd;
+
+ pthread_mutex_lock(&server_started_mtx);
+ pthread_cond_wait(&server_started, &server_started_mtx);
+ pthread_mutex_unlock(&server_started_mtx);
+
CHECK_FAIL(run_test(cgroup_fd, server_fd));
close(server_fd);
close_cgroup_fd:
--
2.23.0.351.gc4317032e6-goog
^ permalink raw reply related
* Re: CONFIG_NET_TC_SKB_EXT
From: Marcelo Ricardo Leitner @ 2019-09-23 18:46 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Paul Blakey, Pravin Shelar, Daniel Borkmann, Vlad Buslov,
David Miller, netdev@vger.kernel.org, Jiri Pirko, Cong Wang,
Jamal Hadi Salim, Simon Horman, Or Gerlitz
In-Reply-To: <20190922144715.37f71fbf@cakuba.netronome.com>
On Sun, Sep 22, 2019 at 02:47:15PM -0700, Jakub Kicinski wrote:
> On Sun, 22 Sep 2019 14:51:44 +0300, Paul Blakey wrote:
...
> > ------------------------------------------------------------
> >
> > Subject: [PATCH net-next] net/sched: Set default of CONFIG_NET_TC_SKB_EXT to N
> >
> > This a new feature, it is prefered that it defaults to N.
> >
> > Fixes: 95a7233c452a ('net: openvswitch: Set OvS recirc_id from tc chain index')
> > Signed-off-by: Paul Blakey <paulb@mellanox.com>
> > ---
> > net/sched/Kconfig | 1 -
> > 1 file changed, 1 deletion(-)
> >
> > diff --git a/net/sched/Kconfig b/net/sched/Kconfig
> > index b3faafe..4bb10b7 100644
> > --- a/net/sched/Kconfig
> > +++ b/net/sched/Kconfig
> > @@ -966,7 +966,6 @@ config NET_IFE_SKBTCINDEX
> > config NET_TC_SKB_EXT
> > bool "TC recirculation support"
> > depends on NET_CLS_ACT
> > - default y if NET_CLS_ACT
> > select SKB_EXTENSIONS
> >
> > help
>
> - Linus suggested we hide this option from user and autoselect if
> possible.
> - As Daniel said all distros will enable this.
> - If correctness is really our concern, giving users an option to
> select whether they want something to behave correctly seems like
> a hack of lowest kind. Perhaps it's time to add a CONFIG for TC
> offload in general? That's a meaningful set of functionality.
Now that we have the static branch in place on OvS code, maybe we can
remove this option and rely just on NET_CLS_ACT instead (such as in
cls_api.c and skbuff.h).
Probing by OvS userspace is still somewhat possible, as the flag
OVS_DP_F_TC_RECIRC_SHARING wouldn't be known and be rejected
otherwise. 'somewhat because there is a limitation, as prior versions
(prior to this commit) didn't validate if the flags being set were at
least known. But this is not news.
General OvS performance won't suffer, thanks to the static branch.
Drivers won't allocate the skb extension just because. They will only
do it when tc offloading is being done and, as already explained in
the thread and other places, it's needed for correct operation. So
general performance is also ok here.
For tc sw datapath, maybe we can have another static branch in there,
more specifically at tcf_classify(). Not sure how to control/toggle
it, though.
^ permalink raw reply
* Re: [RFC] VSOCK: add support for MSG_PEEK
From: Matias Ezequiel Vara Larsen @ 2019-09-23 19:16 UTC (permalink / raw)
To: Stefano Garzarella
Cc: stefanha, davem, kvm, virtualization, netdev, linux-kernel
In-Reply-To: <20190923075830.a6sjwffnkljmyyqm@steredhat>
On Mon, Sep 23, 2019 at 09:58:30AM +0200, Stefano Garzarella wrote:
> Hi Matias,
> thanks for this patch!
>
> Since this patch only concerns virtio_transport,
> I'd use the 'vsock/virtio' prefix in the commit title:
> "vsock/virtio: add support for MSG_PEEK"
>
> Some comments below:
>
> On Sun, Sep 22, 2019 at 05:48:27PM +0000, Matias Ezequiel Vara Larsen wrote:
> > This patch adds support for MSG_PEEK. In such a case, packets are not
> > removed from the rx_queue and credit updates are not sent.
> >
> > Signed-off-by: Matias Ezequiel Vara Larsen <matiasevara@gmail.com>
> > ---
> > net/vmw_vsock/virtio_transport_common.c | 59 +++++++++++++++++++++++++++++++--
> > 1 file changed, 56 insertions(+), 3 deletions(-)
> >
> > diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
> > index 94cc0fa..830e890 100644
> > --- a/net/vmw_vsock/virtio_transport_common.c
> > +++ b/net/vmw_vsock/virtio_transport_common.c
> > @@ -264,6 +264,59 @@ static int virtio_transport_send_credit_update(struct vsock_sock *vsk,
> > }
> >
> > static ssize_t
> > +virtio_transport_stream_do_peek(struct vsock_sock *vsk,
> > + struct msghdr *msg,
> > + size_t len)
> > +{
> > + struct virtio_vsock_sock *vvs = vsk->trans;
> > + struct virtio_vsock_pkt *pkt;
> > + size_t bytes, off = 0, total = 0;
> > + int err = -EFAULT;
> > +
> > + spin_lock_bh(&vvs->rx_lock);
> > +
>
> What about using list_for_each_entry() to cycle through the queued packets?
>
> > + if (list_empty(&vvs->rx_queue)) {
> > + spin_unlock_bh(&vvs->rx_lock);
> > + return 0;
> > + }
> > +
> > + pkt = list_first_entry(&vvs->rx_queue,
> > + struct virtio_vsock_pkt, list);
> > + do {
>
> pkt->off contains the offset inside the packet where the unread data starts.
> So here we should initialize 'off':
>
> off = pkt->off;
>
> Or just use pkt->off later (without increasing it as in the dequeue).
>
> > + bytes = len - total;
> > + if (bytes > pkt->len - off)
> > + bytes = pkt->len - off;
> > +
> > + /* sk_lock is held by caller so no one else can dequeue.
> > + * Unlock rx_lock since memcpy_to_msg() may sleep.
> > + */
> > + spin_unlock_bh(&vvs->rx_lock);
> > +
> > + err = memcpy_to_msg(msg, pkt->buf + off, bytes);
> > + if (err)
> > + goto out;
> > +
> > + spin_lock_bh(&vvs->rx_lock);
> > +
> > + total += bytes;
>
> Using list_for_each_entry(), here we can just do:
> (or better, at the beginning of the cycle)
>
> if (total == len)
> break;
>
> removing the next part...
>
> > + off += bytes;
> > + if (off == pkt->len) {
> > + pkt = list_next_entry(pkt, list);
> > + off = 0;
> > + }
> > + } while ((total < len) && !list_is_first(&pkt->list, &vvs->rx_queue));
>
> ...until here.
>
> > +
> > + spin_unlock_bh(&vvs->rx_lock);
> > +
> > + return total;
> > +
> > +out:
> > + if (total)
> > + err = total;
> > + return err;
> > +}
> > +
> > +static ssize_t
> > virtio_transport_stream_do_dequeue(struct vsock_sock *vsk,
> > struct msghdr *msg,
> > size_t len)
> > @@ -330,9 +383,9 @@ virtio_transport_stream_dequeue(struct vsock_sock *vsk,
> > size_t len, int flags)
> > {
> > if (flags & MSG_PEEK)
> > - return -EOPNOTSUPP;
> > -
> > - return virtio_transport_stream_do_dequeue(vsk, msg, len);
> > + return virtio_transport_stream_do_peek(vsk, msg, len);
> > + else
> > + return virtio_transport_stream_do_dequeue(vsk, msg, len);
> > }
> > EXPORT_SYMBOL_GPL(virtio_transport_stream_dequeue);
> >
>
> The rest looks good to me!
>
> Thanks,
> Stefano
Thanks Stefano. Based on your comments, I will modify the patch and
resubmit it.
Matias
^ permalink raw reply
* Re: DSA driver kernel extension for dsa mv88e6190 switch
From: Andrew Lunn @ 2019-09-23 19:17 UTC (permalink / raw)
To: Zoran Stojsavljevic; +Cc: netdev
In-Reply-To: <CAGAf8LzeyrMSHCYMxn1FNtMQVyhhLYbJaczhe2AMj+7T_nBt7Q@mail.gmail.com>
> We have the configuration problem with the Marvell 88E6190 switch.
> What the our problem is... Is the switch is NOT configured with the
> EEPROM (24C512), which does not exist on the board.
That is pretty normal. If there is a EEPROM, i generally recommend it
is left empty. We want Linux to configure the switch, and if it finds
it already partially configured, things can get confused.
> It is put in autoconfig by HW straps (NOCPU mode).
So dumb switch mode. All ports are switched between each other.
> Once the MDIO command, issued to
> probe the switch and read the make of it, the switch jumps out of the
> autoconfig mode.
Correct. Dumb switch mode is dangerous. There is no STP, etc.
Depending on what you have in device tree, the ports are either
configured down, or separated.
> There are some commands issued from the DSA to
> configure the switch (to apply to switch TXC and RXC RGMII delays -
> RGMII-ID mode), but this is not enough to make it work properly.
Define 'work properly'. How are you configuring the interfaces? Do
you remember to bring the master interface up? Are you adding the
interfaces to a bridge?
Andrew
^ permalink raw reply
* Re: [PATCH] Bluetooth: hidp: Fix assumptions on the return value of hidp_send_message
From: Andrey Smirnov @ 2019-09-23 20:33 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Andrey Smirnov, Pierre-Loup A . Griffais, linux-input,
linux-kernel, linux-bluetooth, netdev
In-Reply-To: <3D70AB75-FEFB-4EB3-9AC8-3BCE90F5458D@holtmann.org>
> I am taking this through my tree. And yes, I applied the updated patch, but answered the other ;)
>
> Regards
>
> Marcel
Are you also going to mark this patch for inclusion to stable tree? I haven't seen it in any of the stable queues (netdev, Greg's), so just wanted to check.
Thanks,
Andrey Smirnov
^ permalink raw reply
* RE: [PATCH 1/6] mdev: class id support
From: Parav Pandit @ 2019-09-23 20:58 UTC (permalink / raw)
To: Jason Wang, kvm@vger.kernel.org, linux-s390@vger.kernel.org,
linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
intel-gfx@lists.freedesktop.org,
intel-gvt-dev@lists.freedesktop.org, kwankhede@nvidia.com,
alex.williamson@redhat.com, mst@redhat.com, tiwei.bie@intel.com
Cc: virtualization@lists.linux-foundation.org, netdev@vger.kernel.org,
cohuck@redhat.com, maxime.coquelin@redhat.com,
cunming.liang@intel.com, zhihong.wang@intel.com,
rob.miller@broadcom.com, xiao.w.wang@intel.com,
haotian.wang@sifive.com, zhenyuw@linux.intel.com,
zhi.a.wang@intel.com, jani.nikula@linux.intel.com,
joonas.lahtinen@linux.intel.com, rodrigo.vivi@intel.com,
airlied@linux.ie, daniel@ffwll.ch, farman@linux.ibm.com,
pasic@linux.ibm.com, sebott@linux.ibm.com, oberpar@linux.ibm.com,
heiko.carstens@de.ibm.com, gor@linux.ibm.com,
borntraeger@de.ibm.com, akrowiak@linux.ibm.com,
freude@linux.ibm.com, lingshan.zhu@intel.com, Ido Shamay,
eperezma@redhat.com, lulu@redhat.com
In-Reply-To: <20190923130331.29324-2-jasowang@redhat.com>
Hi Jason,
> -----Original Message-----
> From: Jason Wang <jasowang@redhat.com>
> Sent: Monday, September 23, 2019 8:03 AM
> To: kvm@vger.kernel.org; linux-s390@vger.kernel.org; linux-
> kernel@vger.kernel.org; dri-devel@lists.freedesktop.org; intel-
> gfx@lists.freedesktop.org; intel-gvt-dev@lists.freedesktop.org;
> kwankhede@nvidia.com; alex.williamson@redhat.com; mst@redhat.com;
> tiwei.bie@intel.com
> Cc: virtualization@lists.linux-foundation.org; netdev@vger.kernel.org;
> cohuck@redhat.com; maxime.coquelin@redhat.com;
> cunming.liang@intel.com; zhihong.wang@intel.com;
> rob.miller@broadcom.com; xiao.w.wang@intel.com;
> haotian.wang@sifive.com; zhenyuw@linux.intel.com; zhi.a.wang@intel.com;
> jani.nikula@linux.intel.com; joonas.lahtinen@linux.intel.com;
> rodrigo.vivi@intel.com; airlied@linux.ie; daniel@ffwll.ch;
> farman@linux.ibm.com; pasic@linux.ibm.com; sebott@linux.ibm.com;
> oberpar@linux.ibm.com; heiko.carstens@de.ibm.com; gor@linux.ibm.com;
> borntraeger@de.ibm.com; akrowiak@linux.ibm.com; freude@linux.ibm.com;
> lingshan.zhu@intel.com; Ido Shamay <idos@mellanox.com>;
> eperezma@redhat.com; lulu@redhat.com; Parav Pandit
> <parav@mellanox.com>; Jason Wang <jasowang@redhat.com>
> Subject: [PATCH 1/6] mdev: class id support
>
> Mdev bus only supports vfio driver right now, so it doesn't implement match
> method. But in the future, we may add drivers other than vfio, one example is
> virtio-mdev[1] driver. This means we need to add device class id support in bus
> match method to pair the mdev device and mdev driver correctly.
>
> So this patch adds id_table to mdev_driver and class_id for mdev parent with
> the match method for mdev bus.
>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> Documentation/driver-api/vfio-mediated-device.rst | 7 +++++--
> drivers/gpu/drm/i915/gvt/kvmgt.c | 2 +-
> drivers/s390/cio/vfio_ccw_ops.c | 2 +-
> drivers/s390/crypto/vfio_ap_ops.c | 3 ++-
> drivers/vfio/mdev/mdev_core.c | 14 ++++++++++++--
> drivers/vfio/mdev/mdev_driver.c | 14 ++++++++++++++
> drivers/vfio/mdev/mdev_private.h | 1 +
> drivers/vfio/mdev/vfio_mdev.c | 6 ++++++
> include/linux/mdev.h | 7 ++++++-
> include/linux/mod_devicetable.h | 8 ++++++++
> samples/vfio-mdev/mbochs.c | 2 +-
> samples/vfio-mdev/mdpy.c | 2 +-
> samples/vfio-mdev/mtty.c | 2 +-
> 13 files changed, 59 insertions(+), 11 deletions(-)
>
> diff --git a/Documentation/driver-api/vfio-mediated-device.rst
> b/Documentation/driver-api/vfio-mediated-device.rst
> index 25eb7d5b834b..0e052072e1d8 100644
> --- a/Documentation/driver-api/vfio-mediated-device.rst
> +++ b/Documentation/driver-api/vfio-mediated-device.rst
> @@ -102,12 +102,14 @@ structure to represent a mediated device's driver::
> * @probe: called when new device created
> * @remove: called when device removed
> * @driver: device driver structure
> + * @id_table: the ids serviced by this driver.
No full stop at the end.
> */
> struct mdev_driver {
> const char *name;
> int (*probe) (struct device *dev);
> void (*remove) (struct device *dev);
> struct device_driver driver;
> + const struct mdev_class_id *id_table;
> };
>
> A mediated bus driver for mdev should use this structure in the function calls
> @@ -116,7 +118,7 @@ to register and unregister itself with the core driver:
> * Register::
>
> extern int mdev_register_driver(struct mdev_driver *drv,
> - struct module *owner);
> + struct module *owner);
>
Unrelated change in this patch.
> * Unregister::
>
> @@ -163,7 +165,8 @@ A driver should use the mdev_parent_ops structure in
> the function call to register itself with the mdev core driver::
>
> extern int mdev_register_device(struct device *dev,
> - const struct mdev_parent_ops *ops);
> + const struct mdev_parent_ops *ops,
> + u8 class_id);
>
Cover letter from Change-V2 says that it class_id changed from " use u16 instead u8 for class id"
But it is still u8 here?
> However, the mdev_parent_ops structure is not required in the function call
> that a driver should use to unregister itself with the mdev core driver::
> diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c
> b/drivers/gpu/drm/i915/gvt/kvmgt.c
> index 23aa3e50cbf8..19d51a35f019 100644
> --- a/drivers/gpu/drm/i915/gvt/kvmgt.c
> +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
> @@ -1625,7 +1625,7 @@ static int kvmgt_host_init(struct device *dev, void
> *gvt, const void *ops)
> return -EFAULT;
> intel_vgpu_ops.supported_type_groups = kvm_vgpu_type_groups;
>
> - return mdev_register_device(dev, &intel_vgpu_ops);
> + return mdev_register_vfio_device(dev, &intel_vgpu_ops);
> }
>
> static void kvmgt_host_exit(struct device *dev) diff --git
> a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c index
> f0d71ab77c50..246ff0f80944 100644
> --- a/drivers/s390/cio/vfio_ccw_ops.c
> +++ b/drivers/s390/cio/vfio_ccw_ops.c
> @@ -588,7 +588,7 @@ static const struct mdev_parent_ops
> vfio_ccw_mdev_ops = {
>
> int vfio_ccw_mdev_reg(struct subchannel *sch) {
> - return mdev_register_device(&sch->dev, &vfio_ccw_mdev_ops);
> + return mdev_register_vfio_device(&sch->dev, &vfio_ccw_mdev_ops);
> }
>
> void vfio_ccw_mdev_unreg(struct subchannel *sch) diff --git
> a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
> index 5c0f53c6dde7..7487fc39d2c5 100644
> --- a/drivers/s390/crypto/vfio_ap_ops.c
> +++ b/drivers/s390/crypto/vfio_ap_ops.c
> @@ -1295,7 +1295,8 @@ int vfio_ap_mdev_register(void) {
> atomic_set(&matrix_dev->available_instances,
> MAX_ZDEV_ENTRIES_EXT);
>
> - return mdev_register_device(&matrix_dev->device,
> &vfio_ap_matrix_ops);
> + return mdev_register_vfio_device(&matrix_dev->device,
> + &vfio_ap_matrix_ops);
> }
>
> void vfio_ap_mdev_unregister(void)
> diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c
> index b558d4cfd082..a02c256a3514 100644
> --- a/drivers/vfio/mdev/mdev_core.c
> +++ b/drivers/vfio/mdev/mdev_core.c
> @@ -135,11 +135,14 @@ static int mdev_device_remove_cb(struct device
> *dev, void *data)
> * mdev_register_device : Register a device
> * @dev: device structure representing parent device.
> * @ops: Parent device operation structure to be registered.
> + * @id: device id.
> *
It device id here, but in below its class_id. Please make them uniform.
> * Add device to list of registered parent devices.
> * Returns a negative value on error, otherwise 0.
> */
> -int mdev_register_device(struct device *dev, const struct mdev_parent_ops
> *ops)
> +int mdev_register_device(struct device *dev,
> + const struct mdev_parent_ops *ops,
> + u8 class_id)
> {
u16 class_id?
> int ret;
> struct mdev_parent *parent;
> @@ -175,6 +178,7 @@ int mdev_register_device(struct device *dev, const
> struct mdev_parent_ops *ops)
>
> parent->dev = dev;
> parent->ops = ops;
> + parent->class_id = class_id;
>
> if (!mdev_bus_compat_class) {
> mdev_bus_compat_class =
> class_compat_register("mdev_bus");
> @@ -208,7 +212,13 @@ int mdev_register_device(struct device *dev, const
> struct mdev_parent_ops *ops)
> put_device(dev);
> return ret;
> }
> -EXPORT_SYMBOL(mdev_register_device);
> +
> +int mdev_register_vfio_device(struct device *dev,
> + const struct mdev_parent_ops *ops) {
> + return mdev_register_device(dev, ops, MDEV_ID_VFIO); }
> +EXPORT_SYMBOL(mdev_register_vfio_device);
>
> /*
> * mdev_unregister_device : Unregister a parent device diff --git
> a/drivers/vfio/mdev/mdev_driver.c b/drivers/vfio/mdev/mdev_driver.c index
> 0d3223aee20b..b70bbebc9dd3 100644
> --- a/drivers/vfio/mdev/mdev_driver.c
> +++ b/drivers/vfio/mdev/mdev_driver.c
> @@ -69,8 +69,22 @@ static int mdev_remove(struct device *dev)
> return 0;
> }
>
> +static int mdev_match(struct device *dev, struct device_driver *drv) {
> + unsigned int i;
> + struct mdev_device *mdev = to_mdev_device(dev);
> + struct mdev_driver *mdrv = to_mdev_driver(drv);
> + const struct mdev_class_id *ids = mdrv->id_table;
> +
> + for (i = 0; ids[i].id; i++)
> + if (ids[i].id == mdev->parent->class_id)
> + return 1;
> + return 0;
> +}
> +
> struct bus_type mdev_bus_type = {
> .name = "mdev",
> + .match = mdev_match,
> .probe = mdev_probe,
> .remove = mdev_remove,
> };
> diff --git a/drivers/vfio/mdev/mdev_private.h
> b/drivers/vfio/mdev/mdev_private.h
> index 7d922950caaf..e58b07c866b1 100644
> --- a/drivers/vfio/mdev/mdev_private.h
> +++ b/drivers/vfio/mdev/mdev_private.h
> @@ -22,6 +22,7 @@ struct mdev_parent {
> struct list_head type_list;
> /* Synchronize device creation/removal with parent unregistration */
> struct rw_semaphore unreg_sem;
> + u8 class_id;
> };
>
> struct mdev_device {
> diff --git a/drivers/vfio/mdev/vfio_mdev.c b/drivers/vfio/mdev/vfio_mdev.c
> index 30964a4e0a28..fd2a4d9a3f26 100644
> --- a/drivers/vfio/mdev/vfio_mdev.c
> +++ b/drivers/vfio/mdev/vfio_mdev.c
> @@ -120,10 +120,16 @@ static void vfio_mdev_remove(struct device *dev)
> vfio_del_group_dev(dev);
> }
>
> +static struct mdev_class_id id_table[] = {
> + { MDEV_ID_VFIO },
> + { 0 },
> +};
> +
> static struct mdev_driver vfio_mdev_driver = {
> .name = "vfio_mdev",
> .probe = vfio_mdev_probe,
> .remove = vfio_mdev_remove,
> + .id_table = id_table,
> };
>
> static int __init vfio_mdev_init(void)
> diff --git a/include/linux/mdev.h b/include/linux/mdev.h index
> 0ce30ca78db0..3ebae310f599 100644
> --- a/include/linux/mdev.h
> +++ b/include/linux/mdev.h
> @@ -118,6 +118,7 @@ struct mdev_type_attribute mdev_type_attr_##_name
> = \
> * @probe: called when new device created
> * @remove: called when device removed
> * @driver: device driver structure
> + * @id_table: the ids serviced by this driver.
> *
> **/
> struct mdev_driver {
> @@ -125,6 +126,7 @@ struct mdev_driver {
> int (*probe)(struct device *dev);
> void (*remove)(struct device *dev);
> struct device_driver driver;
> + const struct mdev_class_id *id_table;
> };
>
> #define to_mdev_driver(drv) container_of(drv, struct mdev_driver, driver)
> @@ -135,7 +137,8 @@ const guid_t *mdev_uuid(struct mdev_device *mdev);
>
> extern struct bus_type mdev_bus_type;
>
> -int mdev_register_device(struct device *dev, const struct mdev_parent_ops
> *ops);
> +int mdev_register_vfio_device(struct device *dev,
> + const struct mdev_parent_ops *ops);
> void mdev_unregister_device(struct device *dev);
>
> int mdev_register_driver(struct mdev_driver *drv, struct module *owner);
> @@ -145,4 +148,6 @@ struct device *mdev_parent_dev(struct mdev_device
> *mdev); struct device *mdev_dev(struct mdev_device *mdev); struct
> mdev_device *mdev_from_dev(struct device *dev);
>
> +#define MDEV_ID_VFIO 1 /* VFIO device */
> +
Instead of define, please put them as enum
enum mdev_class/device_id {
MDEV_ID_VFIO = 1,
/* New entries must be added here */
};
> #endif /* MDEV_H */
> diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
> index 5714fd35a83c..f32c6e44fb1a 100644
> --- a/include/linux/mod_devicetable.h
> +++ b/include/linux/mod_devicetable.h
> @@ -821,4 +821,12 @@ struct wmi_device_id {
> const void *context;
> };
>
> +/**
> + * struct mdev_class_id - MDEV device class identifier
> + * @id: Used to identify a specific class of device, e.g vfio-mdev device.
> + */
> +struct mdev_class_id {
> + __u16 id;
> +};
This is u16 as I guess you wanted as opposed to u8 in other places in patch.
> +
> #endif /* LINUX_MOD_DEVICETABLE_H */
> diff --git a/samples/vfio-mdev/mbochs.c b/samples/vfio-mdev/mbochs.c index
> ac5c8c17b1ff..71a4469be85d 100644
> --- a/samples/vfio-mdev/mbochs.c
> +++ b/samples/vfio-mdev/mbochs.c
> @@ -1468,7 +1468,7 @@ static int __init mbochs_dev_init(void)
> if (ret)
> goto failed2;
>
> - ret = mdev_register_device(&mbochs_dev, &mdev_fops);
> + ret = mdev_register_vfio_device(&mbochs_dev, &mdev_fops);
> if (ret)
> goto failed3;
>
> diff --git a/samples/vfio-mdev/mdpy.c b/samples/vfio-mdev/mdpy.c index
> cc86bf6566e4..d3029dd27d91 100644
> --- a/samples/vfio-mdev/mdpy.c
> +++ b/samples/vfio-mdev/mdpy.c
> @@ -775,7 +775,7 @@ static int __init mdpy_dev_init(void)
> if (ret)
> goto failed2;
>
> - ret = mdev_register_device(&mdpy_dev, &mdev_fops);
> + ret = mdev_register_vfio_device(&mdpy_dev, &mdev_fops);
> if (ret)
> goto failed3;
>
> diff --git a/samples/vfio-mdev/mtty.c b/samples/vfio-mdev/mtty.c index
> 92e770a06ea2..744c88a6b22c 100644
> --- a/samples/vfio-mdev/mtty.c
> +++ b/samples/vfio-mdev/mtty.c
> @@ -1468,7 +1468,7 @@ static int __init mtty_dev_init(void)
> if (ret)
> goto failed2;
>
> - ret = mdev_register_device(&mtty_dev.dev, &mdev_fops);
> + ret = mdev_register_vfio_device(&mtty_dev.dev, &mdev_fops);
> if (ret)
> goto failed3;
>
> --
> 2.19.1
^ permalink raw reply
* RE: [PATCH 1/6] mdev: class id support
From: Parav Pandit @ 2019-09-23 21:02 UTC (permalink / raw)
To: Jason Wang, kvm@vger.kernel.org, linux-s390@vger.kernel.org,
linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
intel-gfx@lists.freedesktop.org,
intel-gvt-dev@lists.freedesktop.org, kwankhede@nvidia.com,
alex.williamson@redhat.com, mst@redhat.com, tiwei.bie@intel.com
Cc: virtualization@lists.linux-foundation.org, netdev@vger.kernel.org,
cohuck@redhat.com, maxime.coquelin@redhat.com,
cunming.liang@intel.com, zhihong.wang@intel.com,
rob.miller@broadcom.com, xiao.w.wang@intel.com,
haotian.wang@sifive.com, zhenyuw@linux.intel.com,
zhi.a.wang@intel.com, jani.nikula@linux.intel.com,
joonas.lahtinen@linux.intel.com, rodrigo.vivi@intel.com,
airlied@linux.ie, daniel@ffwll.ch, farman@linux.ibm.com,
pasic@linux.ibm.com, sebott@linux.ibm.com, oberpar@linux.ibm.com,
heiko.carstens@de.ibm.com, gor@linux.ibm.com,
borntraeger@de.ibm.com, akrowiak@linux.ibm.com,
freude@linux.ibm.com, lingshan.zhu@intel.com, Ido Shamay,
eperezma@redhat.com, lulu@redhat.com
In-Reply-To: <20190923130331.29324-2-jasowang@redhat.com>
Hi Jason,
> -----Original Message-----
> From: Jason Wang <jasowang@redhat.com>
> Sent: Monday, September 23, 2019 8:03 AM
> To: kvm@vger.kernel.org; linux-s390@vger.kernel.org; linux-
> kernel@vger.kernel.org; dri-devel@lists.freedesktop.org; intel-
> gfx@lists.freedesktop.org; intel-gvt-dev@lists.freedesktop.org;
> kwankhede@nvidia.com; alex.williamson@redhat.com; mst@redhat.com;
> tiwei.bie@intel.com
> Cc: virtualization@lists.linux-foundation.org; netdev@vger.kernel.org;
> cohuck@redhat.com; maxime.coquelin@redhat.com;
> cunming.liang@intel.com; zhihong.wang@intel.com;
> rob.miller@broadcom.com; xiao.w.wang@intel.com;
> haotian.wang@sifive.com; zhenyuw@linux.intel.com; zhi.a.wang@intel.com;
> jani.nikula@linux.intel.com; joonas.lahtinen@linux.intel.com;
> rodrigo.vivi@intel.com; airlied@linux.ie; daniel@ffwll.ch;
> farman@linux.ibm.com; pasic@linux.ibm.com; sebott@linux.ibm.com;
> oberpar@linux.ibm.com; heiko.carstens@de.ibm.com; gor@linux.ibm.com;
> borntraeger@de.ibm.com; akrowiak@linux.ibm.com; freude@linux.ibm.com;
> lingshan.zhu@intel.com; Ido Shamay <idos@mellanox.com>;
> eperezma@redhat.com; lulu@redhat.com; Parav Pandit
> <parav@mellanox.com>; Jason Wang <jasowang@redhat.com>
> Subject: [PATCH 1/6] mdev: class id support
>
> Mdev bus only supports vfio driver right now, so it doesn't implement match
> method. But in the future, we may add drivers other than vfio, one example is
> virtio-mdev[1] driver. This means we need to add device class id support in bus
> match method to pair the mdev device and mdev driver correctly.
>
> So this patch adds id_table to mdev_driver and class_id for mdev parent with
> the match method for mdev bus.
>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> Documentation/driver-api/vfio-mediated-device.rst | 7 +++++--
> drivers/gpu/drm/i915/gvt/kvmgt.c | 2 +-
> drivers/s390/cio/vfio_ccw_ops.c | 2 +-
> drivers/s390/crypto/vfio_ap_ops.c | 3 ++-
> drivers/vfio/mdev/mdev_core.c | 14 ++++++++++++--
> drivers/vfio/mdev/mdev_driver.c | 14 ++++++++++++++
> drivers/vfio/mdev/mdev_private.h | 1 +
> drivers/vfio/mdev/vfio_mdev.c | 6 ++++++
> include/linux/mdev.h | 7 ++++++-
> include/linux/mod_devicetable.h | 8 ++++++++
> samples/vfio-mdev/mbochs.c | 2 +-
> samples/vfio-mdev/mdpy.c | 2 +-
> samples/vfio-mdev/mtty.c | 2 +-
> 13 files changed, 59 insertions(+), 11 deletions(-)
>
You additionally need modpost support for id table integration to modifo, modprobe and other tools.
A small patch similar to this one [1] is needed.
Please include in the series.
[1] https://lore.kernel.org/patchwork/patch/1046991/
^ permalink raw reply
* Re: [PATCH net] net: sched: fix possible crash in tcf_action_destroy()
From: Cong Wang @ 2019-09-23 21:10 UTC (permalink / raw)
To: Eric Dumazet
Cc: Jakub Kicinski, Eric Dumazet, David S . Miller, netdev, syzbot,
Vlad Buslov, Jiri Pirko
In-Reply-To: <4e2ff069-e1f5-492f-14eb-5348e2cab907@gmail.com>
On Mon, Sep 23, 2019 at 8:44 AM Eric Dumazet <eric.dumazet@gmail.com> wrote:
>
>
>
> On 9/21/19 7:08 PM, Jakub Kicinski wrote:
> > On Wed, 18 Sep 2019 14:37:21 -0700, Cong Wang wrote:
> >> On Wed, Sep 18, 2019 at 12:57 PM 'Eric Dumazet' via syzkaller
> >> <syzkaller@googlegroups.com> wrote:
> >>>
> >>> If the allocation done in tcf_exts_init() failed,
> >>> we end up with a NULL pointer in exts->actions.
> >> ...
> >>> diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
> >>> index efd3cfb80a2ad775dc8ab3c4900bd73d52c7aaad..9aef93300f1c11791acbb9262dfe77996872eafe 100644
> >>> --- a/net/sched/cls_api.c
> >>> +++ b/net/sched/cls_api.c
> >>> @@ -3027,8 +3027,10 @@ static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb)
> >>> void tcf_exts_destroy(struct tcf_exts *exts)
> >>> {
> >>> #ifdef CONFIG_NET_CLS_ACT
> >>> - tcf_action_destroy(exts->actions, TCA_ACT_UNBIND);
> >>> - kfree(exts->actions);
> >>> + if (exts->actions) {
> >>
> >> I think it is _slightly_ better to check exts->nr_actions!=0 here,
> >> as it would help exts->actions!=NULL&& exts->nr_actions==0
> >> cases too.
> >>
> >> What do you think?
> >
> > Alternatively, since tcf_exts_destroy() now takes NULL, and so
> > obviously does kfree() - perhaps tcf_action_destroy() should
> > return early if actions are NULL?
> >
>
> I do not have any preference really, this is slow path and was trying to
> fix a crash.
>
> tcf_action_destroy() makes me nervous, since it seems to be able to break its loop
> in case __tcf_idr_release() returns an error. This means that some actions will
> never be release.
Good point. Seems we can just continue the loop even when
-EPERM is returned, there is in fact no harm to leave those still
bound to filters there until the filers release them. Not sure if we
should still propagate -EPERM to users in this partially failure
case.
^ permalink raw reply
* Re: [PATCH] kcm: use BPF_PROG_RUN
From: Eric Dumazet @ 2019-09-23 21:31 UTC (permalink / raw)
To: Alexei Starovoitov, Yonghong Song
Cc: Sami Tolvanen, David S. Miller, Tom Herbert,
netdev@vger.kernel.org, bpf@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <CAADnVQJxrPDZtKAik4VEzvw=TwY6PoWytfp7HcQt5Jsaja7mxw@mail.gmail.com>
On 9/6/19 10:06 AM, Alexei Starovoitov wrote:
> On Fri, Sep 6, 2019 at 3:03 AM Yonghong Song <yhs@fb.com> wrote:
>>
>>
>>
>> On 9/5/19 2:15 PM, Sami Tolvanen wrote:
>>> Instead of invoking struct bpf_prog::bpf_func directly, use the
>>> BPF_PROG_RUN macro.
>>>
>>> Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
>>
>> Acked-by: Yonghong Song <yhs@fb.com>
>
> Applied. Thanks
>
Then we probably need this as well, what do you think ?
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c
index 8f12f5c6ab875ebaa6c59c6268c337919fb43bb9..6508e88efdaf57f206b84307f5ad5915a2ed21f7 100644
--- a/net/kcm/kcmsock.c
+++ b/net/kcm/kcmsock.c
@@ -378,8 +378,13 @@ static int kcm_parse_func_strparser(struct strparser *strp, struct sk_buff *skb)
{
struct kcm_psock *psock = container_of(strp, struct kcm_psock, strp);
struct bpf_prog *prog = psock->bpf_prog;
+ int res;
- return BPF_PROG_RUN(prog, skb);
+ preempt_disable();
+ res = BPF_PROG_RUN(prog, skb);
+ preempt_enable();
+
+ return res;
}
static int kcm_read_sock_done(struct strparser *strp, int err)
^ permalink raw reply related
* [linux-firmware][pull request] ice: Add package file for Intel E800 series driver
From: Jeff Kirsher @ 2019-09-23 21:56 UTC (permalink / raw)
To: linux-firmware
Cc: Tony Nguyen, netdev, nhorman, sassmann, poswald, Andrew Bowers,
Jeff Kirsher
From: Tony Nguyen <anthony.l.nguyen@intel.com>
The ice driver must load a package file to the firmware to utilize full
functionality; add the package file to /lib/firmware/intel/ice/ddp. Also
add a symlink, ice.pkg, so the driver can refer to the package by a
consistent name.
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
The following are changes since commit 417a9c6e197a8d3eec792494efc87a2b42f76324:
amdgpu: add initial navi10 firmware
and are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/firmware dev-queue
LICENSE.ice | 39 ++++++++++++++++++++++++++++++++++
WHENCE | 9 ++++++++
intel/ice/ddp/ice-1.3.4.0.pkg | Bin 0 -> 577796 bytes
intel/ice/ddp/ice.pkg | 1 +
4 files changed, 49 insertions(+)
create mode 100644 LICENSE.ice
create mode 100644 intel/ice/ddp/ice-1.3.4.0.pkg
create mode 120000 intel/ice/ddp/ice.pkg
diff --git a/LICENSE.ice b/LICENSE.ice
new file mode 100644
index 0000000..497ee18
--- /dev/null
+++ b/LICENSE.ice
@@ -0,0 +1,39 @@
+Copyright (c) 2019, Intel Corporation.
+All rights reserved.
+
+Redistribution. Redistribution and use in binary form, without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions must reproduce the above copyright notice and the
+ following disclaimer in the documentation and/or other materials
+ provided with the distribution.
+* Neither the name of Intel Corporation nor the names of its suppliers
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+* No reverse engineering, decompilation, or disassembly of this software
+ is permitted.
+
+Limited patent license. Intel Corporation grants a world-wide,
+royalty-free, non-exclusive license under patents it now or hereafter
+owns or controls to make, have made, use, import, offer to sell and
+sell ("Utilize") this software, but solely to the extent that any
+such patent is necessary to Utilize the software alone, or in
+combination with an operating system licensed under an approved Open
+Source license as listed by the Open Source Initiative at
+http://opensource.org/licenses. The patent license shall not apply to
+any other combinations which include this software. No hardware per
+se is licensed hereunder.
+
+DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
diff --git a/WHENCE b/WHENCE
index 55ab617..5f9abb1 100644
--- a/WHENCE
+++ b/WHENCE
@@ -4585,3 +4585,12 @@ File: meson/vdec/gxl_mpeg4_5.bin
File: meson/vdec/gxm_h264.bin
Licence: Redistributable. See LICENSE.amlogic_vdec for details.
+
+--------------------------------------------------------------------------
+
+Driver: ice - Intel(R) Ethernet Connection E800 Series
+
+File: intel/ice/ddp/ice-1.3.4.0.pkg
+Link: intel/ice/ddp/ice.pkg -> intel/ice/ddp/ice-1.3.4.0.pkg
+
+License: Redistributable. See LICENSE.ice for details
diff --git a/intel/ice/ddp/ice-1.3.4.0.pkg b/intel/ice/ddp/ice-1.3.4.0.pkg
new file mode 100644
index 0000000000000000000000000000000000000000..67443c3ccc5c37efe6ded702beceec60bdf7b792
GIT binary patch
literal 577796
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
apf#X1pf#X1pf#X1pf#X1pf%9D2L2zPeQI0)
literal 0
HcmV?d00001
diff --git a/intel/ice/ddp/ice.pkg b/intel/ice/ddp/ice.pkg
new file mode 120000
index 0000000..ec0ab09
--- /dev/null
+++ b/intel/ice/ddp/ice.pkg
@@ -0,0 +1 @@
+ice-1.3.4.0.pkg
\ No newline at end of file
--
2.21.0
^ permalink raw reply related
* [PATCH v2 net] net: sched: fix possible crash in tcf_action_destroy()
From: Eric Dumazet @ 2019-09-23 22:18 UTC (permalink / raw)
To: David S . Miller
Cc: netdev, Eric Dumazet, Eric Dumazet, syzbot, Cong Wang,
Vlad Buslov, Jiri Pirko
If the allocation done in tcf_exts_init() failed,
we end up with a NULL pointer in exts->actions.
kasan: GPF could be caused by NULL-ptr deref or user memory access
general protection fault: 0000 [#1] PREEMPT SMP KASAN
CPU: 1 PID: 8198 Comm: syz-executor.3 Not tainted 5.3.0-rc8+ #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
RIP: 0010:tcf_action_destroy+0x71/0x160 net/sched/act_api.c:705
Code: c3 08 44 89 ee e8 4f cb bb fb 41 83 fd 20 0f 84 c9 00 00 00 e8 c0 c9 bb fb 48 89 d8 48 b9 00 00 00 00 00 fc ff df 48 c1 e8 03 <80> 3c 08 00 0f 85 c0 00 00 00 4c 8b 33 4d 85 f6 0f 84 9d 00 00 00
RSP: 0018:ffff888096e16ff0 EFLAGS: 00010246
RAX: 0000000000000000 RBX: 0000000000000000 RCX: dffffc0000000000
RDX: 0000000000040000 RSI: ffffffff85b6ab30 RDI: 0000000000000000
RBP: ffff888096e17020 R08: ffff8880993f6140 R09: fffffbfff11cae67
R10: fffffbfff11cae66 R11: ffffffff88e57333 R12: 0000000000000000
R13: 0000000000000000 R14: ffff888096e177a0 R15: 0000000000000001
FS: 00007f62bc84a700(0000) GS:ffff8880ae900000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000758040 CR3: 0000000088b64000 CR4: 00000000001426e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
tcf_exts_destroy+0x38/0xb0 net/sched/cls_api.c:3030
tcindex_set_parms+0xf7f/0x1e50 net/sched/cls_tcindex.c:488
tcindex_change+0x230/0x318 net/sched/cls_tcindex.c:519
tc_new_tfilter+0xa4b/0x1c70 net/sched/cls_api.c:2152
rtnetlink_rcv_msg+0x838/0xb00 net/core/rtnetlink.c:5214
netlink_rcv_skb+0x177/0x450 net/netlink/af_netlink.c:2477
rtnetlink_rcv+0x1d/0x30 net/core/rtnetlink.c:5241
netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline]
netlink_unicast+0x531/0x710 net/netlink/af_netlink.c:1328
netlink_sendmsg+0x8a5/0xd60 net/netlink/af_netlink.c:1917
sock_sendmsg_nosec net/socket.c:637 [inline]
sock_sendmsg+0xd7/0x130 net/socket.c:657
___sys_sendmsg+0x3e2/0x920 net/socket.c:2311
__sys_sendmmsg+0x1bf/0x4d0 net/socket.c:2413
__do_sys_sendmmsg net/socket.c:2442 [inline]
Fixes: 90b73b77d08e ("net: sched: change action API to use array of pointers to actions")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: syzbot <syzkaller@googlegroups.com>
Cc: Cong Wang <xiyou.wangcong@gmail.com>
Cc: Vlad Buslov <vladbu@mellanox.com>
Cc: Jiri Pirko <jiri@mellanox.com>
---
net/sched/act_api.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 2558f00f6b3eda64a87f63c32592c15b7a0a2bfe..b58742e22afb8c40badc64f4d7c4e676839d7d07 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -702,6 +702,9 @@ int tcf_action_destroy(struct tc_action *actions[], int bind)
struct tc_action *a;
int ret = 0, i;
+ if (!actions)
+ return 0;
+
for (i = 0; i < TCA_ACT_MAX_PRIO && actions[i]; i++) {
a = actions[i];
actions[i] = NULL;
--
2.23.0.351.gc4317032e6-goog
^ permalink raw reply related
* Re: linux-next: Tree for Aug 7 (net/bridge/netfilter/nf_conntrack_bridge.c)
From: Ivan Kalvachev @ 2019-09-23 22:26 UTC (permalink / raw)
To: Jeremy Sowden
Cc: Randy Dunlap, Stephen Rothwell, Linux Next Mailing List,
Linux Kernel Mailing List, netdev@vger.kernel.org, bridge
In-Reply-To: <20190807155738.GA9394@azazel.net>
On 8/7/19, Jeremy Sowden <jeremy@azazel.net> wrote:
> On 2019-08-07, at 08:29:44 -0700, Randy Dunlap wrote:
>> On 8/7/19 1:36 AM, Stephen Rothwell wrote:
>> > Hi all,
>> >
>> > Changes since 20190806:
>>
>> on i386:
>> when CONFIG_NF_TABLES is not set/enabled:
>>
>> CC net/bridge/netfilter/nf_conntrack_bridge.o
>> In file included from
>> ../net/bridge/netfilter/nf_conntrack_bridge.c:21:0:
>> ../include/net/netfilter/nf_tables.h: In function
>> ‘nft_gencursor_next’:
>> ../include/net/netfilter/nf_tables.h:1224:14: error: ‘const struct
>> net’ has no member named ‘nft’; did you mean ‘nf’?
>> return net->nft.gencursor + 1 == 1 ? 1 : 0;
>> ^~~
>
> I've just posted a series of fixes for netfilter header compilation
> failures, and I think it includes the fix for that:
>
>
> https://lore.kernel.org/netdev/20190807141705.4864-5-jeremy@azazel.net/T/#u
Have these patches been committed?
I just hit the same bug in linux-5.3.1 release.
^ permalink raw reply
* [PATCH] r8152: Use guard clause and fix comment typos
From: Prashant Malani @ 2019-09-23 22:26 UTC (permalink / raw)
To: hayeswang; +Cc: grundler, netdev, nic_swsd, Prashant Malani
Use a guard clause in tx_bottom() to reduce the indentation of the
do-while loop. In doing so, convert the do-while to a while to make the
guard clause checks consistent.
Also, fix a couple of spelling and grammatical mistakes in the
r8152_csum_workaround() function comment.
Change-Id: I460befde150ad92248fd85b0f189ec2df2ab8431
Signed-off-by: Prashant Malani <pmalani@chromium.org>
Reviewed-by: Grant Grundler <grundler@chromium.org>
---
drivers/net/usb/r8152.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 08726090570e1..82bc69a5b24fb 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -1688,7 +1688,7 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp)
}
/* r8152_csum_workaround()
- * The hw limites the value the transport offset. When the offset is out of the
+ * The hw limits the value of the transport offset. When the offset is out of
* range, calculate the checksum by sw.
*/
static void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb,
@@ -2177,8 +2177,9 @@ static void tx_bottom(struct r8152 *tp)
{
int res;
- do {
+ while (1) {
struct tx_agg *agg;
+ struct net_device *netdev = tp->netdev;
if (skb_queue_empty(&tp->tx_queue))
break;
@@ -2188,26 +2189,25 @@ static void tx_bottom(struct r8152 *tp)
break;
res = r8152_tx_agg_fill(tp, agg);
- if (res) {
- struct net_device *netdev = tp->netdev;
+ if (!res)
+ break;
- if (res == -ENODEV) {
- rtl_set_unplug(tp);
- netif_device_detach(netdev);
- } else {
- struct net_device_stats *stats = &netdev->stats;
- unsigned long flags;
+ if (res == -ENODEV) {
+ rtl_set_unplug(tp);
+ netif_device_detach(netdev);
+ } else {
+ struct net_device_stats *stats = &netdev->stats;
+ unsigned long flags;
- netif_warn(tp, tx_err, netdev,
- "failed tx_urb %d\n", res);
- stats->tx_dropped += agg->skb_num;
+ netif_warn(tp, tx_err, netdev,
+ "failed tx_urb %d\n", res);
+ stats->tx_dropped += agg->skb_num;
- spin_lock_irqsave(&tp->tx_lock, flags);
- list_add_tail(&agg->list, &tp->tx_free);
- spin_unlock_irqrestore(&tp->tx_lock, flags);
- }
+ spin_lock_irqsave(&tp->tx_lock, flags);
+ list_add_tail(&agg->list, &tp->tx_free);
+ spin_unlock_irqrestore(&tp->tx_lock, flags);
}
- } while (res == 0);
+ }
}
static void bottom_half(unsigned long data)
--
2.23.0.351.gc4317032e6-goog
^ permalink raw reply related
* RE: [PATCH 4/6] virtio: introduce a mdev based transport
From: Parav Pandit @ 2019-09-23 22:28 UTC (permalink / raw)
To: Jason Wang, kvm@vger.kernel.org, linux-s390@vger.kernel.org,
linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
intel-gfx@lists.freedesktop.org,
intel-gvt-dev@lists.freedesktop.org, kwankhede@nvidia.com,
alex.williamson@redhat.com, mst@redhat.com, tiwei.bie@intel.com
Cc: virtualization@lists.linux-foundation.org, netdev@vger.kernel.org,
cohuck@redhat.com, maxime.coquelin@redhat.com,
cunming.liang@intel.com, zhihong.wang@intel.com,
rob.miller@broadcom.com, xiao.w.wang@intel.com,
haotian.wang@sifive.com, zhenyuw@linux.intel.com,
zhi.a.wang@intel.com, jani.nikula@linux.intel.com,
joonas.lahtinen@linux.intel.com, rodrigo.vivi@intel.com,
airlied@linux.ie, daniel@ffwll.ch, farman@linux.ibm.com,
pasic@linux.ibm.com, sebott@linux.ibm.com, oberpar@linux.ibm.com,
heiko.carstens@de.ibm.com, gor@linux.ibm.com,
borntraeger@de.ibm.com, akrowiak@linux.ibm.com,
freude@linux.ibm.com, lingshan.zhu@intel.com, Ido Shamay,
eperezma@redhat.com, lulu@redhat.com
In-Reply-To: <20190923130331.29324-5-jasowang@redhat.com>
> -----Original Message-----
> From: Jason Wang <jasowang@redhat.com>
> Sent: Monday, September 23, 2019 8:03 AM
> To: kvm@vger.kernel.org; linux-s390@vger.kernel.org; linux-
> kernel@vger.kernel.org; dri-devel@lists.freedesktop.org; intel-
> gfx@lists.freedesktop.org; intel-gvt-dev@lists.freedesktop.org;
> kwankhede@nvidia.com; alex.williamson@redhat.com; mst@redhat.com;
> tiwei.bie@intel.com
> Cc: virtualization@lists.linux-foundation.org; netdev@vger.kernel.org;
> cohuck@redhat.com; maxime.coquelin@redhat.com;
> cunming.liang@intel.com; zhihong.wang@intel.com;
> rob.miller@broadcom.com; xiao.w.wang@intel.com;
> haotian.wang@sifive.com; zhenyuw@linux.intel.com; zhi.a.wang@intel.com;
> jani.nikula@linux.intel.com; joonas.lahtinen@linux.intel.com;
> rodrigo.vivi@intel.com; airlied@linux.ie; daniel@ffwll.ch;
> farman@linux.ibm.com; pasic@linux.ibm.com; sebott@linux.ibm.com;
> oberpar@linux.ibm.com; heiko.carstens@de.ibm.com; gor@linux.ibm.com;
> borntraeger@de.ibm.com; akrowiak@linux.ibm.com; freude@linux.ibm.com;
> lingshan.zhu@intel.com; Ido Shamay <idos@mellanox.com>;
> eperezma@redhat.com; lulu@redhat.com; Parav Pandit
> <parav@mellanox.com>; Jason Wang <jasowang@redhat.com>
> Subject: [PATCH 4/6] virtio: introduce a mdev based transport
>
> This patch introduces a new mdev transport for virtio. This is used to use kernel
> virtio driver to drive the mediated device that is capable of populating
> virtqueue directly.
>
> A new virtio-mdev driver will be registered to the mdev bus, when a new virtio-
> mdev device is probed, it will register the device with mdev based config ops.
> This means it is a software transport between mdev driver and mdev device.
> The transport was implemented through device specific opswhich is a part of
> mdev_parent_ops now.
>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> MAINTAINERS | 1 +
> drivers/vfio/mdev/Kconfig | 7 +
> drivers/vfio/mdev/Makefile | 1 +
> drivers/vfio/mdev/virtio_mdev.c | 416 ++++++++++++++++++++++++++++++++
> 4 files changed, 425 insertions(+)
> create mode 100644 drivers/vfio/mdev/virtio_mdev.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 89832b316500..820ec250cc52 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -17202,6 +17202,7 @@ F: include/linux/virtio*.h
> F: include/uapi/linux/virtio_*.h
> F: drivers/crypto/virtio/
> F: mm/balloon_compaction.c
> +F: drivers/vfio/mdev/virtio_mdev.c
>
> VIRTIO BLOCK AND SCSI DRIVERS
> M: "Michael S. Tsirkin" <mst@redhat.com>
> diff --git a/drivers/vfio/mdev/Kconfig b/drivers/vfio/mdev/Kconfig index
> 5da27f2100f9..c488c31fc137 100644
> --- a/drivers/vfio/mdev/Kconfig
> +++ b/drivers/vfio/mdev/Kconfig
> @@ -16,3 +16,10 @@ config VFIO_MDEV_DEVICE
> default n
> help
> VFIO based driver for Mediated devices.
> +
> +config VIRTIO_MDEV_DEVICE
> + tristate "VIRTIO driver for Mediated devices"
> + depends on VFIO_MDEV && VIRTIO
> + default n
> + help
> + VIRTIO based driver for Mediated devices.
> diff --git a/drivers/vfio/mdev/Makefile b/drivers/vfio/mdev/Makefile index
> 101516fdf375..99d31e29c23e 100644
> --- a/drivers/vfio/mdev/Makefile
> +++ b/drivers/vfio/mdev/Makefile
> @@ -4,3 +4,4 @@ mdev-y := mdev_core.o mdev_sysfs.o mdev_driver.o
>
> obj-$(CONFIG_VFIO_MDEV) += mdev.o
> obj-$(CONFIG_VFIO_MDEV_DEVICE) += vfio_mdev.o
> +obj-$(CONFIG_VIRTIO_MDEV_DEVICE) += virtio_mdev.o
> diff --git a/drivers/vfio/mdev/virtio_mdev.c b/drivers/vfio/mdev/virtio_mdev.c
> new file mode 100644 index 000000000000..919a082adc9c
> --- /dev/null
> +++ b/drivers/vfio/mdev/virtio_mdev.c
> @@ -0,0 +1,416 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * VIRTIO based driver for Mediated device
> + *
> + * Copyright (c) 2019, Red Hat. All rights reserved.
> + * Author: Jason Wang <jasowang@redhat.com>
> + *
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/uuid.h>
> +#include <linux/mdev.h>
> +#include <linux/virtio_mdev.h>
> +#include <linux/virtio.h>
> +#include <linux/virtio_config.h>
> +#include <linux/virtio_ring.h>
> +#include "mdev_private.h"
> +
> +#define DRIVER_VERSION "0.1"
> +#define DRIVER_AUTHOR "Red Hat Corporation"
> +#define DRIVER_DESC "VIRTIO based driver for Mediated device"
> +
> +#define to_virtio_mdev_device(dev) \
> + container_of(dev, struct virtio_mdev_device, vdev)
> +
> +struct virtio_mdev_device {
> + struct virtio_device vdev;
> + struct mdev_device *mdev;
> + unsigned long version;
> +
> + struct virtqueue **vqs;
Every lock must need a comment to describe what it locks.
I don't see this lock is used in this patch. Please introduce in the patch that uses it.
> + spinlock_t lock;
> +};
> +
> +struct virtio_mdev_vq_info {
> + /* the actual virtqueue */
> + struct virtqueue *vq;
> +
> + /* the list node for the virtqueues list */
> + struct list_head node;
> +};
> +
> +static struct mdev_device *vm_get_mdev(struct virtio_device *vdev) {
> + struct virtio_mdev_device *vm_dev = to_virtio_mdev_device(vdev);
> + struct mdev_device *mdev = vm_dev->mdev;
> +
> + return mdev;
> +}
> +
> +static const struct virtio_mdev_parent_ops *mdev_get_parent_ops(struct
> +mdev_device *mdev) {
> + struct mdev_parent *parent = mdev->parent;
> +
> + return parent->ops->device_ops;
> +}
> +
> +static void virtio_mdev_get(struct virtio_device *vdev, unsigned offset,
> + void *buf, unsigned len)
> +{
> + struct mdev_device *mdev = vm_get_mdev(vdev);
> + const struct virtio_mdev_parent_ops *ops =
> mdev_get_parent_ops(mdev);
> +
> + ops->get_config(mdev, offset, buf, len); }
> +
> +static void virtio_mdev_set(struct virtio_device *vdev, unsigned offset,
> + const void *buf, unsigned len)
> +{
> + struct mdev_device *mdev = vm_get_mdev(vdev);
> + const struct virtio_mdev_parent_ops *ops =
> mdev_get_parent_ops(mdev);
> +
> + ops->set_config(mdev, offset, buf, len); }
> +
> +static u32 virtio_mdev_generation(struct virtio_device *vdev) {
> + struct mdev_device *mdev = vm_get_mdev(vdev);
> + const struct virtio_mdev_parent_ops *ops =
> mdev_get_parent_ops(mdev);
> +
> + return ops->get_generation(mdev);
> +}
> +
> +static u8 virtio_mdev_get_status(struct virtio_device *vdev) {
> + struct mdev_device *mdev = vm_get_mdev(vdev);
> + const struct virtio_mdev_parent_ops *ops =
> mdev_get_parent_ops(mdev);
> +
> + return ops->get_status(mdev);
> +}
> +
> +static void virtio_mdev_set_status(struct virtio_device *vdev, u8
> +status) {
> + struct mdev_device *mdev = vm_get_mdev(vdev);
> + const struct virtio_mdev_parent_ops *ops =
> mdev_get_parent_ops(mdev);
> +
> + return ops->set_status(mdev, status);
> +}
> +
> +static void virtio_mdev_reset(struct virtio_device *vdev) {
> + struct mdev_device *mdev = vm_get_mdev(vdev);
> + const struct virtio_mdev_parent_ops *ops =
> mdev_get_parent_ops(mdev);
> +
> + return ops->set_status(mdev, 0);
> +}
> +
> +static bool virtio_mdev_notify(struct virtqueue *vq) {
> + struct mdev_device *mdev = vm_get_mdev(vq->vdev);
> + const struct virtio_mdev_parent_ops *ops =
> mdev_get_parent_ops(mdev);
> +
> + ops->kick_vq(mdev, vq->index);
> +
> + return true;
> +}
> +
> +static irqreturn_t virtio_mdev_config_cb(void *private) {
> + struct virtio_mdev_device *vm_dev = private;
> +
> + virtio_config_changed(&vm_dev->vdev);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t virtio_mdev_virtqueue_cb(void *private) {
> + struct virtio_mdev_vq_info *info = private;
> +
> + return vring_interrupt(0, info->vq);
> +}
> +
> +static struct virtqueue *
> +virtio_mdev_setup_vq(struct virtio_device *vdev, unsigned index,
> + void (*callback)(struct virtqueue *vq),
> + const char *name, bool ctx)
> +{
> + struct mdev_device *mdev = vm_get_mdev(vdev);
> + const struct virtio_mdev_parent_ops *ops =
> mdev_get_parent_ops(mdev);
> + struct virtio_mdev_vq_info *info;
> + struct virtio_mdev_callback cb;
> + struct virtqueue *vq;
> + u32 align, num;
> + u64 desc_addr, driver_addr, device_addr;
> + int err;
> +
> + if (!name)
> + return NULL;
> +
> + /* Queue shouldn't already be set up. */
> + if (ops->get_vq_ready(mdev, index)) {
> + err = -ENOENT;
> + goto error_available;
> + }
> +
No need for a goto, to single return done later.
Just do
if (ops->get_vq_ready(mdev, index))
return -ENOENT;
> + /* Allocate and fill out our active queue description */
> + info = kmalloc(sizeof(*info), GFP_KERNEL);
> + if (!info) {
> + err = -ENOMEM;
> + goto error_kmalloc;
> + }
> +
Similar to above one.
> + num = ops->get_queue_max(mdev);
> + if (num == 0) {
> + err = -ENOENT;
> + goto error_new_virtqueue;
> + }
> +
> + /* Create the vring */
> + align = ops->get_vq_align(mdev);
> + vq = vring_create_virtqueue(index, num, align, vdev,
> + true, true, ctx,
> + virtio_mdev_notify, callback, name);
> + if (!vq) {
> + err = -ENOMEM;
> + goto error_new_virtqueue;
> + }
> +
> + /* Setup virtqueue callback */
> + cb.callback = virtio_mdev_virtqueue_cb;
> + cb.private = info;
> + ops->set_vq_cb(mdev, index, &cb);
> + ops->set_vq_num(mdev, index, virtqueue_get_vring_size(vq));
> +
> + desc_addr = virtqueue_get_desc_addr(vq);
> + driver_addr = virtqueue_get_avail_addr(vq);
> + device_addr = virtqueue_get_used_addr(vq);
> +
> + if (ops->set_vq_address(mdev, index,
> + desc_addr, driver_addr,
> + device_addr)) {
> + err = -EINVAL;
> + goto err_vq;
> + }
> +
> + ops->set_vq_ready(mdev, index, 1);
> +
> + vq->priv = info;
> + info->vq = vq;
> +
> + return vq;
> +
> +err_vq:
> + vring_del_virtqueue(vq);
> +error_new_virtqueue:
> + ops->set_vq_ready(mdev, index, 0);
> + WARN_ON(ops->get_vq_ready(mdev, index));
> + kfree(info);
> +error_kmalloc:
> +error_available:
> + return ERR_PTR(err);
> +
> +}
> +
> +static void virtio_mdev_del_vq(struct virtqueue *vq) {
> + struct mdev_device *mdev = vm_get_mdev(vq->vdev);
> + const struct virtio_mdev_parent_ops *ops =
> mdev_get_parent_ops(mdev);
> + struct virtio_mdev_vq_info *info = vq->priv;
> + unsigned int index = vq->index;
> +
> + /* Select and deactivate the queue */
> + ops->set_vq_ready(mdev, index, 0);
> + WARN_ON(ops->get_vq_ready(mdev, index));
> +
> + vring_del_virtqueue(vq);
> +
> + kfree(info);
> +}
> +
> +static void virtio_mdev_del_vqs(struct virtio_device *vdev) {
> + struct virtqueue *vq, *n;
> +
> + list_for_each_entry_safe(vq, n, &vdev->vqs, list)
> + virtio_mdev_del_vq(vq);
> +}
> +
> +static int virtio_mdev_find_vqs(struct virtio_device *vdev, unsigned nvqs,
> + struct virtqueue *vqs[],
> + vq_callback_t *callbacks[],
> + const char * const names[],
> + const bool *ctx,
> + struct irq_affinity *desc)
> +{
> + struct virtio_mdev_device *vm_dev = to_virtio_mdev_device(vdev);
> + struct mdev_device *mdev = vm_get_mdev(vdev);
> + const struct virtio_mdev_parent_ops *ops =
> mdev_get_parent_ops(mdev);
> + struct virtio_mdev_callback cb;
> + int i, err, queue_idx = 0;
> +
> + vm_dev->vqs = kmalloc_array(queue_idx, sizeof(*vm_dev->vqs),
> + GFP_KERNEL);
> + if (!vm_dev->vqs)
> + return -ENOMEM;
> +
> + for (i = 0; i < nvqs; ++i) {
> + if (!names[i]) {
> + vqs[i] = NULL;
> + continue;
> + }
> +
> + vqs[i] = virtio_mdev_setup_vq(vdev, queue_idx++,
> + callbacks[i], names[i], ctx ?
> + ctx[i] : false);
> + if (IS_ERR(vqs[i])) {
> + err = PTR_ERR(vqs[i]);
> + goto err_setup_vq;
> + }
> + }
> +
> + cb.callback = virtio_mdev_config_cb;
> + cb.private = vm_dev;
> + ops->set_config_cb(mdev, &cb);
> +
> + return 0;
> +
> +err_setup_vq:
> + kfree(vm_dev->vqs);
> + virtio_mdev_del_vqs(vdev);
> + return err;
> +}
> +
> +static u64 virtio_mdev_get_features(struct virtio_device *vdev) {
> + struct mdev_device *mdev = vm_get_mdev(vdev);
> + const struct virtio_mdev_parent_ops *ops =
> mdev_get_parent_ops(mdev);
> +
> + return ops->get_features(mdev);
> +}
> +
> +static int virtio_mdev_finalize_features(struct virtio_device *vdev) {
> + struct mdev_device *mdev = vm_get_mdev(vdev);
> + const struct virtio_mdev_parent_ops *ops =
> mdev_get_parent_ops(mdev);
> +
> + /* Give virtio_ring a chance to accept features. */
> + vring_transport_features(vdev);
> +
> + return ops->set_features(mdev, vdev->features); }
> +
> +static const char *virtio_mdev_bus_name(struct virtio_device *vdev) {
> + struct virtio_mdev_device *vm_dev = to_virtio_mdev_device(vdev);
> + struct mdev_device *mdev = vm_dev->mdev;
> +
> + return dev_name(&mdev->dev);
> +}
> +
> +static const struct virtio_config_ops virtio_mdev_config_ops = {
> + .get = virtio_mdev_get,
> + .set = virtio_mdev_set,
> + .generation = virtio_mdev_generation,
> + .get_status = virtio_mdev_get_status,
> + .set_status = virtio_mdev_set_status,
> + .reset = virtio_mdev_reset,
> + .find_vqs = virtio_mdev_find_vqs,
> + .del_vqs = virtio_mdev_del_vqs,
> + .get_features = virtio_mdev_get_features,
> + .finalize_features = virtio_mdev_finalize_features,
> + .bus_name = virtio_mdev_bus_name,
> +};
> +
> +static void virtio_mdev_release_dev(struct device *_d) {
> + struct virtio_device *vdev =
> + container_of(_d, struct virtio_device, dev);
> + struct virtio_mdev_device *vm_dev =
> + container_of(vdev, struct virtio_mdev_device, vdev);
> +
> + devm_kfree(_d, vm_dev);
> +}
> +
> +static int virtio_mdev_probe(struct device *dev) {
> + struct mdev_device *mdev = to_mdev_device(dev);
> + const struct virtio_mdev_parent_ops *ops =
> mdev_get_parent_ops(mdev);
> + struct virtio_mdev_device *vm_dev;
> + int rc;
> +
> + vm_dev = devm_kzalloc(dev, sizeof(*vm_dev), GFP_KERNEL);
> + if (!vm_dev)
> + return -ENOMEM;
> +
> + vm_dev->vdev.dev.parent = dev;
> + vm_dev->vdev.dev.release = virtio_mdev_release_dev;
> + vm_dev->vdev.config = &virtio_mdev_config_ops;
> + vm_dev->mdev = mdev;
> + vm_dev->vqs = NULL;
> + spin_lock_init(&vm_dev->lock);
> +
> + vm_dev->version = ops->get_version(mdev);
> + if (vm_dev->version != 1) {
> + dev_err(dev, "Version %ld not supported!\n",
> + vm_dev->version);
> + return -ENXIO;
> + }
> +
> + vm_dev->vdev.id.device = ops->get_device_id(mdev);
> + if (vm_dev->vdev.id.device == 0)
> + return -ENODEV;
> +
> + vm_dev->vdev.id.vendor = ops->get_vendor_id(mdev);
> + rc = register_virtio_device(&vm_dev->vdev);
> + if (rc)
> + put_device(dev);
> +
> + dev_set_drvdata(dev, vm_dev);
No need to set drvdata when there is error returned from register_virtio_device().
> +
> + return rc;
> +
Extra line not needed.
> +}
> +
> +static void virtio_mdev_remove(struct device *dev) {
> + struct virtio_mdev_device *vm_dev = dev_get_drvdata(dev);
> +
> + unregister_virtio_device(&vm_dev->vdev);
> +}
> +
> +static struct mdev_class_id id_table[] = {
> + { MDEV_ID_VIRTIO },
> + { 0 },
> +};
> +
> +static struct mdev_driver virtio_mdev_driver = {
> + .name = "virtio_mdev",
> + .probe = virtio_mdev_probe,
> + .remove = virtio_mdev_remove,
No need for tab, just do single white space.
> + .id_table = id_table,
> +};
> +
> +static int __init virtio_mdev_init(void) {
> + return mdev_register_driver(&virtio_mdev_driver, THIS_MODULE); }
> +
> +static void __exit virtio_mdev_exit(void) {
> + mdev_unregister_driver(&virtio_mdev_driver);
> +}
> +
> +module_init(virtio_mdev_init)
> +module_exit(virtio_mdev_exit)
> +
> +MODULE_VERSION(DRIVER_VERSION);
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> --
> 2.19.1
^ permalink raw reply
* Re: linux-next: Tree for Aug 7 (net/bridge/netfilter/nf_conntrack_bridge.c)
From: Jeremy Sowden @ 2019-09-23 22:48 UTC (permalink / raw)
To: Ivan Kalvachev
Cc: Randy Dunlap, Stephen Rothwell, Linux Next Mailing List,
Linux Kernel Mailing List, netdev@vger.kernel.org, bridge
In-Reply-To: <CABA=pqeES0C2+7GpAOYuCOqd5DrbZhjS1Tkrxn4kGxXQJkrAfg@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1376 bytes --]
On 2019-09-24, at 01:26:22 +0300, Ivan Kalvachev wrote:
> On 8/7/19, Jeremy Sowden <jeremy@azazel.net> wrote:
> > On 2019-08-07, at 08:29:44 -0700, Randy Dunlap wrote:
> > > On 8/7/19 1:36 AM, Stephen Rothwell wrote:
> > > > Changes since 20190806:
> > >
> > > on i386:
> > > when CONFIG_NF_TABLES is not set/enabled:
> > >
> > > CC net/bridge/netfilter/nf_conntrack_bridge.o
> > > In file included from
> > > ../net/bridge/netfilter/nf_conntrack_bridge.c:21:0:
> > > ../include/net/netfilter/nf_tables.h: In function
> > > ‘nft_gencursor_next’:
> > > ../include/net/netfilter/nf_tables.h:1224:14: error: ‘const struct
> > > net’ has no member named ‘nft’; did you mean ‘nf’?
> > > return net->nft.gencursor + 1 == 1 ? 1 : 0;
> > > ^~~
> >
> > I've just posted a series of fixes for netfilter header compilation
> > failures, and I think it includes the fix for that:
> >
> >
> > https://lore.kernel.org/netdev/20190807141705.4864-5-jeremy@azazel.net/T/#u
>
> Have these patches been committed?
>
> I just hit the same bug in linux-5.3.1 release.
The series is now in the mainline (and will form part of 5.4-rc1). Greg
has queued the patch that fixes this build-failure for 5.3-stable:
https://lore.kernel.org/netfilter-devel/20190921112145.GA2408749@kroah.com/T/
so it should be in 5.3.2.
J.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: general protection fault in xsk_map_update_elem
From: Daniel Borkmann @ 2019-09-23 22:50 UTC (permalink / raw)
To: syzbot
Cc: ast, bjorn.topel, bpf, davem, hawk, jakub.kicinski,
john.fastabend, jonathan.lemon, kafai, linux-kernel,
magnus.karlsson, netdev, songliubraving, syzkaller-bugs, yhs
In-Reply-To: <0000000000006a3a2f05933a5c53@google.com>
On Mon, Sep 23, 2019 at 08:49:11AM -0700, syzbot wrote:
> Hello,
>
> syzbot found the following crash on:
>
> HEAD commit: b41dae06 Merge tag 'xfs-5.4-merge-7' of git://git.kernel.o..
> git tree: net-next
> console output: https://syzkaller.appspot.com/x/log.txt?x=130b25ad600000
> kernel config: https://syzkaller.appspot.com/x/.config?x=dfcf592db22b9132
> dashboard link: https://syzkaller.appspot.com/bug?extid=491c1b7565ba9069ecae
> compiler: gcc (GCC) 9.0.0 20181231 (experimental)
> syz repro: https://syzkaller.appspot.com/x/repro.syz?x=155a0c29600000
> C reproducer: https://syzkaller.appspot.com/x/repro.c?x=172bf6d9600000
>
> The bug was bisected to:
>
> commit 0402acd683c678874df6bdbc23530ca07ea19353
> Author: Björn Töpel <bjorn.topel@intel.com>
> Date: Thu Aug 15 09:30:13 2019 +0000
>
> xsk: remove AF_XDP socket from map when the socket is released
Bjorn, PTAL, thanks.
^ permalink raw reply
* RE: [PATCH 2/6] mdev: introduce device specific ops
From: Parav Pandit @ 2019-09-23 22:59 UTC (permalink / raw)
To: Jason Wang, kvm@vger.kernel.org, linux-s390@vger.kernel.org,
linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
intel-gfx@lists.freedesktop.org,
intel-gvt-dev@lists.freedesktop.org, kwankhede@nvidia.com,
alex.williamson@redhat.com, mst@redhat.com, tiwei.bie@intel.com
Cc: virtualization@lists.linux-foundation.org, netdev@vger.kernel.org,
cohuck@redhat.com, maxime.coquelin@redhat.com,
cunming.liang@intel.com, zhihong.wang@intel.com,
rob.miller@broadcom.com, xiao.w.wang@intel.com,
haotian.wang@sifive.com, zhenyuw@linux.intel.com,
zhi.a.wang@intel.com, jani.nikula@linux.intel.com,
joonas.lahtinen@linux.intel.com, rodrigo.vivi@intel.com,
airlied@linux.ie, daniel@ffwll.ch, farman@linux.ibm.com,
pasic@linux.ibm.com, sebott@linux.ibm.com, oberpar@linux.ibm.com,
heiko.carstens@de.ibm.com, gor@linux.ibm.com,
borntraeger@de.ibm.com, akrowiak@linux.ibm.com,
freude@linux.ibm.com, lingshan.zhu@intel.com, Ido Shamay,
eperezma@redhat.com, lulu@redhat.com
In-Reply-To: <20190923130331.29324-3-jasowang@redhat.com>
> -----Original Message-----
> From: Jason Wang <jasowang@redhat.com>
> Sent: Monday, September 23, 2019 8:03 AM
> To: kvm@vger.kernel.org; linux-s390@vger.kernel.org; linux-
> kernel@vger.kernel.org; dri-devel@lists.freedesktop.org; intel-
> gfx@lists.freedesktop.org; intel-gvt-dev@lists.freedesktop.org;
> kwankhede@nvidia.com; alex.williamson@redhat.com; mst@redhat.com;
> tiwei.bie@intel.com
> Cc: virtualization@lists.linux-foundation.org; netdev@vger.kernel.org;
> cohuck@redhat.com; maxime.coquelin@redhat.com;
> cunming.liang@intel.com; zhihong.wang@intel.com;
> rob.miller@broadcom.com; xiao.w.wang@intel.com;
> haotian.wang@sifive.com; zhenyuw@linux.intel.com; zhi.a.wang@intel.com;
> jani.nikula@linux.intel.com; joonas.lahtinen@linux.intel.com;
> rodrigo.vivi@intel.com; airlied@linux.ie; daniel@ffwll.ch;
> farman@linux.ibm.com; pasic@linux.ibm.com; sebott@linux.ibm.com;
> oberpar@linux.ibm.com; heiko.carstens@de.ibm.com; gor@linux.ibm.com;
> borntraeger@de.ibm.com; akrowiak@linux.ibm.com; freude@linux.ibm.com;
> lingshan.zhu@intel.com; Ido Shamay <idos@mellanox.com>;
> eperezma@redhat.com; lulu@redhat.com; Parav Pandit
> <parav@mellanox.com>; Jason Wang <jasowang@redhat.com>
> Subject: [PATCH 2/6] mdev: introduce device specific ops
>
> Currently, except for the create and remove. The rest of mdev_parent_ops is
> designed for vfio-mdev driver only and may not help for kernel mdev driver.
> Follow the class id support by previous patch, this patch introduces device
> specific ops pointer inside parent ops which points to device specific ops (e.g
> vfio ops). This allows the future drivers like virtio-mdev to implement its own
> device specific ops.
>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> .../driver-api/vfio-mediated-device.rst | 4 +-
> MAINTAINERS | 1 +
> drivers/gpu/drm/i915/gvt/kvmgt.c | 15 +++---
> drivers/s390/cio/vfio_ccw_ops.c | 15 ++++--
> drivers/s390/crypto/vfio_ap_ops.c | 11 ++--
> drivers/vfio/mdev/vfio_mdev.c | 31 ++++++-----
> include/linux/mdev.h | 36 ++-----------
> include/linux/vfio_mdev.h | 53 +++++++++++++++++++
> samples/vfio-mdev/mbochs.c | 17 +++---
> samples/vfio-mdev/mdpy.c | 17 +++---
> samples/vfio-mdev/mtty.c | 15 ++++--
> 11 files changed, 138 insertions(+), 77 deletions(-) create mode 100644
> include/linux/vfio_mdev.h
>
> diff --git a/Documentation/driver-api/vfio-mediated-device.rst
> b/Documentation/driver-api/vfio-mediated-device.rst
> index 0e052072e1d8..3ab00e48212f 100644
> --- a/Documentation/driver-api/vfio-mediated-device.rst
> +++ b/Documentation/driver-api/vfio-mediated-device.rst
> @@ -152,7 +152,9 @@ callbacks per mdev parent device, per mdev type, or
> any other categorization.
> Vendor drivers are expected to be fully asynchronous in this respect or
> provide their own internal resource protection.)
>
> -The callbacks in the mdev_parent_ops structure are as follows:
> +The device specific callbacks are referred through device_ops pointer
> +in mdev_parent_ops. For vfio-mdev device, its callbacks in device_ops
> +are as follows:
>
> * open: open callback of mediated device
> * close: close callback of mediated device diff --git a/MAINTAINERS
> b/MAINTAINERS index b2326dece28e..89832b316500 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -17075,6 +17075,7 @@ S: Maintained
> F: Documentation/driver-api/vfio-mediated-device.rst
> F: drivers/vfio/mdev/
> F: include/linux/mdev.h
> +F: include/linux/vfio_mdev.h
> F: samples/vfio-mdev/
>
> VFIO PLATFORM DRIVER
> diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c
> b/drivers/gpu/drm/i915/gvt/kvmgt.c
> index 19d51a35f019..8ea86b1e69f1 100644
> --- a/drivers/gpu/drm/i915/gvt/kvmgt.c
> +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
> @@ -42,6 +42,7 @@
> #include <linux/kvm_host.h>
> #include <linux/vfio.h>
> #include <linux/mdev.h>
> +#include <linux/vfio_mdev.h>
> #include <linux/debugfs.h>
>
> #include <linux/nospec.h>
> @@ -1600,20 +1601,22 @@ static const struct attribute_group
> *intel_vgpu_groups[] = {
> NULL,
> };
>
> -static struct mdev_parent_ops intel_vgpu_ops = {
> - .mdev_attr_groups = intel_vgpu_groups,
> - .create = intel_vgpu_create,
> - .remove = intel_vgpu_remove,
> -
> +static struct vfio_mdev_parent_ops intel_vfio_vgpu_ops = {
Naming it with _dev prefix as intel_vfio_vgpu_dev_ops is better to differentiate with parent_ops.
> .open = intel_vgpu_open,
> .release = intel_vgpu_release,
> -
> .read = intel_vgpu_read,
> .write = intel_vgpu_write,
> .mmap = intel_vgpu_mmap,
> .ioctl = intel_vgpu_ioctl,
> };
>
> +static struct mdev_parent_ops intel_vgpu_ops = {
> + .mdev_attr_groups = intel_vgpu_groups,
> + .create = intel_vgpu_create,
> + .remove = intel_vgpu_remove,
> + .device_ops = &intel_vfio_vgpu_ops,
> +};
> +
> static int kvmgt_host_init(struct device *dev, void *gvt, const void *ops) {
> struct attribute **kvm_type_attrs;
> diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
> index 246ff0f80944..02122bbc213e 100644
> --- a/drivers/s390/cio/vfio_ccw_ops.c
> +++ b/drivers/s390/cio/vfio_ccw_ops.c
> @@ -12,6 +12,7 @@
>
> #include <linux/vfio.h>
> #include <linux/mdev.h>
> +#include <linux/vfio_mdev.h>
> #include <linux/nospec.h>
> #include <linux/slab.h>
>
> @@ -574,11 +575,7 @@ static ssize_t vfio_ccw_mdev_ioctl(struct
> mdev_device *mdev,
> }
> }
>
> -static const struct mdev_parent_ops vfio_ccw_mdev_ops = {
> - .owner = THIS_MODULE,
> - .supported_type_groups = mdev_type_groups,
> - .create = vfio_ccw_mdev_create,
> - .remove = vfio_ccw_mdev_remove,
> +static const struct vfio_mdev_parent_ops vfio_mdev_ops = {
> .open = vfio_ccw_mdev_open,
> .release = vfio_ccw_mdev_release,
> .read = vfio_ccw_mdev_read,
> @@ -586,6 +583,14 @@ static const struct mdev_parent_ops
> vfio_ccw_mdev_ops = {
> .ioctl = vfio_ccw_mdev_ioctl,
> };
>
> +static const struct mdev_parent_ops vfio_ccw_mdev_ops = {
> + .owner = THIS_MODULE,
> + .supported_type_groups = mdev_type_groups,
> + .create = vfio_ccw_mdev_create,
> + .remove = vfio_ccw_mdev_remove,
> + .device_ops = &vfio_mdev_ops,
> +};
> +
> int vfio_ccw_mdev_reg(struct subchannel *sch) {
> return mdev_register_vfio_device(&sch->dev, &vfio_ccw_mdev_ops);
> diff --git a/drivers/s390/crypto/vfio_ap_ops.c
> b/drivers/s390/crypto/vfio_ap_ops.c
> index 7487fc39d2c5..4251becc7a6d 100644
> --- a/drivers/s390/crypto/vfio_ap_ops.c
> +++ b/drivers/s390/crypto/vfio_ap_ops.c
> @@ -16,6 +16,7 @@
> #include <linux/bitops.h>
> #include <linux/kvm_host.h>
> #include <linux/module.h>
> +#include <linux/vfio_mdev.h>
> #include <asm/kvm.h>
> #include <asm/zcrypt.h>
>
> @@ -1280,15 +1281,19 @@ static ssize_t vfio_ap_mdev_ioctl(struct
> mdev_device *mdev,
> return ret;
> }
>
> +static const struct vfio_mdev_parent_ops vfio_mdev_ops = {
> + .open = vfio_ap_mdev_open,
> + .release = vfio_ap_mdev_release,
> + .ioctl = vfio_ap_mdev_ioctl,
> +};
> +
> static const struct mdev_parent_ops vfio_ap_matrix_ops = {
> .owner = THIS_MODULE,
> .supported_type_groups = vfio_ap_mdev_type_groups,
> .mdev_attr_groups = vfio_ap_mdev_attr_groups,
> .create = vfio_ap_mdev_create,
> .remove = vfio_ap_mdev_remove,
> - .open = vfio_ap_mdev_open,
> - .release = vfio_ap_mdev_release,
> - .ioctl = vfio_ap_mdev_ioctl,
> + .device_ops = &vfio_mdev_ops,
> };
>
> int vfio_ap_mdev_register(void)
> diff --git a/drivers/vfio/mdev/vfio_mdev.c b/drivers/vfio/mdev/vfio_mdev.c
> index fd2a4d9a3f26..d23c9f58c84f 100644
> --- a/drivers/vfio/mdev/vfio_mdev.c
> +++ b/drivers/vfio/mdev/vfio_mdev.c
> @@ -14,6 +14,7 @@
> #include <linux/slab.h>
> #include <linux/vfio.h>
> #include <linux/mdev.h>
> +#include <linux/vfio_mdev.h>
>
> #include "mdev_private.h"
>
> @@ -25,15 +26,16 @@ static int vfio_mdev_open(void *device_data) {
> struct mdev_device *mdev = device_data;
> struct mdev_parent *parent = mdev->parent;
> + const struct vfio_mdev_parent_ops *ops = parent->ops->device_ops;
> int ret;
>
> - if (unlikely(!parent->ops->open))
> + if (unlikely(!ops->open))
> return -EINVAL;
>
device_ops is optional and can be NULL for mdev devices which are not required to be mapped via vfio.
So please change to,
If (!ops || !ops->open)
return -EINVAL;
and rest of the below places.
> if (!try_module_get(THIS_MODULE))
> return -ENODEV;
>
> - ret = parent->ops->open(mdev);
> + ret = ops->open(mdev);
> if (ret)
> module_put(THIS_MODULE);
>
> @@ -44,9 +46,10 @@ static void vfio_mdev_release(void *device_data) {
> struct mdev_device *mdev = device_data;
> struct mdev_parent *parent = mdev->parent;
> + const struct vfio_mdev_parent_ops *ops = parent->ops->device_ops;
>
> - if (likely(parent->ops->release))
> - parent->ops->release(mdev);
> + if (likely(ops->release))
> + ops->release(mdev);
>
> module_put(THIS_MODULE);
> }
> @@ -56,11 +59,12 @@ static long vfio_mdev_unlocked_ioctl(void
> *device_data, {
> struct mdev_device *mdev = device_data;
> struct mdev_parent *parent = mdev->parent;
> + const struct vfio_mdev_parent_ops *ops = parent->ops->device_ops;
>
> - if (unlikely(!parent->ops->ioctl))
> + if (unlikely(!ops->ioctl))
> return -EINVAL;
>
> - return parent->ops->ioctl(mdev, cmd, arg);
> + return ops->ioctl(mdev, cmd, arg);
> }
>
> static ssize_t vfio_mdev_read(void *device_data, char __user *buf, @@ -68,11
> +72,12 @@ static ssize_t vfio_mdev_read(void *device_data, char __user *buf,
> {
> struct mdev_device *mdev = device_data;
> struct mdev_parent *parent = mdev->parent;
> + const struct vfio_mdev_parent_ops *ops = parent->ops->device_ops;
>
> - if (unlikely(!parent->ops->read))
> + if (unlikely(!ops->read))
> return -EINVAL;
>
> - return parent->ops->read(mdev, buf, count, ppos);
> + return ops->read(mdev, buf, count, ppos);
> }
>
> static ssize_t vfio_mdev_write(void *device_data, const char __user *buf, @@
> -80,22 +85,24 @@ static ssize_t vfio_mdev_write(void *device_data, const char
> __user *buf, {
> struct mdev_device *mdev = device_data;
> struct mdev_parent *parent = mdev->parent;
> + const struct vfio_mdev_parent_ops *ops = parent->ops->device_ops;
>
> - if (unlikely(!parent->ops->write))
> + if (unlikely(!ops->write))
> return -EINVAL;
>
> - return parent->ops->write(mdev, buf, count, ppos);
> + return ops->write(mdev, buf, count, ppos);
> }
>
> static int vfio_mdev_mmap(void *device_data, struct vm_area_struct *vma) {
> struct mdev_device *mdev = device_data;
> struct mdev_parent *parent = mdev->parent;
> + const struct vfio_mdev_parent_ops *ops = parent->ops->device_ops;
>
> - if (unlikely(!parent->ops->mmap))
> + if (unlikely(!ops->mmap))
> return -EINVAL;
>
> - return parent->ops->mmap(mdev, vma);
> + return ops->mmap(mdev, vma);
> }
>
> static const struct vfio_device_ops vfio_mdev_dev_ops = { diff --git
> a/include/linux/mdev.h b/include/linux/mdev.h index
> 3ebae310f599..fa167bcb81e1 100644
> --- a/include/linux/mdev.h
> +++ b/include/linux/mdev.h
> @@ -48,30 +48,8 @@ struct device *mdev_get_iommu_device(struct device
> *dev);
> * @mdev: mdev_device device structure which is being
> * destroyed
> * Returns integer: success (0) or error (< 0)
> - * @open: Open mediated device.
> - * @mdev: mediated device.
> - * Returns integer: success (0) or error (< 0)
> - * @release: release mediated device
> - * @mdev: mediated device.
> - * @read: Read emulation callback
> - * @mdev: mediated device structure
> - * @buf: read buffer
> - * @count: number of bytes to read
> - * @ppos: address.
> - * Retuns number on bytes read on success or error.
> - * @write: Write emulation callback
> - * @mdev: mediated device structure
> - * @buf: write buffer
> - * @count: number of bytes to be written
> - * @ppos: address.
> - * Retuns number on bytes written on success or error.
> - * @ioctl: IOCTL callback
> - * @mdev: mediated device structure
> - * @cmd: ioctl command
> - * @arg: arguments to ioctl
> - * @mmap: mmap callback
> - * @mdev: mediated device structure
> - * @vma: vma structure
> + * @device_ops: Device specific emulation callback.
> + *
> * Parent device that support mediated device should be registered with mdev
> * module with mdev_parent_ops structure.
> **/
> @@ -83,15 +61,7 @@ struct mdev_parent_ops {
>
> int (*create)(struct kobject *kobj, struct mdev_device *mdev);
> int (*remove)(struct mdev_device *mdev);
> - int (*open)(struct mdev_device *mdev);
> - void (*release)(struct mdev_device *mdev);
> - ssize_t (*read)(struct mdev_device *mdev, char __user *buf,
> - size_t count, loff_t *ppos);
> - ssize_t (*write)(struct mdev_device *mdev, const char __user *buf,
> - size_t count, loff_t *ppos);
> - long (*ioctl)(struct mdev_device *mdev, unsigned int cmd,
> - unsigned long arg);
> - int (*mmap)(struct mdev_device *mdev, struct vm_area_struct
> *vma);
> + const void *device_ops;
> };
>
> /* interface for exporting mdev supported type attributes */ diff --git
> a/include/linux/vfio_mdev.h b/include/linux/vfio_mdev.h new file mode
> 100644 index 000000000000..0c1b34f98f5d
> --- /dev/null
> +++ b/include/linux/vfio_mdev.h
> @@ -0,0 +1,53 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * VFIO Mediated device definition
> + */
> +
> +#ifndef VFIO_MDEV_H
> +#define VFIO_MDEV_H
> +
> +#include <linux/types.h>
> +#include <linux/mdev.h>
> +
> +/**
> + * struct vfio_mdev_parent_ops - Structure to be registered for each
> + * parent device to register the device to vfio-mdev module.
> + *
> + * @open: Open mediated device.
> + * @mdev: mediated device.
> + * Returns integer: success (0) or error (< 0)
> + * @release: release mediated device
> + * @mdev: mediated device.
> + * @read: Read emulation callback
> + * @mdev: mediated device structure
> + * @buf: read buffer
> + * @count: number of bytes to read
> + * @ppos: address.
> + * Retuns number on bytes read on success or error.
> + * @write: Write emulation callback
> + * @mdev: mediated device structure
> + * @buf: write buffer
> + * @count: number of bytes to be written
> + * @ppos: address.
> + * Retuns number on bytes written on success or error.
> + * @ioctl: IOCTL callback
> + * @mdev: mediated device structure
> + * @cmd: ioctl command
> + * @arg: arguments to ioctl
> + * @mmap: mmap callback
> + * @mdev: mediated device structure
> + * @vma: vma structure
> + */
> +struct vfio_mdev_parent_ops {
> + int (*open)(struct mdev_device *mdev);
> + void (*release)(struct mdev_device *mdev);
> + ssize_t (*read)(struct mdev_device *mdev, char __user *buf,
> + size_t count, loff_t *ppos);
> + ssize_t (*write)(struct mdev_device *mdev, const char __user *buf,
> + size_t count, loff_t *ppos);
> + long (*ioctl)(struct mdev_device *mdev, unsigned int cmd,
> + unsigned long arg);
> + int (*mmap)(struct mdev_device *mdev, struct vm_area_struct
> *vma);
> +};
> +
> +#endif
> diff --git a/samples/vfio-mdev/mbochs.c b/samples/vfio-mdev/mbochs.c index
> 71a4469be85d..107cc30d0f45 100644
> --- a/samples/vfio-mdev/mbochs.c
> +++ b/samples/vfio-mdev/mbochs.c
> @@ -30,6 +30,7 @@
> #include <linux/iommu.h>
> #include <linux/sysfs.h>
> #include <linux/mdev.h>
> +#include <linux/vfio_mdev.h>
> #include <linux/pci.h>
> #include <linux/dma-buf.h>
> #include <linux/highmem.h>
> @@ -1418,12 +1419,7 @@ static struct attribute_group *mdev_type_groups[]
> = {
> NULL,
> };
>
> -static const struct mdev_parent_ops mdev_fops = {
> - .owner = THIS_MODULE,
> - .mdev_attr_groups = mdev_dev_groups,
> - .supported_type_groups = mdev_type_groups,
> - .create = mbochs_create,
> - .remove = mbochs_remove,
> +static const struct vfio_mdev_parent_ops vfio_mdev_ops = {
> .open = mbochs_open,
> .release = mbochs_close,
> .read = mbochs_read,
> @@ -1432,6 +1428,15 @@ static const struct mdev_parent_ops mdev_fops = {
> .mmap = mbochs_mmap,
> };
>
> +static const struct mdev_parent_ops mdev_fops = {
> + .owner = THIS_MODULE,
> + .mdev_attr_groups = mdev_dev_groups,
> + .supported_type_groups = mdev_type_groups,
> + .create = mbochs_create,
> + .remove = mbochs_remove,
> + .device_ops = &vfio_mdev_ops,
> +};
> +
> static const struct file_operations vd_fops = {
> .owner = THIS_MODULE,
> };
> diff --git a/samples/vfio-mdev/mdpy.c b/samples/vfio-mdev/mdpy.c index
> d3029dd27d91..2cd2018a53f9 100644
> --- a/samples/vfio-mdev/mdpy.c
> +++ b/samples/vfio-mdev/mdpy.c
> @@ -26,6 +26,7 @@
> #include <linux/iommu.h>
> #include <linux/sysfs.h>
> #include <linux/mdev.h>
> +#include <linux/vfio_mdev.h>
> #include <linux/pci.h>
> #include <drm/drm_fourcc.h>
> #include "mdpy-defs.h"
> @@ -725,12 +726,7 @@ static struct attribute_group *mdev_type_groups[] = {
> NULL,
> };
>
> -static const struct mdev_parent_ops mdev_fops = {
> - .owner = THIS_MODULE,
> - .mdev_attr_groups = mdev_dev_groups,
> - .supported_type_groups = mdev_type_groups,
> - .create = mdpy_create,
> - .remove = mdpy_remove,
> +static const struct vfio_mdev_parent_ops vfio_mdev_ops = {
> .open = mdpy_open,
> .release = mdpy_close,
> .read = mdpy_read,
> @@ -739,6 +735,15 @@ static const struct mdev_parent_ops mdev_fops = {
> .mmap = mdpy_mmap,
> };
>
> +static const struct mdev_parent_ops mdev_fops = {
> + .owner = THIS_MODULE,
> + .mdev_attr_groups = mdev_dev_groups,
> + .supported_type_groups = mdev_type_groups,
> + .create = mdpy_create,
> + .remove = mdpy_remove,
> + .device_ops = &vfio_mdev_ops,
> +};
> +
> static const struct file_operations vd_fops = {
> .owner = THIS_MODULE,
> };
> diff --git a/samples/vfio-mdev/mtty.c b/samples/vfio-mdev/mtty.c index
> 744c88a6b22c..e427425b5daf 100644
> --- a/samples/vfio-mdev/mtty.c
> +++ b/samples/vfio-mdev/mtty.c
> @@ -27,6 +27,7 @@
> #include <linux/ctype.h>
> #include <linux/file.h>
> #include <linux/mdev.h>
> +#include <linux/vfio_mdev.h>
> #include <linux/pci.h>
> #include <linux/serial.h>
> #include <uapi/linux/serial_reg.h>
> @@ -1410,6 +1411,14 @@ static struct attribute_group *mdev_type_groups[]
> = {
> NULL,
> };
>
> +static const struct vfio_mdev_parent_ops vfio_mdev_ops = {
> + .open = mtty_open,
> + .release = mtty_close,
> + .read = mtty_read,
> + .write = mtty_write,
> + .ioctl = mtty_ioctl,
> +};
> +
> static const struct mdev_parent_ops mdev_fops = {
> .owner = THIS_MODULE,
> .dev_attr_groups = mtty_dev_groups,
> @@ -1417,11 +1426,7 @@ static const struct mdev_parent_ops mdev_fops = {
> .supported_type_groups = mdev_type_groups,
> .create = mtty_create,
> .remove = mtty_remove,
> - .open = mtty_open,
> - .release = mtty_close,
> - .read = mtty_read,
> - .write = mtty_write,
> - .ioctl = mtty_ioctl,
> + .device_ops = &vfio_mdev_ops,
> };
>
> static void mtty_device_release(struct device *dev)
> --
> 2.19.1
^ permalink raw reply
* Re: [RFC PATCH bpf-next v2 1/2] bpf: adding map batch processing support
From: Brian Vazquez @ 2019-09-23 23:20 UTC (permalink / raw)
To: Yonghong Song
Cc: ast, Daniel Borkmann, netdev, bpf, kernel-team, Jakub Kicinski,
Brian Vazquez, Stanislav Fomichev
In-Reply-To: <20190906225434.3635421-2-yhs@fb.com>
Hi Yonghong, thanks for working on this!
I have some concerns about this implementation but overall I think
this might work for our use case too!
On Sun, Sep 8, 2019 at 1:11 AM Yonghong Song <yhs@fb.com> wrote:
>
> Brian Vazquez has proposed BPF_MAP_DUMP command to look up more than one
> map entries per syscall.
> https://lore.kernel.org/bpf/CABCgpaU3xxX6CMMxD+1knApivtc2jLBHysDXw-0E9bQEL0qC3A@mail.gmail.com/T/#t
>
> During discussion, we found more use cases can be supported in a similar
> map operation batching framework. For example, batched map lookup and delete,
> which can be really helpful for bcc.
> https://github.com/iovisor/bcc/blob/master/tools/tcptop.py#L233-L243
> https://github.com/iovisor/bcc/blob/master/tools/slabratetop.py#L129-L138
>
> Also, in bcc, we have API to delete all entries in a map.
> https://github.com/iovisor/bcc/blob/master/src/cc/api/BPFTable.h#L257-L264
>
> For map update, batched operations also useful as sometimes applications need
> to populate initial maps with more than one entry. For example, the below
> example is from kernel/samples/bpf/xdp_redirect_cpu_user.c:
> https://github.com/torvalds/linux/blob/master/samples/bpf/xdp_redirect_cpu_user.c#L543-L550
>
> This patch addresses all the above use cases. To make uapi stable, it also
> covers other potential use cases. For bpf syscall subcommands are introduced:
> BPF_MAP_LOOKUP_BATCH
> BPF_MAP_LOOKUP_AND_DELETE_BATCH
> BPF_MAP_UPDATE_BATCH
> BPF_MAP_DELETE_BATCH
>
> The UAPI attribute structure looks like:
>
> struct { /* struct used by BPF_MAP_*_BATCH commands */
> __u64 batch; /* input/output:
> * input: start batch,
> * 0 to start from beginning.
> * output: next start batch,
> * 0 to end batching.
> */
> __aligned_u64 keys;
> __aligned_u64 values;
> __u32 count; /* input/output:
> * input: # of elements keys/values.
> * output: # of filled elements.
> */
> __u32 map_fd;
> __u64 elem_flags;
> __u64 flags;
> } batch;
>
> An opaque value 'batch' is used for user/kernel space communication
> for where in the map to start the operation for lookup/lookup_and_delete/delete.
> input 'batch' = 0: to start the operation from the beginning of the map.
> output 'batch': if not 0, the next input for batch operation.
>
> For lookup/lookup_and_delete:
> operation: lookup/lookup_and_delete starting from a particular 'batch'.
> return:
> 'batch' 'count' return code meaning
> 0 0 0 Done. Nothing left
> 0 0 -ENOSPC no space to handle batch 0
> > 0 0 -ENOSPC no space to handle 'batch'
> > 0 > 0 0 stopped right before 'batch'
> Note that:
> (1). Even if return code is 0 and return 'count' > 0, the return 'count' may
> not be equal to input 'count'. This happens when there is no enough space
> to handle a batch.
> (2). If the return code is an error and not -EFAULT,
> 'batch' indicates the batch has issues and 'count' indicates the number
> of elements successfully processed.
>
> For delete:
> operation: deletion starting from a particular 'batch'.
> return: 0 means everything is deleted from 'batch'.
> error code means something deletion not happening.
>
> For update:
> operation: update 'count' number of elements in 'keys'/'values'.
> return: 0 means successful updates for all elements.
> error code, if not -EFAULT, 'count' is the number of successful updates.
>
> Signed-off-by: Yonghong Song <yhs@fb.com>
> ---
> include/linux/bpf.h | 9 ++
> include/uapi/linux/bpf.h | 22 +++
> kernel/bpf/hashtab.c | 324 +++++++++++++++++++++++++++++++++++++++
> kernel/bpf/syscall.c | 68 ++++++++
> 4 files changed, 423 insertions(+)
>
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 5b9d22338606..3c1302e8e2d4 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -37,6 +37,15 @@ struct bpf_map_ops {
> int (*map_get_next_key)(struct bpf_map *map, void *key, void *next_key);
> void (*map_release_uref)(struct bpf_map *map);
> void *(*map_lookup_elem_sys_only)(struct bpf_map *map, void *key);
> + int (*map_lookup_batch)(struct bpf_map *map, const union bpf_attr *attr,
> + union bpf_attr __user *uattr);
> + int (*map_lookup_and_delete_batch)(struct bpf_map *map,
> + const union bpf_attr *attr,
> + union bpf_attr __user *uattr);
> + int (*map_update_batch)(struct bpf_map *map, const union bpf_attr *attr,
> + union bpf_attr __user *uattr);
> + int (*map_delete_batch)(struct bpf_map *map, const union bpf_attr *attr,
> + union bpf_attr __user *uattr);
>
> /* funcs callable from userspace and from eBPF programs */
> void *(*map_lookup_elem)(struct bpf_map *map, void *key);
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index 5d2fb183ee2d..9d4f76073dd9 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -107,6 +107,10 @@ enum bpf_cmd {
> BPF_MAP_LOOKUP_AND_DELETE_ELEM,
> BPF_MAP_FREEZE,
> BPF_BTF_GET_NEXT_ID,
> + BPF_MAP_LOOKUP_BATCH,
> + BPF_MAP_LOOKUP_AND_DELETE_BATCH,
> + BPF_MAP_UPDATE_BATCH,
> + BPF_MAP_DELETE_BATCH,
> };
>
> enum bpf_map_type {
> @@ -396,6 +400,24 @@ union bpf_attr {
> __u64 flags;
> };
>
> + struct { /* struct used by BPF_MAP_*_BATCH commands */
> + __u64 batch; /* input/output:
> + * input: start batch,
> + * 0 to start from beginning.
> + * output: next start batch,
> + * 0 to end batching.
> + */
> + __aligned_u64 keys;
> + __aligned_u64 values;
> + __u32 count; /* input/output:
> + * input: # of elements keys/values.
> + * output: # of filled elements.
> + */
> + __u32 map_fd;
> + __u64 elem_flags;
> + __u64 flags;
> + } batch;
> +
> struct { /* anonymous struct used by BPF_PROG_LOAD command */
> __u32 prog_type; /* one of enum bpf_prog_type */
> __u32 insn_cnt;
> diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
> index 22066a62c8c9..ee7b90200f4d 100644
> --- a/kernel/bpf/hashtab.c
> +++ b/kernel/bpf/hashtab.c
> @@ -1232,6 +1232,322 @@ static void htab_map_seq_show_elem(struct bpf_map *map, void *key,
> rcu_read_unlock();
> }
>
> +static int
> +__htab_map_lookup_and_delete_batch(struct bpf_map *map,
> + const union bpf_attr *attr,
> + union bpf_attr __user *uattr,
> + bool do_delete, bool is_lru_map)
> +{
> + struct bpf_htab *htab = container_of(map, struct bpf_htab, map);
> + u32 bucket_cnt, total, key_size, value_size, roundup_key_size;
> + void *keys = NULL, *values = NULL, *value, *dst_key, *dst_val;
> + u64 elem_map_flags, map_flags;
> + struct hlist_nulls_head *head;
> + void __user *ukeys, *uvalues;
> + struct hlist_nulls_node *n;
> + u32 batch, max_count;
> + unsigned long flags;
> + struct htab_elem *l;
> + struct bucket *b;
> + int ret = 0;
> +
> + max_count = attr->batch.count;
> + if (!max_count)
> + return 0;
> +
> + elem_map_flags = attr->batch.elem_flags;
> + if ((elem_map_flags & ~BPF_F_LOCK) ||
> + ((elem_map_flags & BPF_F_LOCK) && !map_value_has_spin_lock(map)))
> + return -EINVAL;
> +
> + map_flags = attr->batch.flags;
> + if (map_flags)
> + return -EINVAL;
> +
> + batch = (u32)attr->batch.batch;
> + if (batch >= htab->n_buckets)
> + return -EINVAL;
> +
> + /* We cannot do copy_from_user or copy_to_user inside
> + * the rcu_read_lock. Allocate enough space here.
> + */
> + key_size = htab->map.key_size;
> + roundup_key_size = round_up(htab->map.key_size, 8);
> + value_size = htab->map.value_size;
> + keys = kvmalloc(key_size * max_count, GFP_USER | __GFP_NOWARN);
> + values = kvmalloc(value_size * max_count, GFP_USER | __GFP_NOWARN);
> + if (!keys || !values) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + dst_key = keys;
> + dst_val = values;
> + total = 0;
> +
> + preempt_disable();
> + this_cpu_inc(bpf_prog_active);
> + rcu_read_lock();
> +
> +again:
> + b = &htab->buckets[batch];
> + head = &b->head;
> + raw_spin_lock_irqsave(&b->lock, flags);
> +
Would it be possible to avoid that lock when we're not deleting (just
batching lookup)? To be honest I don't how much impact would have to
grab that lock when concurrent additions are happening in a bpf
program.
> + bucket_cnt = 0;
> + hlist_nulls_for_each_entry_rcu(l, n, head, hash_node)
> + bucket_cnt++;
> +
> + if (bucket_cnt > (max_count - total)) {
> + if (total == 0)
> + ret = -ENOSPC;
> + goto after_loop;
> + }
> +
> + hlist_nulls_for_each_entry_rcu(l, n, head, hash_node) {
> + memcpy(dst_key, l->key, key_size);
> +
> + value = l->key + roundup_key_size;
> + if (elem_map_flags & BPF_F_LOCK)
> + copy_map_value_locked(map, dst_val, value, true);
> + else
> + copy_map_value(map, dst_val, value);
> + check_and_init_map_lock(map, dst_val);
> +
> + dst_key += key_size;
> + dst_val += value_size;
> + total++;
> + }
> +
> + if (do_delete) {
> + hlist_nulls_for_each_entry_rcu(l, n, head, hash_node) {
> + hlist_nulls_del_rcu(&l->hash_node);
> + if (is_lru_map)
> + bpf_lru_push_free(&htab->lru, &l->lru_node);
> + else
> + free_htab_elem(htab, l);
> + }
> + }
> +
> + batch++;
> + if (batch >= htab->n_buckets) {
> + batch = 0;
> + goto after_loop;
> + }
> +
> + raw_spin_unlock_irqrestore(&b->lock, flags);
> + goto again;
> +
> +after_loop:
> + raw_spin_unlock_irqrestore(&b->lock, flags);
> +
> + rcu_read_unlock();
> + this_cpu_dec(bpf_prog_active);
> + preempt_enable();
> +
> + /* copy data back to user */
> + ukeys = u64_to_user_ptr(attr->batch.keys);
> + uvalues = u64_to_user_ptr(attr->batch.values);
> + if (put_user(batch, &uattr->batch.batch) ||
> + copy_to_user(ukeys, keys, total * key_size) ||
> + copy_to_user(uvalues, values, total * value_size) ||
> + put_user(total, &uattr->batch.count))
> + ret = -EFAULT;
> +
> +out:
> + kvfree(keys);
> + kvfree(values);
> + return ret;
> +}
> +
> +static int
> +__htab_map_update_batch(struct bpf_map *map, const union bpf_attr *attr,
> + union bpf_attr __user *uattr, bool is_lru_map)
> +{
> + struct bpf_htab *htab = container_of(map, struct bpf_htab, map);
> + u32 count, max_count, key_size, roundup_key_size, value_size;
> + u64 elem_map_flags, map_flags;
> + void __user *ukey, *uvalue;
> + void *key, *value;
> + int ret = 0;
> +
> + max_count = attr->batch.count;
> + if (!max_count)
> + return 0;
> +
> + elem_map_flags = attr->batch.elem_flags;
> + if ((elem_map_flags & BPF_F_LOCK) && !map_value_has_spin_lock(map))
> + return -EINVAL;
> +
> + map_flags = attr->batch.flags;
> + if (map_flags)
> + return -EINVAL;
> +
> + key_size = htab->map.key_size;
> + roundup_key_size = round_up(htab->map.key_size, 8);
> + value_size = htab->map.value_size;
> + key = kmalloc(key_size, GFP_USER | __GFP_NOWARN);
> + value = kmalloc(value_size, GFP_USER | __GFP_NOWARN);
> + if (!key || !value) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + ukey = u64_to_user_ptr(attr->batch.keys);
> + uvalue = u64_to_user_ptr(attr->batch.values);
> + for (count = 0; count < max_count; count++) {
> + if (copy_from_user(key, ukey + count * key_size, key_size) ||
> + copy_from_user(value, uvalue + count * value_size, value_size)) {
> + ret = -EFAULT;
> + break;
> + }
> +
> + preempt_disable();
> + __this_cpu_inc(bpf_prog_active);
> + rcu_read_lock();
> + if (is_lru_map)
> + ret = htab_lru_map_update_elem(map, key, value, elem_map_flags);
> + else
> + ret = htab_map_update_elem(map, key, value, elem_map_flags);
> + rcu_read_unlock();
> + __this_cpu_dec(bpf_prog_active);
> + preempt_enable();
> +
> + if (ret) {
> + if (put_user(count, &uattr->batch.count))
> + ret = -EFAULT;
> + break;
> + }
> + }
> +
> +out:
> + kfree(key);
> + kfree(value);
> + return ret;
> +}
> +
> +static int
> +__htab_map_delete_batch(struct bpf_map *map,
> + const union bpf_attr *attr,
> + union bpf_attr __user *uattr,
> + bool is_lru_map)
> +{
> + struct bpf_htab *htab = container_of(map, struct bpf_htab, map);
> + u64 elem_map_flags, map_flags;
> + struct hlist_nulls_head *head;
> + struct hlist_nulls_node *n;
> + u32 batch, max_count;
> + unsigned long flags;
> + struct htab_elem *l;
> + struct bucket *b;
> +
> + elem_map_flags = attr->batch.elem_flags;
> + map_flags = attr->batch.flags;
> + if (elem_map_flags || map_flags)
> + return -EINVAL;
> +
> + max_count = attr->batch.count;
> + batch = (u32)attr->batch.batch;
> + if (max_count || batch >= htab->n_buckets)
> + return -EINVAL;
> +
> + preempt_disable();
> + __this_cpu_inc(bpf_prog_active);
> + rcu_read_lock();
> +
> +again:
> + b = &htab->buckets[batch];
> + head = &b->head;
> + raw_spin_lock_irqsave(&b->lock, flags);
> +
> + hlist_nulls_for_each_entry_rcu(l, n, head, hash_node) {
> + hlist_nulls_del_rcu(&l->hash_node);
> + if (is_lru_map)
> + bpf_lru_push_free(&htab->lru, &l->lru_node);
> + else
> + free_htab_elem(htab, l);
> + }
> +
> + batch++;
> + if (batch >= htab->n_buckets)
> + goto out;
> +
> + raw_spin_unlock_irqrestore(&b->lock, flags);
> + goto again;
> +
> +out:
> + raw_spin_unlock_irqrestore(&b->lock, flags);
> + rcu_read_unlock();
> + __this_cpu_dec(bpf_prog_active);
> + preempt_enable();
> +
> + return 0;
> +}
> +
> +static int
> +htab_map_lookup_batch(struct bpf_map *map, const union bpf_attr *attr,
> + union bpf_attr __user *uattr)
> +{
> + return __htab_map_lookup_and_delete_batch(map, attr, uattr, false,
> + false);
> +}
> +
> +static int
> +htab_map_lookup_and_delete_batch(struct bpf_map *map,
> + const union bpf_attr *attr,
> + union bpf_attr __user *uattr)
> +{
> + return __htab_map_lookup_and_delete_batch(map, attr, uattr, true,
> + false);
> +}
> +
> +static int
> +htab_map_update_batch(struct bpf_map *map, const union bpf_attr *attr,
> + union bpf_attr __user *uattr)
> +{
> + return __htab_map_update_batch(map, attr, uattr, false);
> +}
> +
> +static int
> +htab_map_delete_batch(struct bpf_map *map,
> + const union bpf_attr *attr,
> + union bpf_attr __user *uattr)
> +{
> + return __htab_map_delete_batch(map, attr, uattr, false);
> +}
> +
> +static int
> +htab_lru_map_lookup_batch(struct bpf_map *map, const union bpf_attr *attr,
> + union bpf_attr __user *uattr)
> +{
> + return __htab_map_lookup_and_delete_batch(map, attr, uattr, false,
> + true);
> +}
> +
> +static int
> +htab_lru_map_lookup_and_delete_batch(struct bpf_map *map,
> + const union bpf_attr *attr,
> + union bpf_attr __user *uattr)
> +{
> + return __htab_map_lookup_and_delete_batch(map, attr, uattr, true,
> + true);
> +}
> +
> +static int
> +htab_lru_map_update_batch(struct bpf_map *map, const union bpf_attr *attr,
> + union bpf_attr __user *uattr)
> +{
> + return __htab_map_update_batch(map, attr, uattr, true);
> +}
> +
> +static int
> +htab_lru_map_delete_batch(struct bpf_map *map,
> + const union bpf_attr *attr,
> + union bpf_attr __user *uattr)
> +{
> + return __htab_map_delete_batch(map, attr, uattr, true);
> +}
> +
> const struct bpf_map_ops htab_map_ops = {
> .map_alloc_check = htab_map_alloc_check,
> .map_alloc = htab_map_alloc,
> @@ -1242,6 +1558,10 @@ const struct bpf_map_ops htab_map_ops = {
> .map_delete_elem = htab_map_delete_elem,
> .map_gen_lookup = htab_map_gen_lookup,
> .map_seq_show_elem = htab_map_seq_show_elem,
> + .map_lookup_batch = htab_map_lookup_batch,
> + .map_lookup_and_delete_batch = htab_map_lookup_and_delete_batch,
> + .map_update_batch = htab_map_update_batch,
> + .map_delete_batch = htab_map_delete_batch,
> };
>
> const struct bpf_map_ops htab_lru_map_ops = {
> @@ -1255,6 +1575,10 @@ const struct bpf_map_ops htab_lru_map_ops = {
> .map_delete_elem = htab_lru_map_delete_elem,
> .map_gen_lookup = htab_lru_map_gen_lookup,
> .map_seq_show_elem = htab_map_seq_show_elem,
> + .map_lookup_batch = htab_lru_map_lookup_batch,
> + .map_lookup_and_delete_batch = htab_lru_map_lookup_and_delete_batch,
> + .map_update_batch = htab_lru_map_update_batch,
> + .map_delete_batch = htab_lru_map_delete_batch,
> };
>
> /* Called from eBPF program */
> diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
> index ca60eafa6922..e83bdf7efbd8 100644
> --- a/kernel/bpf/syscall.c
> +++ b/kernel/bpf/syscall.c
> @@ -2816,6 +2816,62 @@ static int bpf_task_fd_query(const union bpf_attr *attr,
> return err;
> }
>
> +#define BPF_MAP_BATCH_LAST_FIELD batch.flags
> +
> +#define BPF_DO_BATCH(fn) \
> + do { \
> + if (!fn) { \
> + err = -ENOTSUPP; \
> + goto err_put; \
> + } \
> + err = fn(map, attr, uattr); \
> + } while(0)
> +
> +static int bpf_map_do_batch(const union bpf_attr *attr,
> + union bpf_attr __user *uattr,
> + int cmd)
> +{
> + struct bpf_map *map;
> + int err, ufd;
> + struct fd f;
> +
> + if (CHECK_ATTR(BPF_MAP_BATCH))
> + return -EINVAL;
> +
> + ufd = attr->batch.map_fd;
> + f = fdget(ufd);
> + map = __bpf_map_get(f);
> + if (IS_ERR(map))
> + return PTR_ERR(map);
> +
> + if ((cmd == BPF_MAP_LOOKUP_BATCH ||
> + cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH) &&
> + !(map_get_sys_perms(map, f) & FMODE_CAN_READ)) {
> + err = -EPERM;
> + goto err_put;
> + }
> +
> + if (cmd != BPF_MAP_LOOKUP_BATCH &&
> + !(map_get_sys_perms(map, f) & FMODE_CAN_WRITE)) {
> + err = -EPERM;
> + goto err_put;
> + }
> +
> + if (cmd == BPF_MAP_LOOKUP_BATCH) {
> + BPF_DO_BATCH(map->ops->map_lookup_batch);
> + } else if (cmd == BPF_MAP_LOOKUP_AND_DELETE_BATCH) {
> + BPF_DO_BATCH(map->ops->map_lookup_and_delete_batch);
> + } else if (cmd == BPF_MAP_UPDATE_BATCH) {
> + BPF_DO_BATCH(map->ops->map_update_batch);
> + } else {
> + BPF_DO_BATCH(map->ops->map_delete_batch);
> + }
> +
> +err_put:
> + fdput(f);
> + return err;
> +}
> +
> SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
> {
> union bpf_attr attr = {};
> @@ -2913,6 +2969,18 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
> case BPF_MAP_LOOKUP_AND_DELETE_ELEM:
> err = map_lookup_and_delete_elem(&attr);
> break;
> + case BPF_MAP_LOOKUP_BATCH:
> + err = bpf_map_do_batch(&attr, uattr, BPF_MAP_LOOKUP_BATCH);
> + break;
> + case BPF_MAP_LOOKUP_AND_DELETE_BATCH:
> + err = bpf_map_do_batch(&attr, uattr, BPF_MAP_LOOKUP_AND_DELETE_BATCH);
> + break;
> + case BPF_MAP_UPDATE_BATCH:
> + err = bpf_map_do_batch(&attr, uattr, BPF_MAP_UPDATE_BATCH);
> + break;
> + case BPF_MAP_DELETE_BATCH:
> + err = bpf_map_do_batch(&attr, uattr, BPF_MAP_DELETE_BATCH);
> + break;
> default:
> err = -EINVAL;
> break;
> --
> 2.17.1
>
In general it'd be great if we could express the old functions
(get_next_key, lookup, delete) in terms of this new ones so we avoid
having twice the code.
Also to be honest I don't see how batching updates would be useful,
maybe just try to do batching lookup and lookup_and_delete?
^ permalink raw reply
* [PATCH net v2] net/sched: cbs: Fix not adding cbs instance to list
From: Vinicius Costa Gomes @ 2019-09-24 0:15 UTC (permalink / raw)
To: netdev; +Cc: Vinicius Costa Gomes, jhs, xiyou.wangcong, jiri, davem
When removing a cbs instance when offloading is enabled, the crash
below can be observed.
The problem happens because that when offloading is enabled, the cbs
instance is not added to the list.
Also, the current code doesn't handle correctly the case when offload
is disabled without removing the qdisc: if the link speed changes the
credit calculations will be wrong. When we create the cbs instance
with offloading enabled, it's not added to the notification list, when
later we disable offloading, it's not in the list, so link speed
changes will not affect it.
The solution for both issues is the same, add the cbs instance being
created unconditionally to the global list, even if the link state
notification isn't useful "right now".
Crash log:
[518758.189866] BUG: kernel NULL pointer dereference, address: 0000000000000000
[518758.189870] #PF: supervisor read access in kernel mode
[518758.189871] #PF: error_code(0x0000) - not-present page
[518758.189872] PGD 0 P4D 0
[518758.189874] Oops: 0000 [#1] SMP PTI
[518758.189876] CPU: 3 PID: 4825 Comm: tc Not tainted 5.2.9 #1
[518758.189877] Hardware name: Gigabyte Technology Co., Ltd. Z390 AORUS ULTRA/Z390 AORUS ULTRA-CF, BIOS F7 03/14/2019
[518758.189881] RIP: 0010:__list_del_entry_valid+0x29/0xa0
[518758.189883] Code: 90 48 b8 00 01 00 00 00 00 ad de 55 48 8b 17 4c 8b 47 08 48 89 e5 48 39 c2 74 27 48 b8 00 02 00 00 00 00 ad de 49 39 c0 74 2d <49> 8b 30 48 39 fe 75 3d 48 8b 52 08 48 39 f2 75 4c b8 01 00 00 00
[518758.189885] RSP: 0018:ffffa27e43903990 EFLAGS: 00010207
[518758.189887] RAX: dead000000000200 RBX: ffff8bce69f0f000 RCX: 0000000000000000
[518758.189888] RDX: 0000000000000000 RSI: ffff8bce69f0f064 RDI: ffff8bce69f0f1e0
[518758.189890] RBP: ffffa27e43903990 R08: 0000000000000000 R09: ffff8bce69e788c0
[518758.189891] R10: ffff8bce62acd400 R11: 00000000000003cb R12: ffff8bce69e78000
[518758.189892] R13: ffff8bce69f0f140 R14: 0000000000000000 R15: 0000000000000000
[518758.189894] FS: 00007fa1572c8f80(0000) GS:ffff8bce6e0c0000(0000) knlGS:0000000000000000
[518758.189895] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[518758.189896] CR2: 0000000000000000 CR3: 000000040a398006 CR4: 00000000003606e0
[518758.189898] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[518758.189899] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[518758.189900] Call Trace:
[518758.189904] cbs_destroy+0x32/0xa0 [sch_cbs]
[518758.189906] qdisc_destroy+0x45/0x120
[518758.189907] qdisc_put+0x25/0x30
[518758.189908] qdisc_graft+0x2c1/0x450
[518758.189910] tc_get_qdisc+0x1c8/0x310
[518758.189912] ? get_page_from_freelist+0x91a/0xcb0
[518758.189914] rtnetlink_rcv_msg+0x293/0x360
[518758.189916] ? kmem_cache_alloc_node_trace+0x178/0x260
[518758.189918] ? __kmalloc_node_track_caller+0x38/0x50
[518758.189920] ? rtnl_calcit.isra.0+0xf0/0xf0
[518758.189922] netlink_rcv_skb+0x48/0x110
[518758.189923] rtnetlink_rcv+0x10/0x20
[518758.189925] netlink_unicast+0x15b/0x1d0
[518758.189926] netlink_sendmsg+0x1ea/0x380
[518758.189929] sock_sendmsg+0x2f/0x40
[518758.189930] ___sys_sendmsg+0x295/0x2f0
[518758.189932] ? ___sys_recvmsg+0x151/0x1e0
[518758.189933] ? do_wp_page+0x7e/0x450
[518758.189935] __sys_sendmsg+0x48/0x80
[518758.189937] __x64_sys_sendmsg+0x1a/0x20
[518758.189939] do_syscall_64+0x53/0x1f0
[518758.189941] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[518758.189942] RIP: 0033:0x7fa15755169a
[518758.189944] Code: 48 c7 c0 ff ff ff ff eb be 0f 1f 80 00 00 00 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 18 b8 2e 00 00 00 c5 fc 77 0f 05 <48> 3d 00 f0 ff ff 77 5e c3 0f 1f 44 00 00 48 83 ec 28 89 54 24 1c
[518758.189946] RSP: 002b:00007ffda58b60b8 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
[518758.189948] RAX: ffffffffffffffda RBX: 000055e4b836d9a0 RCX: 00007fa15755169a
[518758.189949] RDX: 0000000000000000 RSI: 00007ffda58b6128 RDI: 0000000000000003
[518758.189951] RBP: 00007ffda58b6190 R08: 0000000000000001 R09: 000055e4b9d848a0
[518758.189952] R10: 0000000000000000 R11: 0000000000000246 R12: 000000005d654b49
[518758.189953] R13: 0000000000000000 R14: 00007ffda58b6230 R15: 00007ffda58b6210
[518758.189955] Modules linked in: sch_cbs sch_etf sch_mqprio netlink_diag unix_diag e1000e igb intel_pch_thermal thermal video backlight pcc_cpufreq
[518758.189960] CR2: 0000000000000000
[518758.189961] ---[ end trace 6a13f7aaf5376019 ]---
[518758.189963] RIP: 0010:__list_del_entry_valid+0x29/0xa0
[518758.189964] Code: 90 48 b8 00 01 00 00 00 00 ad de 55 48 8b 17 4c 8b 47 08 48 89 e5 48 39 c2 74 27 48 b8 00 02 00 00 00 00 ad de 49 39 c0 74 2d <49> 8b 30 48 39 fe 75 3d 48 8b 52 08 48 39 f2 75 4c b8 01 00 00 00
[518758.189967] RSP: 0018:ffffa27e43903990 EFLAGS: 00010207
[518758.189968] RAX: dead000000000200 RBX: ffff8bce69f0f000 RCX: 0000000000000000
[518758.189969] RDX: 0000000000000000 RSI: ffff8bce69f0f064 RDI: ffff8bce69f0f1e0
[518758.189971] RBP: ffffa27e43903990 R08: 0000000000000000 R09: ffff8bce69e788c0
[518758.189972] R10: ffff8bce62acd400 R11: 00000000000003cb R12: ffff8bce69e78000
[518758.189973] R13: ffff8bce69f0f140 R14: 0000000000000000 R15: 0000000000000000
[518758.189975] FS: 00007fa1572c8f80(0000) GS:ffff8bce6e0c0000(0000) knlGS:0000000000000000
[518758.189976] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[518758.189977] CR2: 0000000000000000 CR3: 000000040a398006 CR4: 00000000003606e0
[518758.189979] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[518758.189980] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Fixes: e0a7683 ("net/sched: cbs: fix port_rate miscalculation")
Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
---
Changes from v1:
- Expanded commit message.
net/sched/sch_cbs.c | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c
index 93b58fd..fc15c1b 100644
--- a/net/sched/sch_cbs.c
+++ b/net/sched/sch_cbs.c
@@ -404,6 +404,10 @@ static int cbs_init(struct Qdisc *sch, struct nlattr *opt,
if (!q->qdisc)
return -ENOMEM;
+ spin_lock(&cbs_list_lock);
+ list_add(&q->cbs_list, &cbs_list);
+ spin_unlock(&cbs_list_lock);
+
qdisc_hash_add(q->qdisc, false);
q->queue = sch->dev_queue - netdev_get_tx_queue(dev, 0);
@@ -417,12 +421,6 @@ static int cbs_init(struct Qdisc *sch, struct nlattr *opt,
if (err)
return err;
- if (!q->offload) {
- spin_lock(&cbs_list_lock);
- list_add(&q->cbs_list, &cbs_list);
- spin_unlock(&cbs_list_lock);
- }
-
return 0;
}
@@ -431,15 +429,18 @@ static void cbs_destroy(struct Qdisc *sch)
struct cbs_sched_data *q = qdisc_priv(sch);
struct net_device *dev = qdisc_dev(sch);
- spin_lock(&cbs_list_lock);
- list_del(&q->cbs_list);
- spin_unlock(&cbs_list_lock);
+ /* Nothing to do if we couldn't create the underlying qdisc */
+ if (!q->qdisc)
+ return;
qdisc_watchdog_cancel(&q->watchdog);
cbs_disable_offload(dev, q);
- if (q->qdisc)
- qdisc_put(q->qdisc);
+ spin_lock(&cbs_list_lock);
+ list_del(&q->cbs_list);
+ spin_unlock(&cbs_list_lock);
+
+ qdisc_put(q->qdisc);
}
static int cbs_dump(struct Qdisc *sch, struct sk_buff *skb)
--
2.23.0
^ permalink raw reply related
* Re: [PATCH 1/1] MAINTAINERS: add Yanjun to FORCEDETH maintainers list
From: Zhu Yanjun @ 2019-09-24 0:23 UTC (permalink / raw)
To: rain.1986.08.12, mchehab+samsung, davem, gregkh, robh,
linus.walleij, nicolas.ferre, linux-kernel, netdev
In-Reply-To: <20190923143746.4310-1-rain.1986.08.12@gmail.com>
On 2019/9/23 22:37, rain.1986.08.12@gmail.com wrote:
> From: Rain River <rain.1986.08.12@gmail.com>
>
> Yanjun has been spending quite a lot of time fixing bugs
> in FORCEDETH source code. I'd like to add Yanjun to maintainers
> list.
>
> Signed-off-by: Rain River <rain.1986.08.12@gmail.com>
Acked-by: Zhu Yanjun <yanjun.zhu@oracle.com>
Thanks a lot.
Zhu Yanjun
> ---
> MAINTAINERS | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a400af0501c9..336ad8fe8b60 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -643,6 +643,7 @@ F: drivers/net/ethernet/alacritech/*
>
> FORCEDETH GIGABIT ETHERNET DRIVER
> M: Rain River <rain.1986.08.12@gmail.com>
> +M: Zhu Yanjun <yanjun.zhu@oracle.com>
> L: netdev@vger.kernel.org
> S: Maintained
> F: drivers/net/ethernet/nvidia/*
^ permalink raw reply
* Re: [PATCH V2 net 1/1] net/tls(TLS_SW): Fix list_del double free caused by a race condition in tls_tx_records
From: Jakub Kicinski @ 2019-09-24 0:28 UTC (permalink / raw)
To: Pooja Trivedi
Cc: netdev, davem, daniel, john.fastabend, davejwatson, aviadye,
borisp, Pooja Trivedi, Mallesham Jatharakonda
In-Reply-To: <CAOrEdsk6P=HWfK-mKyLt7=tZh342gZrRKwOH9f6ntkNyya-4fA@mail.gmail.com>
On Sat, 21 Sep 2019 23:19:20 -0400, Pooja Trivedi wrote:
> On Wed, Sep 18, 2019 at 5:45 PM Jakub Kicinski wrote:
> > On Wed, 18 Sep 2019 17:37:44 -0400, Pooja Trivedi wrote:
> > > Hi Jakub,
> > >
> > > I have explained one potential way for the race to happen in my
> > > original message to the netdev mailing list here:
> > > https://marc.info/?l=linux-netdev&m=156805120229554&w=2
> > >
> > > Here is the part out of there that's relevant to your question:
> > >
> > > -----------------------------------------
> > >
> > > One potential way for race condition to appear:
> > >
> > > When under tcp memory pressure, Thread 1 takes the following code path:
> > > do_sendfile ---> ... ---> .... ---> tls_sw_sendpage --->
> > > tls_sw_do_sendpage ---> tls_tx_records ---> tls_push_sg --->
> > > do_tcp_sendpages ---> sk_stream_wait_memory ---> sk_wait_event
> >
> > Ugh, so do_tcp_sendpages() can also release the lock :/
> >
> > Since the problem occurs in tls_sw_do_sendpage() and
> > tls_sw_do_sendmsg() as well, should we perhaps fix it at that level?
>
> That won't do because tls_tx_records also gets called when completion
> callbacks schedule delayed work. That was the code path that caused
> the crash for my test. Cavium's nitrox crypto offload driver calling
> tls_encrypt_done, which calls schedule_delayed_work. Delayed work that
> was scheduled would then be processed by tx_work_handler.
> Notice in my previous reply,
> "Thread 2 code path:
> tx_work_handler ---> tls_tx_records"
>
> "Thread 2 code path:
> tx_work_handler ---> tls_tx_records"
Right, the work handler would obviously also have to obey the exclusion
mechanism of choice.
Having said that this really does feel like we are trying to lock code,
not data here :(
^ permalink raw reply
* RE: [PATCH] rtlwifi: rtl8723ae: Remove unused 'rtstatus' variable
From: Pkshih @ 2019-09-24 1:21 UTC (permalink / raw)
To: Austin Kim, kvalo@codeaurora.org, davem@davemloft.net
Cc: linux-wireless@vger.kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <CADLLry5b1RDjXX8Dbc4ebbZOFFaAd0wc3rDCaD-V9RBwrpNyMA@mail.gmail.com>
> -----Original Message-----
> From: Austin Kim [mailto:austindh.kim@gmail.com]
> Sent: Monday, September 23, 2019 9:35 PM
> To: Pkshih; kvalo@codeaurora.org; davem@davemloft.net
> Cc: linux-wireless@vger.kernel.org; netdev@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH] rtlwifi: rtl8723ae: Remove unused 'rtstatus' variable
>
> Hello, Maintainers...
> Would you please review above patch if you are available?
>
You can check status of your patch here
https://patchwork.kernel.org/project/linux-wireless/list/?series=174859
If your patch is existing in patchwork, maintainer doesn't forget it.
Another thing is to avoid top posting that makes maintainer hard to read mail.
---
PK
^ permalink raw reply
* RE: [PATCH] r8152: Use guard clause and fix comment typos
From: Hayes Wang @ 2019-09-24 2:47 UTC (permalink / raw)
To: Prashant Malani; +Cc: grundler@chromium.org, netdev@vger.kernel.org, nic_swsd
In-Reply-To: <20190923222657.253628-1-pmalani@chromium.org>
Prashant Malani [mailto:pmalani@chromium.org]
> Sent: Tuesday, September 24, 2019 6:27 AM
> To: Hayes Wang
[...]
> - do {
> + while (1) {
> struct tx_agg *agg;
> + struct net_device *netdev = tp->netdev;
>
> if (skb_queue_empty(&tp->tx_queue))
> break;
> @@ -2188,26 +2189,25 @@ static void tx_bottom(struct r8152 *tp)
> break;
>
> res = r8152_tx_agg_fill(tp, agg);
> - if (res) {
> - struct net_device *netdev = tp->netdev;
> + if (!res)
> + break;
I let the loop run continually until an error occurs or the queue is empty.
However, you stop the loop when r8152_tx_agg_fill() is successful.
If an error occurs continually, the loop may not be broken.
> - if (res == -ENODEV) {
> - rtl_set_unplug(tp);
> - netif_device_detach(netdev);
> - } else {
> - struct net_device_stats *stats = &netdev->stats;
> - unsigned long flags;
> + if (res == -ENODEV) {
> + rtl_set_unplug(tp);
> + netif_device_detach(netdev);
> + } else {
> + struct net_device_stats *stats = &netdev->stats;
> + unsigned long flags;
>
> - netif_warn(tp, tx_err, netdev,
> - "failed tx_urb %d\n", res);
> - stats->tx_dropped += agg->skb_num;
> + netif_warn(tp, tx_err, netdev,
> + "failed tx_urb %d\n", res);
> + stats->tx_dropped += agg->skb_num;
>
> - spin_lock_irqsave(&tp->tx_lock, flags);
> - list_add_tail(&agg->list, &tp->tx_free);
> - spin_unlock_irqrestore(&tp->tx_lock, flags);
> - }
> + spin_lock_irqsave(&tp->tx_lock, flags);
> + list_add_tail(&agg->list, &tp->tx_free);
> + spin_unlock_irqrestore(&tp->tx_lock, flags);
> }
> - } while (res == 0);
> + }
I think the behavior is different from the current one.
Best Regards,
Hayes
^ permalink raw reply
* [PATCH v2] r8152: Use guard clause and fix comment typos
From: Prashant Malani @ 2019-09-24 4:00 UTC (permalink / raw)
To: hayeswang; +Cc: grundler, netdev, nic_swsd, Prashant Malani
Use a guard clause in tx_bottom() to reduce the indentation of the
do-while loop.
Also, fix a couple of spelling and grammatical mistakes in the
r8152_csum_workaround() function comment.
Change-Id: I460befde150ad92248fd85b0f189ec2df2ab8431
Signed-off-by: Prashant Malani <pmalani@chromium.org>
Reviewed-by: Grant Grundler <grundler@chromium.org>
---
drivers/net/usb/r8152.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 08726090570e1..2c1faa8cf5fc9 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -1688,7 +1688,7 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp)
}
/* r8152_csum_workaround()
- * The hw limites the value the transport offset. When the offset is out of the
+ * The hw limits the value of the transport offset. When the offset is out of
* range, calculate the checksum by sw.
*/
static void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb,
@@ -2179,6 +2179,7 @@ static void tx_bottom(struct r8152 *tp)
do {
struct tx_agg *agg;
+ struct net_device *netdev = tp->netdev;
if (skb_queue_empty(&tp->tx_queue))
break;
@@ -2188,24 +2189,23 @@ static void tx_bottom(struct r8152 *tp)
break;
res = r8152_tx_agg_fill(tp, agg);
- if (res) {
- struct net_device *netdev = tp->netdev;
+ if (!res)
+ continue;
- if (res == -ENODEV) {
- rtl_set_unplug(tp);
- netif_device_detach(netdev);
- } else {
- struct net_device_stats *stats = &netdev->stats;
- unsigned long flags;
+ if (res == -ENODEV) {
+ rtl_set_unplug(tp);
+ netif_device_detach(netdev);
+ } else {
+ struct net_device_stats *stats = &netdev->stats;
+ unsigned long flags;
- netif_warn(tp, tx_err, netdev,
- "failed tx_urb %d\n", res);
- stats->tx_dropped += agg->skb_num;
+ netif_warn(tp, tx_err, netdev,
+ "failed tx_urb %d\n", res);
+ stats->tx_dropped += agg->skb_num;
- spin_lock_irqsave(&tp->tx_lock, flags);
- list_add_tail(&agg->list, &tp->tx_free);
- spin_unlock_irqrestore(&tp->tx_lock, flags);
- }
+ spin_lock_irqsave(&tp->tx_lock, flags);
+ list_add_tail(&agg->list, &tp->tx_free);
+ spin_unlock_irqrestore(&tp->tx_lock, flags);
}
} while (res == 0);
}
--
2.23.0.351.gc4317032e6-goog
^ 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