]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: mac80211: remove chanctx to link back-references
authorJohannes Berg <johannes.berg@intel.com>
Wed, 5 Nov 2025 15:03:43 +0000 (16:03 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 10 Nov 2025 09:38:49 +0000 (10:38 +0100)
Each link can currently use a chanctx and have another one
reserved, and both of these are also tracked backwards in
the assigned_links and reserved_links lists. If we consider
that there aren't *that* many links, this duplicate book-
keeping isn't necessary.
(I think it used to be necessary before the wiphy locking
changes, when chanctx_mtx existed, because we couldn't do
any interface iterations while holding only chanctx_mtx.)

Additionally, for NAN, we're going to want to track which
chanctxs are in use by the (group of) NAN interfaces. For
those, links don't really make sense as such, so chanctxs
need to be assigned to a different data structure.

Thus, as a first step, remove those back-lists of users
(right now only links) of each channel context. This is a
very basic conversion, ieee80211_vif_use_reserved_switch()
should made to iterate smarter.

Link: https://patch.msgid.link/20251105160431.dbeea1c42e76.I8d273c407274e1c05a4778aa20b56a9f326e87a7@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/chan.c
net/mac80211/ieee80211_i.h
net/mac80211/link.c
net/mac80211/util.c

index 7f8799fd673eb81bab0e680b1e6331aa3215ad17..944e1c18501a79d5f6a5b969e385434e2864f0a5 100644 (file)
@@ -20,8 +20,10 @@ static int ieee80211_chanctx_num_assigned(struct ieee80211_local *local,
 
        lockdep_assert_wiphy(local->hw.wiphy);
 
-       list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list)
-               num++;
+       for_each_sdata_link(local, link) {
+               if (rcu_access_pointer(link->conf->chanctx_conf) == &ctx->conf)
+                       num++;
+       }
 
        return num;
 }
@@ -34,8 +36,10 @@ static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
 
        lockdep_assert_wiphy(local->hw.wiphy);
 
-       list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list)
-               num++;
+       for_each_sdata_link(local, link) {
+               if (link->reserved_chanctx == ctx)
+                       num++;
+       }
 
        return num;
 }
@@ -43,8 +47,19 @@ static int ieee80211_chanctx_num_reserved(struct ieee80211_local *local,
 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);
+       struct ieee80211_link_data *link;
+       int num = 0;
+
+       lockdep_assert_wiphy(local->hw.wiphy);
+
+       for_each_sdata_link(local, link) {
+               if (rcu_access_pointer(link->conf->chanctx_conf) == &ctx->conf)
+                       num++;
+               if (link->reserved_chanctx == ctx)
+                       num++;
+       }
+
+       return num;
 }
 
 static int ieee80211_num_chanctx(struct ieee80211_local *local, int radio_idx)
