commit:     ccb74324f775c901be1e1ddef5b15982a7d649e0
Author:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
AuthorDate: Sat Sep 12 18:14:03 2020 +0000
Commit:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
CommitDate: Sat Sep 12 18:14:03 2020 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=ccb74324

Linux patch 5.8.9

Signed-off-by: Mike Pagano <mpagano <AT> gentoo.org>

 0000_README            |   4 +
 1008_linux-5.8.9.patch | 952 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 956 insertions(+)

diff --git a/0000_README b/0000_README
index 93860e0..96ae239 100644
--- a/0000_README
+++ b/0000_README
@@ -75,6 +75,10 @@ Patch:  1007_linux-5.8.8.patch
 From:   http://www.kernel.org
 Desc:   Linux 5.8.8
 
+Patch:  1008_linux-5.8.9.patch
+From:   http://www.kernel.org
+Desc:   Linux 5.8.9
+
 Patch:  1500_XATTR_USER_PREFIX.patch
 From:   https://bugs.gentoo.org/show_bug.cgi?id=470644
 Desc:   Support for namespace user.pax.* on tmpfs.

diff --git a/1008_linux-5.8.9.patch b/1008_linux-5.8.9.patch
new file mode 100644
index 0000000..55b6aa0
--- /dev/null
+++ b/1008_linux-5.8.9.patch
@@ -0,0 +1,952 @@
+diff --git a/Makefile b/Makefile
+index dba4d8f2f7862..36eab48d1d4a6 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 5
+ PATCHLEVEL = 8
+-SUBLEVEL = 8
++SUBLEVEL = 9
+ EXTRAVERSION =
+ NAME = Kleptomaniac Octopus
+ 
+diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
+index c30cf5307ce3e..26de0dab60bbb 100644
+--- a/drivers/infiniband/core/cma.c
++++ b/drivers/infiniband/core/cma.c
+@@ -428,19 +428,6 @@ static int cma_comp_exch(struct rdma_id_private *id_priv,
+       return ret;
+ }
+ 
+-static enum rdma_cm_state cma_exch(struct rdma_id_private *id_priv,
+-                                 enum rdma_cm_state exch)
+-{
+-      unsigned long flags;
+-      enum rdma_cm_state old;
+-
+-      spin_lock_irqsave(&id_priv->lock, flags);
+-      old = id_priv->state;
+-      id_priv->state = exch;
+-      spin_unlock_irqrestore(&id_priv->lock, flags);
+-      return old;
+-}
+-
+ static inline u8 cma_get_ip_ver(const struct cma_hdr *hdr)
+ {
+       return hdr->ip_version >> 4;
+@@ -1829,23 +1816,11 @@ static void cma_leave_mc_groups(struct rdma_id_private 
*id_priv)
+       }
+ }
+ 
+-void rdma_destroy_id(struct rdma_cm_id *id)
++static void _destroy_id(struct rdma_id_private *id_priv,
++                      enum rdma_cm_state state)
+ {
+-      struct rdma_id_private *id_priv;
+-      enum rdma_cm_state state;
+-
+-      id_priv = container_of(id, struct rdma_id_private, id);
+-      trace_cm_id_destroy(id_priv);
+-      state = cma_exch(id_priv, RDMA_CM_DESTROYING);
+       cma_cancel_operation(id_priv, state);
+ 
+-      /*
+-       * Wait for any active callback to finish.  New callbacks will find
+-       * the id_priv state set to destroying and abort.
+-       */
+-      mutex_lock(&id_priv->handler_mutex);
+-      mutex_unlock(&id_priv->handler_mutex);
+-
+       rdma_restrack_del(&id_priv->res);
+       if (id_priv->cma_dev) {
+               if (rdma_cap_ib_cm(id_priv->id.device, 1)) {
+@@ -1874,6 +1849,42 @@ void rdma_destroy_id(struct rdma_cm_id *id)
+       put_net(id_priv->id.route.addr.dev_addr.net);
+       kfree(id_priv);
+ }
++
++/*
++ * destroy an ID from within the handler_mutex. This ensures that no other
++ * handlers can start running concurrently.
++ */
++static void destroy_id_handler_unlock(struct rdma_id_private *id_priv)
++      __releases(&idprv->handler_mutex)
++{
++      enum rdma_cm_state state;
++      unsigned long flags;
++
++      trace_cm_id_destroy(id_priv);
++
++      /*
++       * Setting the state to destroyed under the handler mutex provides a
++       * fence against calling handler callbacks. If this is invoked due to
++       * the failure of a handler callback then it guarentees that no future
++       * handlers will be called.
++       */
++      lockdep_assert_held(&id_priv->handler_mutex);
++      spin_lock_irqsave(&id_priv->lock, flags);
++      state = id_priv->state;
++      id_priv->state = RDMA_CM_DESTROYING;
++      spin_unlock_irqrestore(&id_priv->lock, flags);
++      mutex_unlock(&id_priv->handler_mutex);
++      _destroy_id(id_priv, state);
++}
++
++void rdma_destroy_id(struct rdma_cm_id *id)
++{
++      struct rdma_id_private *id_priv =
++              container_of(id, struct rdma_id_private, id);
++
++      mutex_lock(&id_priv->handler_mutex);
++      destroy_id_handler_unlock(id_priv);
++}
+ EXPORT_SYMBOL(rdma_destroy_id);
+ 
+ static int cma_rep_recv(struct rdma_id_private *id_priv)
+@@ -1925,6 +1936,8 @@ static int cma_cm_event_handler(struct rdma_id_private 
*id_priv,
+ {
+       int ret;
+ 
++      lockdep_assert_held(&id_priv->handler_mutex);
++
+       trace_cm_event_handler(id_priv, event);
+       ret = id_priv->id.event_handler(&id_priv->id, event);
+       trace_cm_event_done(id_priv, event, ret);
+@@ -1936,7 +1949,7 @@ static int cma_ib_handler(struct ib_cm_id *cm_id,
+ {
+       struct rdma_id_private *id_priv = cm_id->context;
+       struct rdma_cm_event event = {};
+-      int ret = 0;
++      int ret;
+ 
+       mutex_lock(&id_priv->handler_mutex);
+       if ((ib_event->event != IB_CM_TIMEWAIT_EXIT &&
+@@ -2005,14 +2018,12 @@ static int cma_ib_handler(struct ib_cm_id *cm_id,
+       if (ret) {
+               /* Destroy the CM ID by returning a non-zero value. */
+               id_priv->cm_id.ib = NULL;
+-              cma_exch(id_priv, RDMA_CM_DESTROYING);
+-              mutex_unlock(&id_priv->handler_mutex);
+-              rdma_destroy_id(&id_priv->id);
++              destroy_id_handler_unlock(id_priv);
+               return ret;
+       }
+ out:
+       mutex_unlock(&id_priv->handler_mutex);
+-      return ret;
++      return 0;
+ }
+ 
+ static struct rdma_id_private *
+@@ -2174,7 +2185,7 @@ static int cma_ib_req_handler(struct ib_cm_id *cm_id,
+       mutex_lock(&listen_id->handler_mutex);
+       if (listen_id->state != RDMA_CM_LISTEN) {
+               ret = -ECONNABORTED;
+-              goto err1;
++              goto err_unlock;
+       }
+ 
+       offset = cma_user_data_offset(listen_id);
+@@ -2191,55 +2202,38 @@ static int cma_ib_req_handler(struct ib_cm_id *cm_id,
+       }
+       if (!conn_id) {
+               ret = -ENOMEM;
+-              goto err1;
++              goto err_unlock;
+       }
+ 
+       mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
+       ret = cma_ib_acquire_dev(conn_id, listen_id, &req);
+-      if (ret)
+-              goto err2;
++      if (ret) {
++              destroy_id_handler_unlock(conn_id);
++              goto err_unlock;
++      }
+ 
+       conn_id->cm_id.ib = cm_id;
+       cm_id->context = conn_id;
+       cm_id->cm_handler = cma_ib_handler;
+ 
+-      /*
+-       * Protect against the user destroying conn_id from another thread
+-       * until we're done accessing it.
+-       */
+-      cma_id_get(conn_id);
+       ret = cma_cm_event_handler(conn_id, &event);
+-      if (ret)
+-              goto err3;
+-      /*
+-       * Acquire mutex to prevent user executing rdma_destroy_id()
+-       * while we're accessing the cm_id.
+-       */
+-      mutex_lock(&lock);
++      if (ret) {
++              /* Destroy the CM ID by returning a non-zero value. */
++              conn_id->cm_id.ib = NULL;
++              mutex_unlock(&listen_id->handler_mutex);
++              destroy_id_handler_unlock(conn_id);
++              goto net_dev_put;
++      }
++
+       if (cma_comp(conn_id, RDMA_CM_CONNECT) &&
+           (conn_id->id.qp_type != IB_QPT_UD)) {
+               trace_cm_send_mra(cm_id->context);
+               ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
+       }
+-      mutex_unlock(&lock);
+       mutex_unlock(&conn_id->handler_mutex);
+-      mutex_unlock(&listen_id->handler_mutex);
+-      cma_id_put(conn_id);
+-      if (net_dev)
+-              dev_put(net_dev);
+-      return 0;
+ 
+-err3:
+-      cma_id_put(conn_id);
+-      /* Destroy the CM ID by returning a non-zero value. */
+-      conn_id->cm_id.ib = NULL;
+-err2:
+-      cma_exch(conn_id, RDMA_CM_DESTROYING);
+-      mutex_unlock(&conn_id->handler_mutex);
+-err1:
++err_unlock:
+       mutex_unlock(&listen_id->handler_mutex);
+-      if (conn_id)
+-              rdma_destroy_id(&conn_id->id);
+ 
+ net_dev_put:
+       if (net_dev)
+@@ -2339,9 +2333,7 @@ static int cma_iw_handler(struct iw_cm_id *iw_id, struct 
iw_cm_event *iw_event)
+       if (ret) {
+               /* Destroy the CM ID by returning a non-zero value. */
+               id_priv->cm_id.iw = NULL;
+-              cma_exch(id_priv, RDMA_CM_DESTROYING);
+-              mutex_unlock(&id_priv->handler_mutex);
+-              rdma_destroy_id(&id_priv->id);
++              destroy_id_handler_unlock(id_priv);
+               return ret;
+       }
+ 
+@@ -2388,16 +2380,16 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
+ 
+       ret = rdma_translate_ip(laddr, &conn_id->id.route.addr.dev_addr);
+       if (ret) {
+-              mutex_unlock(&conn_id->handler_mutex);
+-              rdma_destroy_id(new_cm_id);
+-              goto out;
++              mutex_unlock(&listen_id->handler_mutex);
++              destroy_id_handler_unlock(conn_id);
++              return ret;
+       }
+ 
+       ret = cma_iw_acquire_dev(conn_id, listen_id);
+       if (ret) {
+-              mutex_unlock(&conn_id->handler_mutex);
+-              rdma_destroy_id(new_cm_id);
+-              goto out;
++              mutex_unlock(&listen_id->handler_mutex);
++              destroy_id_handler_unlock(conn_id);
++              return ret;
+       }
+ 
+       conn_id->cm_id.iw = cm_id;
+@@ -2407,25 +2399,16 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
+       memcpy(cma_src_addr(conn_id), laddr, rdma_addr_size(laddr));
+       memcpy(cma_dst_addr(conn_id), raddr, rdma_addr_size(raddr));
+ 
+-      /*
+-       * Protect against the user destroying conn_id from another thread
+-       * until we're done accessing it.
+-       */
+-      cma_id_get(conn_id);
+       ret = cma_cm_event_handler(conn_id, &event);
+       if (ret) {
+               /* User wants to destroy the CM ID */
+               conn_id->cm_id.iw = NULL;
+-              cma_exch(conn_id, RDMA_CM_DESTROYING);
+-              mutex_unlock(&conn_id->handler_mutex);
+               mutex_unlock(&listen_id->handler_mutex);
+-              cma_id_put(conn_id);
+-              rdma_destroy_id(&conn_id->id);
++              destroy_id_handler_unlock(conn_id);
+               return ret;
+       }
+ 
+       mutex_unlock(&conn_id->handler_mutex);
+-      cma_id_put(conn_id);
+ 
+ out:
+       mutex_unlock(&listen_id->handler_mutex);
+@@ -2482,6 +2465,10 @@ static int cma_listen_handler(struct rdma_cm_id *id,
+ {
+       struct rdma_id_private *id_priv = id->context;
+ 
++      /* Listening IDs are always destroyed on removal */
++      if (event->event == RDMA_CM_EVENT_DEVICE_REMOVAL)
++              return -1;
++
+       id->context = id_priv->id.context;
+       id->event_handler = id_priv->id.event_handler;
+       trace_cm_event_handler(id_priv, event);
+@@ -2657,21 +2644,21 @@ static void cma_work_handler(struct work_struct *_work)
+ {
+       struct cma_work *work = container_of(_work, struct cma_work, work);
+       struct rdma_id_private *id_priv = work->id;
+-      int destroy = 0;
+ 
+       mutex_lock(&id_priv->handler_mutex);
+       if (!cma_comp_exch(id_priv, work->old_state, work->new_state))
+-              goto out;
++              goto out_unlock;
+ 
+       if (cma_cm_event_handler(id_priv, &work->event)) {
+-              cma_exch(id_priv, RDMA_CM_DESTROYING);
+-              destroy = 1;
++              cma_id_put(id_priv);
++              destroy_id_handler_unlock(id_priv);
++              goto out_free;
+       }
+-out:
++
++out_unlock:
+       mutex_unlock(&id_priv->handler_mutex);
+       cma_id_put(id_priv);
+-      if (destroy)
+-              rdma_destroy_id(&id_priv->id);
++out_free:
+       kfree(work);
+ }
+ 
+@@ -2679,23 +2666,22 @@ static void cma_ndev_work_handler(struct work_struct 
*_work)
+ {
+       struct cma_ndev_work *work = container_of(_work, struct cma_ndev_work, 
work);
+       struct rdma_id_private *id_priv = work->id;
+-      int destroy = 0;
+ 
+       mutex_lock(&id_priv->handler_mutex);
+       if (id_priv->state == RDMA_CM_DESTROYING ||
+           id_priv->state == RDMA_CM_DEVICE_REMOVAL)
+-              goto out;
++              goto out_unlock;
+ 
+       if (cma_cm_event_handler(id_priv, &work->event)) {
+-              cma_exch(id_priv, RDMA_CM_DESTROYING);
+-              destroy = 1;
++              cma_id_put(id_priv);
++              destroy_id_handler_unlock(id_priv);
++              goto out_free;
+       }
+ 
+-out:
++out_unlock:
+       mutex_unlock(&id_priv->handler_mutex);
+       cma_id_put(id_priv);
+-      if (destroy)
+-              rdma_destroy_id(&id_priv->id);
++out_free:
+       kfree(work);
+ }
+ 
+@@ -3171,9 +3157,7 @@ static void addr_handler(int status, struct sockaddr 
*src_addr,
+               event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
+ 
+       if (cma_cm_event_handler(id_priv, &event)) {
+-              cma_exch(id_priv, RDMA_CM_DESTROYING);
+-              mutex_unlock(&id_priv->handler_mutex);
+-              rdma_destroy_id(&id_priv->id);
++              destroy_id_handler_unlock(id_priv);
+               return;
+       }
+ out:
+@@ -3790,7 +3774,7 @@ static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
+       struct rdma_cm_event event = {};
+       const struct ib_cm_sidr_rep_event_param *rep =
+                               &ib_event->param.sidr_rep_rcvd;
+-      int ret = 0;
++      int ret;
+ 
+       mutex_lock(&id_priv->handler_mutex);
+       if (id_priv->state != RDMA_CM_CONNECT)
+@@ -3840,14 +3824,12 @@ static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
+       if (ret) {
+               /* Destroy the CM ID by returning a non-zero value. */
+               id_priv->cm_id.ib = NULL;
+-              cma_exch(id_priv, RDMA_CM_DESTROYING);
+-              mutex_unlock(&id_priv->handler_mutex);
+-              rdma_destroy_id(&id_priv->id);
++              destroy_id_handler_unlock(id_priv);
+               return ret;
+       }
+ out:
+       mutex_unlock(&id_priv->handler_mutex);
+-      return ret;
++      return 0;
+ }
+ 
+ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
+@@ -4372,9 +4354,7 @@ static int cma_ib_mc_handler(int status, struct 
ib_sa_multicast *multicast)
+ 
+       rdma_destroy_ah_attr(&event.param.ud.ah_attr);
+       if (ret) {
+-              cma_exch(id_priv, RDMA_CM_DESTROYING);
+-              mutex_unlock(&id_priv->handler_mutex);
+-              rdma_destroy_id(&id_priv->id);
++              destroy_id_handler_unlock(id_priv);
+               return 0;
+       }
+ 
+@@ -4789,50 +4769,59 @@ free_cma_dev:
+       return ret;
+ }
+ 
+-static int cma_remove_id_dev(struct rdma_id_private *id_priv)
++static void cma_send_device_removal_put(struct rdma_id_private *id_priv)
+ {
+-      struct rdma_cm_event event = {};
++      struct rdma_cm_event event = { .event = RDMA_CM_EVENT_DEVICE_REMOVAL };
+       enum rdma_cm_state state;
+-      int ret = 0;
+-
+-      /* Record that we want to remove the device */
+-      state = cma_exch(id_priv, RDMA_CM_DEVICE_REMOVAL);
+-      if (state == RDMA_CM_DESTROYING)
+-              return 0;
++      unsigned long flags;
+ 
+-      cma_cancel_operation(id_priv, state);
+       mutex_lock(&id_priv->handler_mutex);
++      /* Record that we want to remove the device */
++      spin_lock_irqsave(&id_priv->lock, flags);
++      state = id_priv->state;
++      if (state == RDMA_CM_DESTROYING || state == RDMA_CM_DEVICE_REMOVAL) {
++              spin_unlock_irqrestore(&id_priv->lock, flags);
++              mutex_unlock(&id_priv->handler_mutex);
++              cma_id_put(id_priv);
++              return;
++      }
++      id_priv->state = RDMA_CM_DEVICE_REMOVAL;
++      spin_unlock_irqrestore(&id_priv->lock, flags);
+ 
+-      /* Check for destruction from another callback. */
+-      if (!cma_comp(id_priv, RDMA_CM_DEVICE_REMOVAL))
+-              goto out;
+-
+-      event.event = RDMA_CM_EVENT_DEVICE_REMOVAL;
+-      ret = cma_cm_event_handler(id_priv, &event);
+-out:
++      if (cma_cm_event_handler(id_priv, &event)) {
++              /*
++               * At this point the ULP promises it won't call
++               * rdma_destroy_id() concurrently
++               */
++              cma_id_put(id_priv);
++              mutex_unlock(&id_priv->handler_mutex);
++              trace_cm_id_destroy(id_priv);
++              _destroy_id(id_priv, state);
++              return;
++      }
+       mutex_unlock(&id_priv->handler_mutex);
+-      return ret;
++
++      /*
++       * If this races with destroy then the thread that first assigns state
++       * to a destroying does the cancel.
++       */
++      cma_cancel_operation(id_priv, state);
++      cma_id_put(id_priv);
+ }
+ 
+ static void cma_process_remove(struct cma_device *cma_dev)
+ {
+-      struct rdma_id_private *id_priv;
+-      int ret;
+-
+       mutex_lock(&lock);
+       while (!list_empty(&cma_dev->id_list)) {
+-              id_priv = list_entry(cma_dev->id_list.next,
+-                                   struct rdma_id_private, list);
++              struct rdma_id_private *id_priv = list_first_entry(
++                      &cma_dev->id_list, struct rdma_id_private, list);
+ 
+               list_del(&id_priv->listen_list);
+               list_del_init(&id_priv->list);
+               cma_id_get(id_priv);
+               mutex_unlock(&lock);
+ 
+-              ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv);
+-              cma_id_put(id_priv);
+-              if (ret)
+-                      rdma_destroy_id(&id_priv->id);
++              cma_send_device_removal_put(id_priv);
+ 
+               mutex_lock(&lock);
+       }
+diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
+index b91f92e4e5f22..915ac75b55fc7 100644
+--- a/drivers/net/usb/dm9601.c
++++ b/drivers/net/usb/dm9601.c
+@@ -625,6 +625,10 @@ static const struct usb_device_id products[] = {
+        USB_DEVICE(0x0a46, 0x1269),    /* DM9621A USB to Fast Ethernet Adapter 
*/
+        .driver_info = (unsigned long)&dm9601_info,
+       },
++      {
++       USB_DEVICE(0x0586, 0x3427),    /* ZyXEL Keenetic Plus DSL xDSL modem */
++       .driver_info = (unsigned long)&dm9601_info,
++      },
+       {},                     // END
+ };
+ 
+diff --git a/fs/io_uring.c b/fs/io_uring.c
+index 38f3ec15ba3b1..d05023ca74bdc 100644
+--- a/fs/io_uring.c
++++ b/fs/io_uring.c
+@@ -7601,6 +7601,28 @@ static bool io_match_link(struct io_kiocb *preq, struct 
io_kiocb *req)
+       return false;
+ }
+ 
++static inline bool io_match_files(struct io_kiocb *req,
++                                     struct files_struct *files)
++{
++      return (req->flags & REQ_F_WORK_INITIALIZED) && req->work.files == 
files;
++}
++
++static bool io_match_link_files(struct io_kiocb *req,
++                              struct files_struct *files)
++{
++      struct io_kiocb *link;
++
++      if (io_match_files(req, files))
++              return true;
++      if (req->flags & REQ_F_LINK_HEAD) {
++              list_for_each_entry(link, &req->link_list, link_list) {
++                      if (io_match_files(link, files))
++                              return true;
++              }
++      }
++      return false;
++}
++
+ /*
+  * We're looking to cancel 'req' because it's holding on to our files, but
+  * 'req' could be a link to another request. See if it is, and cancel that
+@@ -7675,12 +7697,37 @@ static void io_attempt_cancel(struct io_ring_ctx *ctx, 
struct io_kiocb *req)
+       io_timeout_remove_link(ctx, req);
+ }
+ 
++static void io_cancel_defer_files(struct io_ring_ctx *ctx,
++                                struct files_struct *files)
++{
++      struct io_kiocb *req = NULL;
++      LIST_HEAD(list);
++
++      spin_lock_irq(&ctx->completion_lock);
++      list_for_each_entry_reverse(req, &ctx->defer_list, list) {
++              if (io_match_link_files(req, files)) {
++                      list_cut_position(&list, &ctx->defer_list, &req->list);
++                      break;
++              }
++      }
++      spin_unlock_irq(&ctx->completion_lock);
++
++      while (!list_empty(&list)) {
++              req = list_first_entry(&list, struct io_kiocb, list);
++              list_del_init(&req->list);
++              req_set_fail_links(req);
++              io_cqring_add_event(req, -ECANCELED);
++              io_double_put_req(req);
++      }
++}
++
+ static void io_uring_cancel_files(struct io_ring_ctx *ctx,
+                                 struct files_struct *files)
+ {
+       if (list_empty_careful(&ctx->inflight_list))
+               return;
+ 
++      io_cancel_defer_files(ctx, files);
+       /* cancel all at once, should be faster than doing it one by one*/
+       io_wq_cancel_cb(ctx->io_wq, io_wq_files_match, files, true);
+ 
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 7a774ebf64e26..5bd0b550893fb 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -6609,12 +6609,13 @@ void netif_napi_add(struct net_device *dev, struct 
napi_struct *napi,
+               netdev_err_once(dev, "%s() called with weight %d\n", __func__,
+                               weight);
+       napi->weight = weight;
+-      list_add(&napi->dev_list, &dev->napi_list);
+       napi->dev = dev;
+ #ifdef CONFIG_NETPOLL
+       napi->poll_owner = -1;
+ #endif
+       set_bit(NAPI_STATE_SCHED, &napi->state);
++      set_bit(NAPI_STATE_NPSVC, &napi->state);
++      list_add_rcu(&napi->dev_list, &dev->napi_list);
+       napi_hash_add(napi);
+ }
+ EXPORT_SYMBOL(netif_napi_add);
+diff --git a/net/core/netpoll.c b/net/core/netpoll.c
+index 093e90e52bc25..2338753e936b7 100644
+--- a/net/core/netpoll.c
++++ b/net/core/netpoll.c
+@@ -162,7 +162,7 @@ static void poll_napi(struct net_device *dev)
+       struct napi_struct *napi;
+       int cpu = smp_processor_id();
+ 
+-      list_for_each_entry(napi, &dev->napi_list, dev_list) {
++      list_for_each_entry_rcu(napi, &dev->napi_list, dev_list) {
+               if (cmpxchg(&napi->poll_owner, -1, cpu) == -1) {
+                       poll_one_napi(napi);
+                       smp_store_release(&napi->poll_owner, -1);
+diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
+index 3c65f71d0e820..6734bab26386b 100644
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -2121,7 +2121,8 @@ void fib_info_notify_update(struct net *net, struct 
nl_info *info)
+               struct hlist_head *head = &net->ipv4.fib_table_hash[h];
+               struct fib_table *tb;
+ 
+-              hlist_for_each_entry_rcu(tb, head, tb_hlist)
++              hlist_for_each_entry_rcu(tb, head, tb_hlist,
++                                       lockdep_rtnl_is_held())
+                       __fib_info_notify_update(net, tb, info);
+       }
+ }
+diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
+index fac2135aa47b6..5b60a4bdd36af 100644
+--- a/net/ipv6/sysctl_net_ipv6.c
++++ b/net/ipv6/sysctl_net_ipv6.c
+@@ -21,6 +21,7 @@
+ #include <net/calipso.h>
+ #endif
+ 
++static int two = 2;
+ static int flowlabel_reflect_max = 0x7;
+ static int auto_flowlabels_min;
+ static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX;
+@@ -150,7 +151,7 @@ static struct ctl_table ipv6_table_template[] = {
+               .mode           = 0644,
+               .proc_handler   = proc_rt6_multipath_hash_policy,
+               .extra1         = SYSCTL_ZERO,
+-              .extra2         = SYSCTL_ONE,
++              .extra2         = &two,
+       },
+       {
+               .procname       = "seg6_flowlabel",
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index c0abe738e7d31..939e445d5188c 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -772,7 +772,6 @@ fallback:
+ restart:
+       mptcp_clean_una(sk);
+ 
+-wait_for_sndbuf:
+       __mptcp_flush_join_list(msk);
+       ssk = mptcp_subflow_get_send(msk);
+       while (!sk_stream_memory_free(sk) ||
+@@ -873,7 +872,7 @@ wait_for_sndbuf:
+                                */
+                               mptcp_set_timeout(sk, ssk);
+                               release_sock(ssk);
+-                              goto wait_for_sndbuf;
++                              goto restart;
+                       }
+               }
+       }
+diff --git a/net/netlabel/netlabel_domainhash.c 
b/net/netlabel/netlabel_domainhash.c
+index a1f2320ecc16d..785d13b8b5748 100644
+--- a/net/netlabel/netlabel_domainhash.c
++++ b/net/netlabel/netlabel_domainhash.c
+@@ -85,6 +85,7 @@ static void netlbl_domhsh_free_entry(struct rcu_head *entry)
+                       kfree(netlbl_domhsh_addr6_entry(iter6));
+               }
+ #endif /* IPv6 */
++              kfree(ptr->def.addrsel);
+       }
+       kfree(ptr->domain);
+       kfree(ptr);
+@@ -537,6 +538,8 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
+                               goto add_return;
+               }
+ #endif /* IPv6 */
++              /* cleanup the new entry since we've moved everything over */
++              netlbl_domhsh_free_entry(&entry->rcu);
+       } else
+               ret_val = -EINVAL;
+ 
+@@ -580,6 +583,12 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map 
*entry,
+ {
+       int ret_val = 0;
+       struct audit_buffer *audit_buf;
++      struct netlbl_af4list *iter4;
++      struct netlbl_domaddr4_map *map4;
++#if IS_ENABLED(CONFIG_IPV6)
++      struct netlbl_af6list *iter6;
++      struct netlbl_domaddr6_map *map6;
++#endif /* IPv6 */
+ 
+       if (entry == NULL)
+               return -ENOENT;
+@@ -597,6 +606,9 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map 
*entry,
+               ret_val = -ENOENT;
+       spin_unlock(&netlbl_domhsh_lock);
+ 
++      if (ret_val)
++              return ret_val;
++
+       audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
+       if (audit_buf != NULL) {
+               audit_log_format(audit_buf,
+@@ -606,40 +618,29 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map 
*entry,
+               audit_log_end(audit_buf);
+       }
+ 
+-      if (ret_val == 0) {
+-              struct netlbl_af4list *iter4;
+-              struct netlbl_domaddr4_map *map4;
+-#if IS_ENABLED(CONFIG_IPV6)
+-              struct netlbl_af6list *iter6;
+-              struct netlbl_domaddr6_map *map6;
+-#endif /* IPv6 */
+-
+-              switch (entry->def.type) {
+-              case NETLBL_NLTYPE_ADDRSELECT:
+-                      netlbl_af4list_foreach_rcu(iter4,
+-                                           &entry->def.addrsel->list4) {
+-                              map4 = netlbl_domhsh_addr4_entry(iter4);
+-                              cipso_v4_doi_putdef(map4->def.cipso);
+-                      }
++      switch (entry->def.type) {
++      case NETLBL_NLTYPE_ADDRSELECT:
++              netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
++                      map4 = netlbl_domhsh_addr4_entry(iter4);
++                      cipso_v4_doi_putdef(map4->def.cipso);
++              }
+ #if IS_ENABLED(CONFIG_IPV6)
+-                      netlbl_af6list_foreach_rcu(iter6,
+-                                           &entry->def.addrsel->list6) {
+-                              map6 = netlbl_domhsh_addr6_entry(iter6);
+-                              calipso_doi_putdef(map6->def.calipso);
+-                      }
++              netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
++                      map6 = netlbl_domhsh_addr6_entry(iter6);
++                      calipso_doi_putdef(map6->def.calipso);
++              }
+ #endif /* IPv6 */
+-                      break;
+-              case NETLBL_NLTYPE_CIPSOV4:
+-                      cipso_v4_doi_putdef(entry->def.cipso);
+-                      break;
++              break;
++      case NETLBL_NLTYPE_CIPSOV4:
++              cipso_v4_doi_putdef(entry->def.cipso);
++              break;
+ #if IS_ENABLED(CONFIG_IPV6)
+-              case NETLBL_NLTYPE_CALIPSO:
+-                      calipso_doi_putdef(entry->def.calipso);
+-                      break;
++      case NETLBL_NLTYPE_CALIPSO:
++              calipso_doi_putdef(entry->def.calipso);
++              break;
+ #endif /* IPv6 */
+-              }
+-              call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
+       }
++      call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
+ 
+       return ret_val;
+ }
+diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
+index b1eb12d33b9a6..6a5086e586efb 100644
+--- a/net/sched/sch_taprio.c
++++ b/net/sched/sch_taprio.c
+@@ -1177,9 +1177,27 @@ static void taprio_offload_config_changed(struct 
taprio_sched *q)
+       spin_unlock(&q->current_entry_lock);
+ }
+ 
+-static void taprio_sched_to_offload(struct taprio_sched *q,
++static u32 tc_map_to_queue_mask(struct net_device *dev, u32 tc_mask)
++{
++      u32 i, queue_mask = 0;
++
++      for (i = 0; i < dev->num_tc; i++) {
++              u32 offset, count;
++
++              if (!(tc_mask & BIT(i)))
++                      continue;
++
++              offset = dev->tc_to_txq[i].offset;
++              count = dev->tc_to_txq[i].count;
++
++              queue_mask |= GENMASK(offset + count - 1, offset);
++      }
++
++      return queue_mask;
++}
++
++static void taprio_sched_to_offload(struct net_device *dev,
+                                   struct sched_gate_list *sched,
+-                                  const struct tc_mqprio_qopt *mqprio,
+                                   struct tc_taprio_qopt_offload *offload)
+ {
+       struct sched_entry *entry;
+@@ -1194,7 +1212,8 @@ static void taprio_sched_to_offload(struct taprio_sched 
*q,
+ 
+               e->command = entry->command;
+               e->interval = entry->interval;
+-              e->gate_mask = entry->gate_mask;
++              e->gate_mask = tc_map_to_queue_mask(dev, entry->gate_mask);
++
+               i++;
+       }
+ 
+@@ -1202,7 +1221,6 @@ static void taprio_sched_to_offload(struct taprio_sched 
*q,
+ }
+ 
+ static int taprio_enable_offload(struct net_device *dev,
+-                               struct tc_mqprio_qopt *mqprio,
+                                struct taprio_sched *q,
+                                struct sched_gate_list *sched,
+                                struct netlink_ext_ack *extack)
+@@ -1224,7 +1242,7 @@ static int taprio_enable_offload(struct net_device *dev,
+               return -ENOMEM;
+       }
+       offload->enable = 1;
+-      taprio_sched_to_offload(q, sched, mqprio, offload);
++      taprio_sched_to_offload(dev, sched, offload);
+ 
+       err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_TAPRIO, offload);
+       if (err < 0) {
+@@ -1486,7 +1504,7 @@ static int taprio_change(struct Qdisc *sch, struct 
nlattr *opt,
+       }
+ 
+       if (FULL_OFFLOAD_IS_ENABLED(q->flags))
+-              err = taprio_enable_offload(dev, mqprio, q, new_admin, extack);
++              err = taprio_enable_offload(dev, q, new_admin, extack);
+       else
+               err = taprio_disable_offload(dev, q, extack);
+       if (err)
+diff --git a/net/sctp/socket.c b/net/sctp/socket.c
+index d57e1a002ffc8..fa20e945700e0 100644
+--- a/net/sctp/socket.c
++++ b/net/sctp/socket.c
+@@ -8297,8 +8297,6 @@ static int sctp_get_port_local(struct sock *sk, union 
sctp_addr *addr)
+ 
+       pr_debug("%s: begins, snum:%d\n", __func__, snum);
+ 
+-      local_bh_disable();
+-
+       if (snum == 0) {
+               /* Search for an available port. */
+               int low, high, remaining, index;
+@@ -8316,20 +8314,21 @@ static int sctp_get_port_local(struct sock *sk, union 
sctp_addr *addr)
+                               continue;
+                       index = sctp_phashfn(net, rover);
+                       head = &sctp_port_hashtable[index];
+-                      spin_lock(&head->lock);
++                      spin_lock_bh(&head->lock);
+                       sctp_for_each_hentry(pp, &head->chain)
+                               if ((pp->port == rover) &&
+                                   net_eq(net, pp->net))
+                                       goto next;
+                       break;
+               next:
+-                      spin_unlock(&head->lock);
++                      spin_unlock_bh(&head->lock);
++                      cond_resched();
+               } while (--remaining > 0);
+ 
+               /* Exhausted local port range during search? */
+               ret = 1;
+               if (remaining <= 0)
+-                      goto fail;
++                      return ret;
+ 
+               /* OK, here is the one we will use.  HEAD (the port
+                * hash table list entry) is non-NULL and we hold it's
+@@ -8344,7 +8343,7 @@ static int sctp_get_port_local(struct sock *sk, union 
sctp_addr *addr)
+                * port iterator, pp being NULL.
+                */
+               head = &sctp_port_hashtable[sctp_phashfn(net, snum)];
+-              spin_lock(&head->lock);
++              spin_lock_bh(&head->lock);
+               sctp_for_each_hentry(pp, &head->chain) {
+                       if ((pp->port == snum) && net_eq(pp->net, net))
+                               goto pp_found;
+@@ -8444,10 +8443,7 @@ success:
+       ret = 0;
+ 
+ fail_unlock:
+-      spin_unlock(&head->lock);
+-
+-fail:
+-      local_bh_enable();
++      spin_unlock_bh(&head->lock);
+       return ret;
+ }
+ 
+diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c
+index d6426b6cc9c5a..3f35577b7404f 100644
+--- a/net/tipc/crypto.c
++++ b/net/tipc/crypto.c
+@@ -326,7 +326,8 @@ static void tipc_aead_free(struct rcu_head *rp)
+       if (aead->cloned) {
+               tipc_aead_put(aead->cloned);
+       } else {
+-              head = *this_cpu_ptr(aead->tfm_entry);
++              head = *get_cpu_ptr(aead->tfm_entry);
++              put_cpu_ptr(aead->tfm_entry);
+               list_for_each_entry_safe(tfm_entry, tmp, &head->list, list) {
+                       crypto_free_aead(tfm_entry->tfm);
+                       list_del(&tfm_entry->list);
+@@ -399,10 +400,15 @@ static void tipc_aead_users_set(struct tipc_aead __rcu 
*aead, int val)
+  */
+ static struct crypto_aead *tipc_aead_tfm_next(struct tipc_aead *aead)
+ {
+-      struct tipc_tfm **tfm_entry = this_cpu_ptr(aead->tfm_entry);
++      struct tipc_tfm **tfm_entry;
++      struct crypto_aead *tfm;
+ 
++      tfm_entry = get_cpu_ptr(aead->tfm_entry);
+       *tfm_entry = list_next_entry(*tfm_entry, list);
+-      return (*tfm_entry)->tfm;
++      tfm = (*tfm_entry)->tfm;
++      put_cpu_ptr(tfm_entry);
++
++      return tfm;
+ }
+ 
+ /**
+diff --git a/net/tipc/socket.c b/net/tipc/socket.c
+index a94f38333698a..79cc84393f932 100644
+--- a/net/tipc/socket.c
++++ b/net/tipc/socket.c
+@@ -2773,18 +2773,21 @@ static int tipc_shutdown(struct socket *sock, int how)
+ 
+       trace_tipc_sk_shutdown(sk, NULL, TIPC_DUMP_ALL, " ");
+       __tipc_shutdown(sock, TIPC_CONN_SHUTDOWN);
+-      sk->sk_shutdown = SEND_SHUTDOWN;
++      if (tipc_sk_type_connectionless(sk))
++              sk->sk_shutdown = SHUTDOWN_MASK;
++      else
++              sk->sk_shutdown = SEND_SHUTDOWN;
+ 
+       if (sk->sk_state == TIPC_DISCONNECTING) {
+               /* Discard any unreceived messages */
+               __skb_queue_purge(&sk->sk_receive_queue);
+ 
+-              /* Wake up anyone sleeping in poll */
+-              sk->sk_state_change(sk);
+               res = 0;
+       } else {
+               res = -ENOTCONN;
+       }
++      /* Wake up anyone sleeping in poll. */
++      sk->sk_state_change(sk);
+ 
+       release_sock(sk);
+       return res;

Reply via email to