Hey Collen, Luis, On Sun, Mar 16, 2014 at 9:04 PM, Colleen T <colleen@xxxxxxxxxxx> wrote: > On Sat, Mar 15, 2014 at 9:42 PM, Luis R. Rodriguez > <mcgrof@xxxxxxxxxxxxxxxx> wrote: >> On Sat, Mar 15, 2014 at 8:59 AM, Janusz Dziedzic >> <janusz.dziedzic@xxxxxxxxx> wrote: >>> 2014-03-15 2:03 GMT+01:00 Luis R. Rodriguez <mcgrof@xxxxxxxxxxxxxxxx>: >>>> On Fri, Mar 14, 2014 at 3:12 PM, Colleen T <colleen@xxxxxxxxxxx> wrote: >>>>> I'm on mac80211-next/master, sha is >>>>> 5a970df8990d173e7e4092952f2e3da1de69b27d >>>> >>>> I tried to reproduce by just merging the fixes in question onto Linus' >>>> tree and using radios=3 but no go. Can you provide the full kernel >>>> log, I'm particularly interested in what happened before. The >>>> COUNTRY=US on debian, which I believe you're on, should just trigger a >>>> regulatory domain setting to US upon initialization. Depending on how >>>> Debian does it this could either trigger as a module parameter or as a >>>> userspace event *after* the world regdom get set. > > I'm attaching a full kernel log that shows the warning being > triggered. You are correct, I'm on debian. In the attached case I > ran: > $ modprobe mac80211_hwsim radios=4 > I pulled the fixes onto Linus' tree and I end up with the same result. > Seems I might have found the culprit - reg_todo is called while the request to CRDA is in flight and the patch in question causes the already-in-process user-request to be handled again. Since it's the same regdomain as the last request (it's the last request itself), we get this: treatment = __reg_process_hint_user(user_request); if (treatment == REG_REQ_IGNORE || treatment == REG_REQ_ALREADY_SET) { kfree(user_request); <------ return treatment; } Can you try adding the attached patch? It just replaced relevant kfree-s with a function that avoids freeing the last request. Also, in the current scheme of things, CRDA might be called twice for the same request in some corner cases, but that's not a problem, since reg_is_valid_request() will block the second set_regdom(). Regards, Arik
From c05c4e5eefc56a1dd1d74d7326a599deb44c6844 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov <arik@xxxxxxxxxx> Date: Wed, 9 Apr 2014 19:24:16 +0300 Subject: [PATCH] cfg80211: avoid freeing last_request while in flight Avoid freeing the last request while it is being processed. This can happen in some cases if reg_work is kicked for some reason while the currently pending request is in flight. Signed-off-by: Arik Nemtsov <arik@xxxxxxxxxx> --- net/wireless/reg.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index ba04c63..bad094b 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -240,7 +240,13 @@ static char user_alpha2[2]; module_param(ieee80211_regdom, charp, 0444); MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); -static void reg_free_request(struct regulatory_request *lr) +static void reg_free_request(struct regulatory_request *request) +{ + if (request != get_last_request()) + kfree(request); +} + +static void reg_free_last_request(struct regulatory_request *lr) { if (lr != &core_request_world && lr) kfree_rcu(lr, rcu_head); @@ -254,7 +260,7 @@ static void reg_update_last_request(struct regulatory_request *request) if (lr == request) return; - reg_free_request(lr); + reg_free_last_request(lr); rcu_assign_pointer(last_request, request); } @@ -1616,7 +1622,7 @@ reg_process_hint_user(struct regulatory_request *user_request) treatment = __reg_process_hint_user(user_request); if (treatment == REG_REQ_IGNORE || treatment == REG_REQ_ALREADY_SET) { - kfree(user_request); + reg_free_request(user_request); return treatment; } @@ -1676,14 +1682,14 @@ reg_process_hint_driver(struct wiphy *wiphy, case REG_REQ_OK: break; case REG_REQ_IGNORE: - kfree(driver_request); + reg_free_request(driver_request); return treatment; case REG_REQ_INTERSECT: /* fall through */ case REG_REQ_ALREADY_SET: regd = reg_copy_regd(get_cfg80211_regdom()); if (IS_ERR(regd)) { - kfree(driver_request); + reg_free_request(driver_request); return REG_REQ_IGNORE; } rcu_assign_pointer(wiphy->regd, regd); @@ -1777,10 +1783,10 @@ reg_process_hint_country_ie(struct wiphy *wiphy, case REG_REQ_IGNORE: /* fall through */ case REG_REQ_ALREADY_SET: - kfree(country_ie_request); + reg_free_request(country_ie_request); return treatment; case REG_REQ_INTERSECT: - kfree(country_ie_request); + reg_free_request(country_ie_request); /* * This doesn't happen yet, not sure we * ever want to support it for this case. @@ -1841,7 +1847,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) return; out_free: - kfree(reg_request); + reg_free_request(reg_request); } /* -- 1.8.1.2