@@ -150,7 +165,10 @@ ieee80211_chanctx_reserved_chanreq(struct ieee80211_local *local,
        if (WARN_ON(!req))
                return NULL;
 
-       list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) {
+       for_each_sdata_link(local, link) {
+               if (link->reserved_chanctx != ctx)
+                       continue;
+
                req = ieee80211_chanreq_compatible(&link->reserved, req, tmp);
                if (!req)
                        break;
@@ -170,9 +188,12 @@ ieee80211_chanctx_non_reserved_chandef(struct ieee80211_local *local,
 
        lockdep_assert_wiphy(local->hw.wiphy);
 
-       list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) {
+       for_each_sdata_link(local, link) {
                struct ieee80211_bss_conf *link_conf = link->conf;
 
+               if (rcu_access_pointer(link_conf->chanctx_conf) != &ctx->conf)
+                       continue;
+
                if (link->reserved_chanctx)
                        continue;
 
@@ -200,7 +221,7 @@ ieee80211_chanctx_can_reserve(struct ieee80211_local *local,
        if (!ieee80211_chanctx_non_reserved_chandef(local, ctx, req, &tmp))
                return false;
 
-       if (!list_empty(&ctx->reserved_links) &&
+       if (ieee80211_chanctx_num_reserved(local, ctx) != 0 &&
            ieee80211_chanctx_reserved_chanreq(local, ctx, req, &tmp))
                return true;
 
@@ -633,8 +654,6 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
                 * context to actually be removed.
                 */
                link->reserved_chanctx = ctx;
-               list_add(&link->reserved_chanctx_list,
-                        &ctx->reserved_links);
 
                ieee80211_change_chanctx(local, ctx, ctx, compat);
 
@@ -705,8 +724,6 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local,
        if (!ctx)
                return NULL;
 
-       INIT_LIST_HEAD(&ctx->assigned_links);
-       INIT_LIST_HEAD(&ctx->reserved_links);
        ctx->conf.def = chanreq->oper;
        ctx->conf.ap = chanreq->ap;
        ctx->conf.rx_chains_static = 1;
@@ -904,7 +921,6 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
 
                drv_unassign_vif_chanctx(local, sdata, link->conf, curr_ctx);
                conf = NULL;
-               list_del(&link->assigned_chanctx_list);
        }
 
        if (new_ctx) {
@@ -919,9 +935,6 @@ static int ieee80211_assign_link_chanctx(struct ieee80211_link_data *link,
 
                        /* succeeded, so commit it to the data structures */
                        conf = &new_ctx->conf;
-                       if (!local->in_reconfig)
-                               list_add(&link->assigned_chanctx_list,
-                                        &new_ctx->assigned_links);
                }
        } else {
                ret = 0;
@@ -1108,7 +1121,6 @@ void ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link)
        if (WARN_ON(!ctx))
                return;
 
-       list_del(&link->reserved_chanctx_list);
        link->reserved_chanctx = NULL;
 
        if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) {
@@ -1142,9 +1154,9 @@ ieee80211_replace_chanctx(struct ieee80211_local *local,
        struct wiphy *wiphy = local->hw.wiphy;
        const struct wiphy_radio *radio;
 
-       if (!curr_ctx || (curr_ctx->replace_state ==
-                         IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
-           !list_empty(&curr_ctx->reserved_links)) {
+       if (!curr_ctx ||
+           curr_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED ||
+           ieee80211_chanctx_num_reserved(local, curr_ctx) != 0) {
                /*
                 * Another link already requested this context for a
                 * reservation. Find another one hoping all links assigned
@@ -1167,7 +1179,7 @@ ieee80211_replace_chanctx(struct ieee80211_local *local,
                            IEEE80211_CHANCTX_REPLACE_NONE)
                                continue;
 
-                       if (!list_empty(&ctx->reserved_links))
+                       if (ieee80211_chanctx_num_reserved(local, ctx) != 0)
                                continue;
 
                        if (ctx->conf.radio_idx >= 0) {
@@ -1185,9 +1197,9 @@ ieee80211_replace_chanctx(struct ieee80211_local *local,
         * If that's true then all available contexts already have reservations
         * and cannot be used.
         */
-       if (!curr_ctx || (curr_ctx->replace_state ==
-                         IEEE80211_CHANCTX_WILL_BE_REPLACED) ||
-           !list_empty(&curr_ctx->reserved_links))
+       if (!curr_ctx ||
+           curr_ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED ||
+           ieee80211_chanctx_num_reserved(local, curr_ctx) != 0)
                return ERR_PTR(-EBUSY);
 
        new_ctx = ieee80211_alloc_chanctx(local, chanreq, mode, -1);
@@ -1267,7 +1279,6 @@ int ieee80211_link_reserve_chanctx(struct ieee80211_link_data *link,
                        return PTR_ERR(new_ctx);
        }
 
-       list_add(&link->reserved_chanctx_list, &new_ctx->reserved_links);
        link->reserved_chanctx = new_ctx;
        link->reserved = *chanreq;
        link->reserved_radar_required = radar_required;
@@ -1381,7 +1392,6 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
        vif_chsw[0].new_ctx = &new_ctx->conf;
        vif_chsw[0].link_conf = link->conf;
 
-       list_del(&link->reserved_chanctx_list);
        link->reserved_chanctx = NULL;
 
        err = drv_switch_vif_chanctx(local, vif_chsw, 1,
@@ -1394,7 +1404,6 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link)
        }
 
        link->radar_required = link->reserved_radar_required;
-       list_move(&link->assigned_chanctx_list, &new_ctx->assigned_links);
        rcu_assign_pointer(link_conf->chanctx_conf, &new_ctx->conf);
 
        if (sdata->vif.type == NL80211_IFTYPE_AP)
@@ -1451,7 +1460,6 @@ ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link)
 
        ieee80211_change_chanctx(local, new_ctx, new_ctx, chanreq);
 
-       list_del(&link->reserved_chanctx_list);
        link->reserved_chanctx = NULL;
 
        err = ieee80211_assign_link_chanctx(link, new_ctx, false);
@@ -1517,8 +1525,10 @@ static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local,
                        goto out;
                }
 
-               list_for_each_entry(link, &ctx->reserved_links,
-                                   reserved_chanctx_list) {
+               for_each_sdata_link(local, link) {
+                       if (link->reserved_chanctx != ctx)
+                               continue;
+
                        if (!ieee80211_link_has_in_place_reservation(link))
                                continue;
 
@@ -1551,7 +1561,7 @@ static int ieee80211_chsw_switch_ctxs(struct ieee80211_local *local)
                if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
                        continue;
 
-               if (!list_empty(&ctx->replace_ctx->assigned_links))
+               if (ieee80211_chanctx_num_assigned(local, ctx) != 0)
                        continue;
 
                ieee80211_del_chanctx(local, ctx->replace_ctx, false);
@@ -1568,7 +1578,7 @@ err:
                if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
                        continue;
 
-               if (!list_empty(&ctx->replace_ctx->assigned_links))
+               if (ieee80211_chanctx_num_assigned(local, ctx) != 0)
                        continue;
 
                ieee80211_del_chanctx(local, ctx, false);
@@ -1619,8 +1629,10 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
                n_reserved = 0;
                n_ready = 0;
 
-               list_for_each_entry(link, &ctx->replace_ctx->assigned_links,
-                                   assigned_chanctx_list) {
+               for_each_sdata_link(local, link) {
+                       if (rcu_access_pointer(link->conf->chanctx_conf) != &ctx->conf)
+                               continue;
+
                        n_assigned++;
                        if (link->reserved_chanctx) {
                                n_reserved++;
@@ -1641,8 +1653,10 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
                }
 
                ctx->conf.radar_enabled = false;
-               list_for_each_entry(link, &ctx->reserved_links,
-                                   reserved_chanctx_list) {
+               for_each_sdata_link(local, link) {
+                       if (link->reserved_chanctx != ctx)
+                               continue;
+
                        if (ieee80211_link_has_in_place_reservation(link) &&
                            !link->reserved_ready)
                                return -EAGAIN;
@@ -1683,8 +1697,10 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
                        goto err;
                }
 
-               list_for_each_entry(link, &ctx->reserved_links,
-                                   reserved_chanctx_list) {
+               for_each_sdata_link(local, link) {
+                       if (link->reserved_chanctx != ctx)
+                               continue;
+
                        if (!ieee80211_link_has_in_place_reservation(link))
                                continue;
 
@@ -1718,7 +1734,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
         * context(s).
         */
        list_for_each_entry(ctx, &local->chanctx_list, list) {
-               struct ieee80211_link_data *link, *link_tmp;
+               struct ieee80211_link_data *link;
 
                if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
                        continue;
@@ -1728,12 +1744,14 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
                        goto err;
                }
 
-               list_for_each_entry(link, &ctx->reserved_links,
-                                   reserved_chanctx_list) {
+               for_each_sdata_link(local, link) {
                        struct ieee80211_sub_if_data *sdata = link->sdata;
                        struct ieee80211_bss_conf *link_conf = link->conf;
                        u64 changed = 0;
 
+                       if (link->reserved_chanctx != ctx)
+                               continue;
+
                        if (!ieee80211_link_has_in_place_reservation(link))
                                continue;
 
@@ -1765,14 +1783,13 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
                ieee80211_recalc_radar_chanctx(local, ctx);
                ieee80211_recalc_chanctx_min_def(local, ctx, NULL, false);
 
-               list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
-                                        reserved_chanctx_list) {
+               for_each_sdata_link(local, link) {
+                       if (link->reserved_chanctx != ctx)
+                               continue;
+
                        if (ieee80211_link_get_chanctx(link) != ctx)
                                continue;
 
-                       list_del(&link->reserved_chanctx_list);
-                       list_move(&link->assigned_chanctx_list,
-                                 &ctx->assigned_links);
                        link->reserved_chanctx = NULL;
 
                        ieee80211_link_chanctx_reservation_complete(link);
@@ -1786,12 +1803,11 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
                 * reservation for originally requested interface has already
                 * succeeded at this point.
                 */
-               list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
-                                        reserved_chanctx_list) {
-                       if (WARN_ON(ieee80211_link_has_in_place_reservation(link)))
+               for_each_sdata_link(local, link) {
+                       if (link->reserved_chanctx != ctx)
                                continue;
 
-                       if (WARN_ON(link->reserved_chanctx != ctx))
+                       if (WARN_ON(ieee80211_link_has_in_place_reservation(link)))
                                continue;
 
                        if (!link->reserved_ready)
@@ -1834,13 +1850,15 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
 
 err:
        list_for_each_entry(ctx, &local->chanctx_list, list) {
-               struct ieee80211_link_data *link, *link_tmp;
+               struct ieee80211_link_data *link;
 
                if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER)
                        continue;
 
-               list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links,
-                                        reserved_chanctx_list) {
+               for_each_sdata_link(local, link) {
+                       if (link->reserved_chanctx != ctx)
+                               continue;
+
                        ieee80211_link_unreserve_chanctx(link);
                        ieee80211_link_chanctx_reservation_complete(link);
                }
@@ -1949,7 +1967,6 @@ int _ieee80211_link_use_channel(struct ieee80211_link_data *link,
                /* remove reservation */
                WARN_ON(link->reserved_chanctx != ctx);
                link->reserved_chanctx = NULL;
-               list_del(&link->reserved_chanctx_list);
        }
 
        if (ret) {
index 72e4f326946fa85d510d0a8206426aeb0f8ccb2d..c94156f209952e297930199669fb8097426b1e7d 100644 (file)
@@ -916,9 +916,6 @@ struct ieee80211_chanctx {
        struct list_head list;
        struct rcu_head rcu_head;
 
-       struct list_head assigned_links;
-       struct list_head reserved_links;
-
        enum ieee80211_chanctx_replace_state replace_state;
        struct ieee80211_chanctx *replace_ctx;
 
@@ -1071,9 +1068,6 @@ struct ieee80211_link_data {
        struct ieee80211_sub_if_data *sdata;
        unsigned int link_id;
 
-       struct list_head assigned_chanctx_list; /* protected by wiphy mutex */
-       struct list_head reserved_chanctx_list; /* protected by wiphy mutex */
-
        /* multicast keys only */
        struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS +
                                        NUM_DEFAULT_MGMT_KEYS +
index 4a19b765ccb69fd250ed9911d0329070a38bd33c..85ed3cbb2e360e3095b3a35d813213052aed7ed7 100644 (file)
@@ -119,8 +119,6 @@ void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
                        ieee80211_color_change_finalize_work);
        wiphy_delayed_work_init(&link->color_collision_detect_work,
                                ieee80211_color_collision_detection_work);
-       INIT_LIST_HEAD(&link->assigned_chanctx_list);
-       INIT_LIST_HEAD(&link->reserved_chanctx_list);
        wiphy_delayed_work_init(&link->dfs_cac_timer_work,
                                ieee80211_dfs_cac_timer_work);
 
index c9931537f9d2d38ec350744c26f74bd76924a8cc..324d84d11cab9b0a3d735fa62846d0fa793916fb 100644 (file)
@@ -4016,23 +4016,23 @@ static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local,
        if (WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED))
                return 0;
 
-       list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list)
-               if (link->reserved_radar_required)
-                       radar_detect |= BIT(link->reserved.oper.width);
-
-       /*
-        * An in-place reservation context should not have any assigned vifs
-        * until it replaces the other context.
-        */
-       WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER &&
-               !list_empty(&ctx->assigned_links));
+       for_each_sdata_link(local, link) {
+               if (rcu_access_pointer(link->conf->chanctx_conf) == &ctx->conf) {
+                       /*
+                        * An in-place reservation context should not have any
+                        * assigned links until it replaces the other context.
+                        */
+                       WARN_ON(ctx->replace_state ==
+                               IEEE80211_CHANCTX_REPLACES_OTHER);
 
-       list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) {
-               if (!link->radar_required)
-                       continue;
+                       if (link->radar_required)
+                               radar_detect |=
+                                       BIT(link->conf->chanreq.oper.width);
+               }
 
-               radar_detect |=
-                       BIT(link->conf->chanreq.oper.width);
+               if (link->reserved_chanctx == ctx &&
+                   link->reserved_radar_required)
+                       radar_detect |= BIT(link->reserved.oper.width);
        }
 
        return radar_detect;