From: "Matthew Wilcox (Oracle)" <wi...@infradead.org>

Replae the func_lock with the internal XArray spinlock.  Ensuring that
nan_func is fully initialised before dropping the lock allows us to
iterate the array while not holding the lock, avoiding the awkward dance
in ieee80211_reconfig_nan().

Signed-off-by: Matthew Wilcox (Oracle) <wi...@infradead.org>
---
 net/mac80211/cfg.c         | 57 ++++++++++++++------------------------
 net/mac80211/ieee80211_i.h |  9 ++----
 net/mac80211/iface.c       | 16 +++++------
 net/mac80211/util.c        | 30 ++++----------------
 4 files changed, 37 insertions(+), 75 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 47d7670094a9..2ea45b7007db 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -266,7 +266,7 @@ static int ieee80211_add_nan_func(struct wiphy *wiphy,
                                  struct cfg80211_nan_func *nan_func)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
-       int ret;
+       int ret, id;
 
        if (sdata->vif.type != NL80211_IFTYPE_NAN)
                return -EOPNOTSUPP;
@@ -274,27 +274,22 @@ static int ieee80211_add_nan_func(struct wiphy *wiphy,
        if (!ieee80211_sdata_running(sdata))
                return -ENETDOWN;
 
-       spin_lock_bh(&sdata->u.nan.func_lock);
-
-       ret = idr_alloc(&sdata->u.nan.function_inst_ids,
-                       nan_func, 1, sdata->local->hw.max_nan_de_entries + 1,
-                       GFP_ATOMIC);
-       spin_unlock_bh(&sdata->u.nan.func_lock);
+       xa_lock_bh(&sdata->u.nan.functions);
+       ret = __xa_alloc(&sdata->u.nan.functions, &id, nan_func,
+                       XA_LIMIT(0, sdata->local->hw.max_nan_de_entries),
+                       GFP_KERNEL);
+       if (ret == 0)
+               nan_func->instance_id = id;
+       xa_unlock_bh(&sdata->u.nan.functions);
 
        if (ret < 0)
                return ret;
 
-       nan_func->instance_id = ret;
-
        WARN_ON(nan_func->instance_id == 0);
 
        ret = drv_add_nan_func(sdata->local, sdata, nan_func);
-       if (ret) {
-               spin_lock_bh(&sdata->u.nan.func_lock);
-               idr_remove(&sdata->u.nan.function_inst_ids,
-                          nan_func->instance_id);
-               spin_unlock_bh(&sdata->u.nan.func_lock);
-       }
+       if (ret)
+               xa_erase_bh(&sdata->u.nan.functions, nan_func->instance_id);
 
        return ret;
 }
