Commit aaa016cc authored by Johannes Berg's avatar Johannes Berg

mac80211: rewrite remain-on-channel logic

Jouni found a bug in the remain-on-channel logic: when a short item
is queued, a long item is combined with it extending the original
one, and then the long item is deleted, the timeout doesn't go back
to the short one, and the short item ends up taking a long time. In
this case, this showed as blocking scan when running two test cases
back to back - the scan from the second was delayed even though all
the remain-on-channel items should long have been gone.

Fixing this with the current data structures turns out to be a bit
complicated, we just remove the long item from the dependents list
right now and don't recalculate the timeouts.

There's a somewhat similar bug where we delete the short item and
all the dependents go with it; to fix this we'd have to move them
from the dependents to the real list.

Instead of trying to do that, rewrite the code to not have all this
complexity in the data structures: use a single list and allow more
than one entry in it being marked as started. This makes the code a
bit more complex, the worker needs to understand that it might need
to just remove one of the started items, while keeping the device
off-channel, but that's not more complicated than the nested data
structures.

This then fixes both issues described, and makes it easier to also
limit the overall off-channel time when combining.

TODO: as before, with hardware remain-on-channel, deleting an item
after combining results in cancelling them all - we can keep track
of the time elapsed and only cancel after that to fix this.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 661ef475
...@@ -325,19 +325,15 @@ struct mesh_preq_queue { ...@@ -325,19 +325,15 @@ struct mesh_preq_queue {
struct ieee80211_roc_work { struct ieee80211_roc_work {
struct list_head list; struct list_head list;
struct list_head dependents;
struct delayed_work work;
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct ieee80211_channel *chan; struct ieee80211_channel *chan;
bool started, abort, hw_begun, notified; bool started, abort, hw_begun, notified;
bool to_be_freed;
bool on_channel; bool on_channel;
unsigned long hw_start_time; unsigned long start_time;
u32 duration, req_duration; u32 duration, req_duration;
struct sk_buff *frame; struct sk_buff *frame;
...@@ -1335,6 +1331,7 @@ struct ieee80211_local { ...@@ -1335,6 +1331,7 @@ struct ieee80211_local {
/* /*
* Remain-on-channel support * Remain-on-channel support
*/ */
struct delayed_work roc_work;
struct list_head roc_list; struct list_head roc_list;
struct work_struct hw_roc_start, hw_roc_done; struct work_struct hw_roc_start, hw_roc_done;
unsigned long hw_roc_start_time; unsigned long hw_roc_start_time;
......
...@@ -1149,6 +1149,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) ...@@ -1149,6 +1149,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
rtnl_unlock(); rtnl_unlock();
cancel_delayed_work_sync(&local->roc_work);
cancel_work_sync(&local->restart_work); cancel_work_sync(&local->restart_work);
cancel_work_sync(&local->reconfig_filter); cancel_work_sync(&local->reconfig_filter);
cancel_work_sync(&local->tdls_chsw_work); cancel_work_sync(&local->tdls_chsw_work);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment