From: Luca Coelho <luca@coelho.fi>
To: Michal Kazior <michal.kazior@tieto.com>
Cc: linux-wireless@vger.kernel.org, johannes@sipsolutions.net
Subject: Re: [PATCH v7 1/5] mac80211: implement multi-vif in-place reservations
Date: Mon, 02 Jun 2014 14:33:20 +0300 [thread overview]
Message-ID: <1401708800.5528.62.camel@dubbel> (raw)
In-Reply-To: <1401348851-26732-2-git-send-email-michal.kazior@tieto.com>
On Thu, 2014-05-29 at 09:34 +0200, Michal Kazior wrote:
> Multi-vif in-place reservations happen when
> it is impossible to allocate more channel contexts
> as indicated by interface combinations.
>
> Such reservations are not finalized until all
> assigned interfaces are ready.
>
> This still doesn't handle all possible cases
> (i.e. degradation of number of channels) properly.
>
> Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
> ---
> diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
> index 3702d64..01379a17 100644
> --- a/net/mac80211/chan.c
> +++ b/net/mac80211/chan.c
[...]
> @@ -898,8 +920,16 @@ int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata)
> list_del(&sdata->reserved_chanctx_list);
> sdata->reserved_chanctx = NULL;
>
> - if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0)
> - ieee80211_free_chanctx(sdata->local, ctx);
> + if (ieee80211_chanctx_refcount(sdata->local, ctx) == 0) {
> + if (ctx->replaces) {
> + WARN_ON(ctx->replaces->replaced_by != ctx);
> + ctx->replaces->replaced_by = NULL;
> + list_del_rcu(&ctx->list);
> + kfree_rcu(ctx, rcu_head);
Couldn't this go into the ieee80211_free_chanctx()?
[...]
> @@ -911,39 +941,71 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
> {
> struct ieee80211_local *local = sdata->local;
> struct ieee80211_chanctx_conf *conf;
> - struct ieee80211_chanctx *new_ctx, *curr_ctx;
> - int ret = 0;
> + struct ieee80211_chanctx *new_ctx, *curr_ctx, *ctx;
>
> - mutex_lock(&local->chanctx_mtx);
> + lockdep_assert_held(&local->chanctx_mtx);
> +
> + if (local->use_chanctx && !local->ops->switch_vif_chanctx)
> + return -ENOTSUPP;
Do we really need to fail here for all reservations (ie. even when it's
not an in-place reservation)?
[...]
> } else {
> - ret = -EBUSY;
> - goto out;
> + if (curr_ctx->replaced_by ||
> + !list_empty(&curr_ctx->reserved_vifs)) {
> + /*
> + * Another vif already requested this context
> + * for an in-place reservation. Find another
If !curr_ctx->replaced_by, then this is not an in-place reservation,
right? the ->reserved_vifs will switch from another context to this one.
The comment is a bit misleading.
> + * one hoping all vifs assigned to it will also
> + * switch soon enough.
> + *
> + * TODO: This needs a little more work as some
> + * cases may fail which could otherwise succeed
> + * provided some channel context juggling was
> + * performed.
> + */
This TODO seems fair enough, but could you provide at least one example
of such case?
> + list_for_each_entry(ctx, &local->chanctx_list,
> + list) {
> + if (ctx->replaced_by)
> + continue;
> +
> + if (ctx->replaces)
> + continue;
> +
> + if (!list_empty(&ctx->reserved_vifs))
> + continue;
> +
> + curr_ctx = ctx;
> + break;
> + }
I'm probably missing something, because I don't get this. Do you just
try to find *any* other existing context and "steal" it? Even if the
other context you find has a completely unrelated chandef?
> + }
> +
> + /*
> + * If that's true then all available contexts are all
> + * in-place reserved already.
> + */
> + if (curr_ctx->replaced_by)
> + return -EBUSY;
What about the reserved_vifs case? You may also get here if
curr_ctx->replaced_by is not true, but curr_ctx->reserved_vifs is not
empty.
[...]
> -int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata,
> - u32 *changed)
> +static int
> +ieee80211_vif_use_reserved_assign(struct ieee80211_sub_if_data *sdata)
> {
> struct ieee80211_local *local = sdata->local;
> - struct ieee80211_chanctx *ctx;
> - struct ieee80211_chanctx *old_ctx;
> - struct ieee80211_chanctx_conf *conf;
> - int ret;
> - u32 tmp_changed = *changed;
> -
> - /* TODO: need to recheck if the chandef is usable etc.? */
> + struct ieee80211_vif_chanctx_switch vif_chsw[1] = {};
> + struct ieee80211_chanctx *old_ctx, *new_ctx;
> + const struct cfg80211_chan_def *chandef;
> + u32 changed = 0;
> + int err;
>
> lockdep_assert_held(&local->mtx);
> + lockdep_assert_held(&local->chanctx_mtx);
>
> - mutex_lock(&local->chanctx_mtx);
> + new_ctx = sdata->reserved_chanctx;
> + old_ctx = ieee80211_vif_get_chanctx(sdata);
>
> - ctx = sdata->reserved_chanctx;
> - if (WARN_ON(!ctx)) {
> - ret = -EINVAL;
> - goto out;
> - }
> + if (WARN_ON(!sdata->reserved_ready))
> + return -EBUSY;
>
> - conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
> - lockdep_is_held(&local->chanctx_mtx));
> - if (!conf) {
> - ret = -EINVAL;
> - goto out;
> + if (WARN_ON(!new_ctx))
> + return -EINVAL;
> +
> + if (WARN_ON(!old_ctx))
> + return -EINVAL;
You already WARN_ON !new_ctx and !old_ctx in
ieee80211_vif_use_reserved_context(). I know it doesn't hurt, but do
you have to double-check here?
> +
> + if (WARN_ON(new_ctx->replaced_by))
> + return -EINVAL;
> +
> + if (WARN_ON(old_ctx->replaced_by && new_ctx->replaces))
> + return -EINVAL;
What if new_ctx is going to replace something else?
[...]
> +static int
> +ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
> +{
> + struct ieee80211_sub_if_data *sdata, *sdata_tmp;
> + struct ieee80211_chanctx *new_ctx = NULL, *ctx, *ctx_tmp;
I prefer if declarations with assignments are in lines of their own, but
maybe it's just me.
> + struct ieee80211_vif_chanctx_switch *vif_chsw = NULL;
> + const struct cfg80211_chan_def *chandef;
> + int i, err, n_ctx = 0, n_vifs = 0;
> +
> + lockdep_assert_held(&local->mtx);
> + lockdep_assert_held(&local->chanctx_mtx);
> +
> + /*
> + * If there are 2 independant pairs of channel contexts performing
Typo, independent.
> + * cross-switch of their vifs this code will still wait until both are
> + * ready even though it could be possible to switch one before the
> + * other is ready.
> + *
> + * For practical reasons and code simplicity just do a single huge
> + * switch.
> + */
> +
> + list_for_each_entry(ctx, &local->chanctx_list, list) {
> + if (!(ctx->replaces && !ctx->replaced_by))
> + continue;
if (!ctx->replaces || ctx->replaced_by) looks more natural to me. (Same
thing for some other cases in this patch).
> +
> + if (!local->use_chanctx)
> + new_ctx = ctx;
> +
> + n_ctx++;
> +
> + list_for_each_entry(sdata, &ctx->replaces->assigned_vifs,
> + assigned_chanctx_list) {
> + if (!sdata->reserved_chanctx) {
> + wiphy_info(local->hw.wiphy,
> + "channel context reservation cannot be finalized because some interfaces aren't switching\n");
> + err = -EBUSY;
> + goto err;
> + }
Hadn't we decided to disconnect the vifs that didn't follow? Can't
remember anymore. :) But now you're just canceling the whole switch?
> +
> + if (!sdata->reserved_ready)
> + return -EAGAIN;
> + }
Shouldn't this be above the previous if? If not everyone switched yet,
can't we give more time for others to join the switch?
> +
> + list_for_each_entry(sdata, &ctx->reserved_vifs,
> + reserved_chanctx_list) {
> + if (!ieee80211_vif_has_in_place_reservation(sdata))
> + continue;
> +
> + if (!sdata->reserved_ready)
> + return -EAGAIN;
> +
> + n_vifs++;
> +
> + if (sdata->reserved_radar_required)
> + ctx->conf.radar_enabled = true;
> + }
> + }
> +
> + if (WARN_ON(n_ctx == 0) ||
> + WARN_ON(n_vifs == 0) ||
> + WARN_ON(n_ctx > 1 && !local->use_chanctx) ||
> + WARN_ON(!new_ctx && !local->use_chanctx)) {
Can this last WARN ever happen? Only if there's no chanctx at all in the
chanctx_list (which should never happen)?
> + err = -EINVAL;
> + goto err;
> + }
> +
> + if (local->use_chanctx) {
> + vif_chsw = kzalloc(sizeof(*vif_chsw) * n_vifs, GFP_KERNEL);
> + if (vif_chsw) {
> + err = -ENOMEM;
> + goto err;
> + }
> +
> + i = 0;
> + list_for_each_entry(ctx, &local->chanctx_list, list) {
> + if (!(ctx->replaces && !ctx->replaced_by))
> + continue;
> +
> + list_for_each_entry(sdata, &ctx->reserved_vifs,
> + reserved_chanctx_list) {
> + if (!ieee80211_vif_has_in_place_reservation(
> + sdata))
> + continue;
> +
> + vif_chsw[i].vif = &sdata->vif;
> + vif_chsw[i].old_ctx = &ctx->replaces->conf;
> + vif_chsw[i].new_ctx = &ctx->conf;
> +
> + i++;
> + }
> + }
> +
> + err = drv_switch_vif_chanctx(local, vif_chsw, n_vifs,
> + CHANCTX_SWMODE_SWAP_CONTEXTS);
> + kfree(vif_chsw);
> +
> + if (err)
> + goto err;
> } else {
> - ret = ieee80211_assign_vif_chanctx(sdata, ctx);
> - if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
> - ieee80211_free_chanctx(local, old_ctx);
> - if (ret) {
> - /* if assign fails refcount stays the same */
> - if (ieee80211_chanctx_refcount(local, ctx) == 0)
> - ieee80211_free_chanctx(local, ctx);
> - goto out;
> + chandef = ieee80211_chanctx_reserved_chandef(local, new_ctx,
> + NULL);
> + if (WARN_ON(!chandef)) {
> + err = -EINVAL;
> + goto err;
> }
>
> - if (sdata->vif.type == NL80211_IFTYPE_AP)
> - __ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
> + local->hw.conf.radar_enabled = new_ctx->conf.radar_enabled;
> + local->_oper_chandef = *chandef;
> + ieee80211_hw_config(local, 0);
> }
>
> - *changed = tmp_changed;
> + i = 0;
> + list_for_each_entry_safe(ctx, ctx_tmp, &local->chanctx_list, list) {
> + if (!(ctx->replaces && !ctx->replaced_by))
> + continue;
>
> - ieee80211_recalc_chanctx_chantype(local, ctx);
> - ieee80211_recalc_smps_chanctx(local, ctx);
> - ieee80211_recalc_radar_chanctx(local, ctx);
> - ieee80211_recalc_chanctx_min_def(local, ctx);
> -out:
> - mutex_unlock(&local->chanctx_mtx);
> - return ret;
> + list_for_each_entry(sdata, &ctx->reserved_vifs,
> + reserved_chanctx_list) {
> + u32 changed = 0;
> +
> + if (!ieee80211_vif_has_in_place_reservation(sdata))
> + continue;
> +
> + rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
> +
> + if (sdata->vif.type == NL80211_IFTYPE_AP)
> + __ieee80211_vif_copy_chanctx_to_vlans(sdata,
> + false);
> +
> + sdata->radar_required = sdata->reserved_radar_required;
> +
> + if (sdata->vif.bss_conf.chandef.width !=
> + sdata->reserved_chandef.width)
> + changed = BSS_CHANGED_BANDWIDTH;
> +
> + sdata->vif.bss_conf.chandef = sdata->reserved_chandef;
> + if (changed)
> + ieee80211_bss_info_change_notify(sdata,
> + changed);
> +
> + ieee80211_recalc_txpower(sdata);
> + }
> +
> + ieee80211_recalc_chanctx_chantype(local, ctx);
> + ieee80211_recalc_smps_chanctx(local, ctx);
> + ieee80211_recalc_radar_chanctx(local, ctx);
> + ieee80211_recalc_chanctx_min_def(local, ctx);
> +
> + list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
> + reserved_chanctx_list) {
> + list_del(&sdata->reserved_chanctx_list);
> + list_move(&sdata->assigned_chanctx_list,
> + &new_ctx->assigned_vifs);
> + sdata->reserved_chanctx = NULL;
> + }
> +
> + list_del_rcu(&ctx->replaces->list);
> + kfree_rcu(ctx->replaces, rcu_head);
> + ctx->replaces = NULL;
> +
> + /*
> + * Some simple reservations depending on the in-place switch
> + * might've been ready before and were deferred. Retry them now
> + * but don't propagate the error up the call stack as the
> + * directly requested reservation has been already handled
> + * successfully at this point.
> + */
> + list_for_each_entry(sdata, &ctx->reserved_vifs,
> + reserved_chanctx_list) {
> + if (WARN_ON(ieee80211_vif_has_in_place_reservation(
> + sdata)))
> + continue;
> +
> + if (!sdata->reserved_ready)
> + continue;
> +
> + err = ieee80211_vif_use_reserved_assign(sdata);
> + if (WARN_ON(err && err != -EAGAIN)) {
Do we really want to WARN on other error cases here? It could be some
kind of -EBUSY or so and just disconnecting would be okay?
> + sdata_info(sdata,
> + "failed to finalize reservation (err=%d)\n",
> + err);
> + ieee80211_vif_unreserve_chanctx(sdata);
> + cfg80211_stop_iface(local->hw.wiphy,
> + &sdata->wdev,
> + GFP_KERNEL);
> + }
> + }
> + }
> +
> + return 0;
> +
> +err:
> + list_for_each_entry(ctx, &local->chanctx_list, list) {
> + if (!(ctx->replaces && !ctx->replaced_by))
> + continue;
> +
> + list_for_each_entry_safe(sdata, sdata_tmp, &ctx->reserved_vifs,
> + reserved_chanctx_list)
> + ieee80211_vif_unreserve_chanctx(sdata);
> + }
> +
> + return err;
> +}
This function is huge, any way to break it down? Or at least add
comments before each block explaining what they do...
> +int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
> +{
> + struct ieee80211_local *local = sdata->local;
> + struct ieee80211_chanctx *new_ctx;
> + struct ieee80211_chanctx *old_ctx;
> + int err;
> +
> + lockdep_assert_held(&local->mtx);
> + lockdep_assert_held(&local->chanctx_mtx);
> +
> + new_ctx = sdata->reserved_chanctx;
> + old_ctx = ieee80211_vif_get_chanctx(sdata);
> +
> + if (WARN_ON(!new_ctx))
> + return -EINVAL;
> +
> + if (WARN_ON(!old_ctx))
> + return -EINVAL;
> +
> + if (WARN_ON(sdata->reserved_ready))
> + return -EINVAL;
> +
> + sdata->reserved_ready = true;
> + if (!(old_ctx->replaced_by && new_ctx->replaces)) {
Isn't !old->ctx->replaced_by enough here? Do you really care if the
new_ctx will replace something else at this point?
> + err = ieee80211_vif_use_reserved_assign(sdata);
> + if (err && err != -EAGAIN)
> + return err;
> + }
> +
> + /*
> + * In-place reservation may need to be finalized now either if:
> + * - sdata is taking part in the swapping itself and is the last one
> + * - sdata has switched with a simple reservation to an existing
> + * context readying the in-place switching old_ctx
> + */
> +
> + if (old_ctx->replaced_by || new_ctx->replaces) {
Same thing here... if new_ctx replaces something *else* shouldn't we use
_assign() instead?
> + err = ieee80211_vif_use_reserved_switch(local);
> + if (err && err != -EAGAIN)
> + return err;
> + }
> +
> + return 0;
> }
[...]
--
Luca.
next prev parent reply other threads:[~2014-06-02 11:33 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-05-29 7:34 [PATCH v7 0/5] cfg/mac80211: implement multi-vif csa Michal Kazior
2014-05-29 7:34 ` [PATCH v7 1/5] mac80211: implement multi-vif in-place reservations Michal Kazior
2014-06-02 11:33 ` Luca Coelho [this message]
2014-06-03 6:15 ` Michal Kazior
2014-06-03 17:10 ` Johannes Berg
2014-06-04 12:12 ` Michal Kazior
2014-06-04 12:38 ` Johannes Berg
2014-05-29 7:34 ` [PATCH v7 2/5] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
2014-05-29 7:34 ` [PATCH v7 3/5] mac80211: use chanctx reservation for AP CSA Michal Kazior
2014-06-03 19:49 ` Johannes Berg
2014-05-29 7:34 ` [PATCH v7 4/5] mac80211: use chanctx reservation for STA CSA Michal Kazior
2014-05-29 7:34 ` [PATCH v7 5/5] cfg80211: remove channel_switch combination check Michal Kazior
2014-06-03 19:51 ` [PATCH v7 0/5] cfg/mac80211: implement multi-vif csa Johannes Berg
2014-06-05 12:56 ` [PATCH v8 " Michal Kazior
2014-06-05 12:56 ` [PATCH v8 1/5] mac80211: implement multi-vif in-place reservations Michal Kazior
2014-06-09 16:27 ` Eliad Peller
2014-06-10 5:16 ` Michal Kazior
2014-06-05 12:56 ` [PATCH v8 2/5] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
2014-06-05 12:56 ` [PATCH v8 3/5] mac80211: use chanctx reservation for AP CSA Michal Kazior
2014-06-05 12:56 ` [PATCH v8 4/5] mac80211: use chanctx reservation for STA CSA Michal Kazior
2014-06-05 12:56 ` [PATCH v8 5/5] cfg80211: remove channel_switch combination check Michal Kazior
2014-06-12 12:54 ` [PATCH v9 0/5] cfg/mac80211: implement multi-vif csa Michal Kazior
2014-06-12 12:54 ` [PATCH v9 1/5] mac80211: implement multi-vif in-place reservations Michal Kazior
2014-06-16 14:35 ` Luca Coelho
2014-06-17 5:52 ` Michal Kazior
2014-06-12 12:54 ` [PATCH v9 2/5] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
2014-06-12 12:54 ` [PATCH v9 3/5] mac80211: use chanctx reservation for AP CSA Michal Kazior
2014-06-12 12:54 ` [PATCH v9 4/5] mac80211: use chanctx reservation for STA CSA Michal Kazior
2014-06-12 12:54 ` [PATCH v9 5/5] cfg80211: remove channel_switch combination check Michal Kazior
2014-06-17 12:58 ` [PATCH v10 0/5] cfg/mac80211: implement multi-vif csa Michal Kazior
2014-06-17 12:58 ` [PATCH v10 1/5] mac80211: implement multi-vif in-place reservations Michal Kazior
2014-06-23 13:03 ` Johannes Berg
2014-06-24 11:55 ` Michal Kazior
2014-06-24 11:59 ` Johannes Berg
2014-06-17 12:58 ` [PATCH v10 2/5] mac80211: make check_combinations() aware of chanctx reservation Michal Kazior
2014-06-17 12:58 ` [PATCH v10 3/5] mac80211: use chanctx reservation for AP CSA Michal Kazior
2014-06-17 12:58 ` [PATCH v10 4/5] mac80211: use chanctx reservation for STA CSA Michal Kazior
2014-06-17 12:58 ` [PATCH v10 5/5] cfg80211: remove channel_switch combination check Michal Kazior
2014-06-23 10:46 ` [PATCH v10 0/5] cfg/mac80211: implement multi-vif csa Luca Coelho
2014-06-23 13:04 ` Johannes Berg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1401708800.5528.62.camel@dubbel \
--to=luca@coelho.fi \
--cc=johannes@sipsolutions.net \
--cc=linux-wireless@vger.kernel.org \
--cc=michal.kazior@tieto.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).