@@ -304,11 +299,11 @@ ieee80211_find_nan_func_by_cookie(struct 
ieee80211_sub_if_data *sdata,
                                  u64 cookie)
 {
        struct cfg80211_nan_func *func;
-       int id;
+       unsigned long id;
 
-       lockdep_assert_held(&sdata->u.nan.func_lock);
+       lockdep_assert_held(&sdata->u.nan.functions.xa_lock);
 
-       idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id) {
+       xa_for_each(&sdata->u.nan.functions, id, func) {
                if (func->cookie == cookie)
                        return func;
        }
@@ -327,13 +322,13 @@ static void ieee80211_del_nan_func(struct wiphy *wiphy,
            !ieee80211_sdata_running(sdata))
                return;
 
-       spin_lock_bh(&sdata->u.nan.func_lock);
+       xa_lock_bh(&sdata->u.nan.functions);
 
        func = ieee80211_find_nan_func_by_cookie(sdata, cookie);
        if (func)
                instance_id = func->instance_id;
 
-       spin_unlock_bh(&sdata->u.nan.func_lock);
+       xa_unlock_bh(&sdata->u.nan.functions);
 
        if (instance_id)
                drv_del_nan_func(sdata->local, sdata, instance_id);
@@ -3766,19 +3761,11 @@ void ieee80211_nan_func_terminated(struct ieee80211_vif 
*vif,
        if (WARN_ON(vif->type != NL80211_IFTYPE_NAN))
                return;
 
-       spin_lock_bh(&sdata->u.nan.func_lock);
-
-       func = idr_find(&sdata->u.nan.function_inst_ids, inst_id);
-       if (WARN_ON(!func)) {
-               spin_unlock_bh(&sdata->u.nan.func_lock);
+       func = xa_erase_bh(&sdata->u.nan.functions, inst_id);
+       if (WARN_ON(!func))
                return;
-       }
 
        cookie = func->cookie;
-       idr_remove(&sdata->u.nan.function_inst_ids, inst_id);
-
-       spin_unlock_bh(&sdata->u.nan.func_lock);
-
        cfg80211_free_nan_func(func);
 
        cfg80211_nan_func_terminated(ieee80211_vif_to_wdev(vif), inst_id,
@@ -3796,16 +3783,14 @@ void ieee80211_nan_func_match(struct ieee80211_vif *vif,
        if (WARN_ON(vif->type != NL80211_IFTYPE_NAN))
                return;
 
-       spin_lock_bh(&sdata->u.nan.func_lock);
-
-       func = idr_find(&sdata->u.nan.function_inst_ids,  match->inst_id);
+       xa_lock_bh(&sdata->u.nan.functions);
+       func = xa_load(&sdata->u.nan.functions,  match->inst_id);
        if (WARN_ON(!func)) {
-               spin_unlock_bh(&sdata->u.nan.func_lock);
+               xa_unlock_bh(&sdata->u.nan.functions);
                return;
        }
        match->cookie = func->cookie;
-
-       spin_unlock_bh(&sdata->u.nan.func_lock);
+       xa_unlock_bh(&sdata->u.nan.functions);
 
        cfg80211_nan_match(ieee80211_vif_to_wdev(vif), match, gfp);
 }
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ade005892099..7be25939a6bf 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -23,7 +23,7 @@
 #include <linux/spinlock.h>
 #include <linux/etherdevice.h>
 #include <linux/leds.h>
-#include <linux/idr.h>
+#include <linux/xarray.h>
 #include <linux/rhashtable.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/cfg80211.h>
@@ -862,14 +862,11 @@ struct ieee80211_if_mntr {
  * struct ieee80211_if_nan - NAN state
  *
  * @conf: current NAN configuration
- * @func_ids: a bitmap of available instance_id's
+ * @functions: NAN function pointers
  */
 struct ieee80211_if_nan {
        struct cfg80211_nan_conf conf;
-
-       /* protects function_inst_ids */
-       spinlock_t func_lock;
-       struct idr function_inst_ids;
+       struct xarray functions;
 };
 
 struct ieee80211_sub_if_data {
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 8dc6580e1787..022e2eb6a46c 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -802,6 +802,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data 
*sdata,
        struct cfg80211_chan_def chandef;
        bool cancel_scan;
        struct cfg80211_nan_func *func;
+       unsigned long index;
 
        clear_bit(SDATA_STATE_RUNNING, &sdata->state);
 
@@ -961,15 +962,12 @@ static void ieee80211_do_stop(struct 
ieee80211_sub_if_data *sdata,
                break;
        case NL80211_IFTYPE_NAN:
                /* clean all the functions */
-               spin_lock_bh(&sdata->u.nan.func_lock);
-
-               idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, i) {
-                       idr_remove(&sdata->u.nan.function_inst_ids, i);
+               xa_lock_bh(&sdata->u.nan.functions);
+               xa_for_each(&sdata->u.nan.functions, index, func) {
+                       __xa_erase(&sdata->u.nan.functions, index);
                        cfg80211_free_nan_func(func);
                }
-               idr_destroy(&sdata->u.nan.function_inst_ids);
-
-               spin_unlock_bh(&sdata->u.nan.func_lock);
+               xa_unlock_bh(&sdata->u.nan.functions);
                break;
        case NL80211_IFTYPE_P2P_DEVICE:
                /* relies on synchronize_rcu() below */
@@ -1463,8 +1461,8 @@ static void ieee80211_setup_sdata(struct 
ieee80211_sub_if_data *sdata,
                sdata->vif.bss_conf.bssid = NULL;
                break;
        case NL80211_IFTYPE_NAN:
-               idr_init(&sdata->u.nan.function_inst_ids);
-               spin_lock_init(&sdata->u.nan.func_lock);
+               xa_init_flags(&sdata->u.nan.functions,
+                               XA_FLAGS_ALLOC1 | XA_FLAGS_LOCK_BH);
                sdata->vif.bss_conf.bssid = sdata->vif.addr;
                break;
        case NL80211_IFTYPE_AP_VLAN:
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 286c7ee35e63..4996a3c01205 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2082,42 +2082,24 @@ static void ieee80211_reconfig_stations(struct 
ieee80211_sub_if_data *sdata)
 
 static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata)
 {
-       struct cfg80211_nan_func *func, **funcs;
-       int res, id, i = 0;
+       struct cfg80211_nan_func *func;
+       unsigned long id;
+       int res;
 
        res = drv_start_nan(sdata->local, sdata,
                            &sdata->u.nan.conf);
        if (WARN_ON(res))
                return res;
 
-       funcs = kcalloc(sdata->local->hw.max_nan_de_entries + 1,
-                       sizeof(*funcs),
-                       GFP_KERNEL);
-       if (!funcs)
-               return -ENOMEM;
-
-       /* Add all the functions:
-        * This is a little bit ugly. We need to call a potentially sleeping
-        * callback for each NAN function, so we can't hold the spinlock.
-        */
-       spin_lock_bh(&sdata->u.nan.func_lock);
-
-       idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id)
-               funcs[i++] = func;
-
-       spin_unlock_bh(&sdata->u.nan.func_lock);
-
-       for (i = 0; funcs[i]; i++) {
-               res = drv_add_nan_func(sdata->local, sdata, funcs[i]);
+       xa_for_each(&sdata->u.nan.functions, id, func) {
+               res = drv_add_nan_func(sdata->local, sdata, func);
                if (WARN_ON(res))
                        ieee80211_nan_func_terminated(&sdata->vif,
-                                                     funcs[i]->instance_id,
+                                                     func->instance_id,
                                                      
NL80211_NAN_FUNC_TERM_REASON_ERROR,
                                                      GFP_KERNEL);
        }
 
-       kfree(funcs);
-
        return 0;
 }
 
-- 
2.23.0.rc1

Reply via email to