mac80211: compute chanctx refcount on-the-fly
authorMichal Kazior <michal.kazior@tieto.com>
Wed, 9 Apr 2014 13:29:33 +0000 (15:29 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 25 Apr 2014 15:08:30 +0000 (17:08 +0200)
It doesn't make much sense to store refcount in
the chanctx structure. One still needs to hold
chanctx_mtx to get the value safely. Besides,
refcount isn't on performance critical paths.

This will make implementing chanctx reservation
refcounting a little easier.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c

index 9620d4fba0d1ab0b95056df19e353ff941886140..4d15a1566cd5b6f1fb56c6fec689bbf2cdd5b74f 100644 (file)
@@ -3251,7 +3251,7 @@ int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 
        /* don't handle for multi-VIF cases */
        chanctx = container_of(conf, struct ieee80211_chanctx, conf);
-       if (chanctx->refcount > 1) {
+       if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
                mutex_unlock(&local->chanctx_mtx);
                return -EBUSY;
        }
index e4166b3af5d46e70c286b540c3a12e294d1a1af4..d8b1b861484259a426e91ad12d5dbe0ac17f784b 100644 (file)
@@ -9,6 +9,41 @@
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
+static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
+                                         struct ieee80211_chanctx *ctx)
+{
+       struct ieee80211_sub_if_data *sdata;
+       int num = 0;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
+               num++;
+
+       return num;
+}
+
+static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
+                                         struct ieee80211_chanctx *ctx)
+{
+       struct ieee80211_sub_if_data *sdata;
+       int num = 0;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list)
+               num++;
+
+       return num;
+}
+
+int ieee80211_chanctx_refcount(struct ieee80211_local *local,
+                              struct ieee80211_chanctx *ctx)
+{
+       return ieee80211_chanctx_num_assigned(local, ctx) +
+              ieee80211_chanctx_num_reserved(local, ctx);
+}
+
 static int ieee80211_num_chanctx(struct ieee80211_local *local)
 {
        struct ieee80211_chanctx *ctx;
@@ -463,7 +498,7 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
 {
        lockdep_assert_held(&local->chanctx_mtx);
 
-       WARN_ON_ONCE(ctx->refcount != 0);
+       WARN_ON_ONCE(ieee80211_chanctx_refcount(local, ctx) != 0);
 
        list_del_rcu(&ctx->list);
        ieee80211_del_chanctx(local, ctx);
@@ -542,7 +577,6 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
        if (conf) {
                curr_ctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-               curr_ctx->refcount--;
                drv_unassign_vif_chanctx(local, sdata, curr_ctx);
                conf = NULL;
                list_del(&sdata->assigned_chanctx_list);
@@ -553,7 +587,6 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
                if (ret)
                        goto out;
 
-               new_ctx->refcount++;
                conf = &new_ctx->conf;
                list_add(&sdata->assigned_chanctx_list,
                         &new_ctx->assigned_vifs);
@@ -564,14 +597,14 @@ out:
 
        sdata->vif.bss_conf.idle = !conf;
 
-       if (curr_ctx && curr_ctx->refcount > 0) {
+       if (curr_ctx && ieee80211_chanctx_num_assigned(local, curr_ctx) > 0) {
                ieee80211_recalc_chanctx_chantype(local, curr_ctx);
                ieee80211_recalc_smps_chanctx(local, curr_ctx);
                ieee80211_recalc_radar_chanctx(local, curr_ctx);
                ieee80211_recalc_chanctx_min_def(local, curr_ctx);
        }
 
-       if (new_ctx && new_ctx->refcount > 0) {
+       if (new_ctx && ieee80211_chanctx_num_assigned(local, new_ctx) > 0) {
                ieee80211_recalc_txpower(sdata);
                ieee80211_recalc_chanctx_min_def(local, new_ctx);
        }
@@ -603,7 +636,7 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
                ieee80211_vif_unreserve_chanctx(sdata);
 
        ieee80211_assign_vif_chanctx(sdata, NULL);
-       if (ctx->refcount == 0)
+       if (ieee80211_chanctx_refcount(local, ctx) == 0)
                ieee80211_free_chanctx(local, ctx);
 }
 
@@ -735,7 +768,7 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
        ret = ieee80211_assign_vif_chanctx(sdata, ctx);
        if (ret) {
                /* if assign fails refcount stays the same */
-               if (ctx->refcount == 0)
+               if (ieee80211_chanctx_refcount(local, ctx) == 0)
                        ieee80211_free_chanctx(local, ctx);
                goto out;
        }
@@ -759,7 +792,7 @@ static int __ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
                                     IEEE80211_CHAN_DISABLED))
                return -EINVAL;
 
-       if (ctx->refcount != 1)
+       if (ieee80211_chanctx_refcount(local, ctx) != 1)
                return -EINVAL;
 
        if (sdata->vif.bss_conf.chandef.width != chandef->width) {
@@ -865,7 +898,7 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
        list_del(&sdata->reserved_chanctx_list);
        sdata->reserved_chanctx = NULL;
 
-       if (--ctx->refcount == 0)
+       if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0)
                ieee80211_free_chanctx(sdata->local, ctx);
 
        return 0;
@@ -894,7 +927,7 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 
        new_ctx = ieee80211_find_reservation_chanctx(local, chandef, mode);
        if (!new_ctx) {
-               if (curr_ctx->refcount == 1 &&
+               if (ieee80211_chanctx_refcount(local, curr_ctx) == 1 &&
                    (local->hw.flags & IEEE80211_HW_CHANGE_RUNNING_CHANCTX)) {
                        /* if we're the only users of the chanctx and
                         * the driver supports changing a running
@@ -915,7 +948,6 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
        }
 
        list_add(&sdata->reserved_chanctx_list, &new_ctx->reserved_vifs);
-       new_ctx->refcount++;
        sdata->reserved_chanctx = new_ctx;
        sdata->reserved_chandef = *chandef;
        sdata->reserved_radar_required = radar_required;
@@ -961,7 +993,6 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
        sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
 
        /* unref our reservation */
-       ctx->refcount--;
        sdata->reserved_chanctx = NULL;
        sdata->radar_required = sdata->reserved_radar_required;
        list_del(&sdata->reserved_chanctx_list);
@@ -974,11 +1005,11 @@ int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
                        goto out;
        } else {
                ret = ieee80211_assign_vif_chanctx(sdata, ctx);
-               if (old_ctx->refcount == 0)
+               if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
                        ieee80211_free_chanctx(local, old_ctx);
                if (ret) {
                        /* if assign fails refcount stays the same */
-                       if (ctx->refcount == 0)
+                       if (ieee80211_chanctx_refcount(local, ctx) == 0)
                                ieee80211_free_chanctx(local, ctx);
                        goto out;
                }
index 3eaf6d7fad52c13b64beaa507283e4a8518a72f0..b455f62d357ad6675bad1eda38c9019b6a7539c9 100644 (file)
@@ -695,7 +695,6 @@ struct ieee80211_chanctx {
        struct list_head reserved_vifs;
 
        enum ieee80211_chanctx_mode mode;
-       int refcount;
        bool driver_present;
 
        struct ieee80211_chanctx_conf conf;
@@ -1803,6 +1802,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);
 void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
                                         bool clear);
+int ieee80211_chanctx_refcount(struct ieee80211_local *local,
+                              struct ieee80211_chanctx *ctx);
 
 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
                                   struct ieee80211_chanctx *chanctx);
index dee50aefd6e868e247ba869e9e9883d4640330e3..98755ce49af345f06d481ee494d7b2eda12b117d 100644 (file)
@@ -1089,7 +1089,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        }
        chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
                               struct ieee80211_chanctx, conf);
-       if (chanctx->refcount > 1) {
+       if (ieee80211_chanctx_refcount(local, chanctx) > 1) {
                sdata_info(sdata,
                           "channel switch with multiple interfaces on the same channel, disconnecting\n");
                ieee80211_queue_work(&local->hw,