* [PATCH] mac80211: fix and simplify mesh locking
@ 2011-05-14 9:00 Johannes Berg
2011-05-14 9:20 ` Johannes Berg
0 siblings, 1 reply; 7+ messages in thread
From: Johannes Berg @ 2011-05-14 9:00 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless, Javier Cardona
From: Johannes Berg <johannes.berg@intel.com>
The locking in mesh_{mpath,mpp}_table_grow not only
has an rcu_read_unlock() missing, it's also racy
(though really only technically since it's invoked
from a single function only) since it obtains the
new size of the table without any locking, so two
invocations of the function could attempt the same
resize.
Additionally, it uses synchronize_rcu() which is
rather expensive and can be avoided trivially here.
Modify the functions to only use the table lock
and use call_rcu() instead of synchronize_rcu().
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/mesh.h | 3 +++
net/mac80211/mesh_pathtbl.c | 44 ++++++++++++++++++++++----------------------
2 files changed, 25 insertions(+), 22 deletions(-)
--- a/net/mac80211/mesh_pathtbl.c 2011-05-14 10:47:15.000000000 +0200
+++ b/net/mac80211/mesh_pathtbl.c 2011-05-14 10:55:42.000000000 +0200
@@ -370,52 +370,52 @@ err_path_alloc:
return err;
}
+static void mesh_table_free_rcu(struct rcu_head *rcu)
+{
+ struct mesh_table *tbl = container_of(rcu, struct mesh_table, rcu_head);
+
+ mesh_table_free(tbl, false);
+}
+
void mesh_mpath_table_grow(void)
{
struct mesh_table *oldtbl, *newtbl;
- rcu_read_lock();
- newtbl = mesh_table_alloc(rcu_dereference(mesh_paths)->size_order + 1);
- if (!newtbl)
- return;
write_lock_bh(&pathtbl_resize_lock);
+ newtbl = mesh_table_alloc(mesh_paths->size_order + 1);
+ if (!newtbl)
+ goto out;
oldtbl = mesh_paths;
if (mesh_table_grow(mesh_paths, newtbl) < 0) {
- rcu_read_unlock();
__mesh_table_free(newtbl);
- write_unlock_bh(&pathtbl_resize_lock);
- return;
+ goto out;
}
- rcu_read_unlock();
rcu_assign_pointer(mesh_paths, newtbl);
- write_unlock_bh(&pathtbl_resize_lock);
- synchronize_rcu();
- mesh_table_free(oldtbl, false);
+ call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu);
+
+ out:
+ write_unlock_bh(&pathtbl_resize_lock);
}
void mesh_mpp_table_grow(void)
{
struct mesh_table *oldtbl, *newtbl;
- rcu_read_lock();
- newtbl = mesh_table_alloc(rcu_dereference(mpp_paths)->size_order + 1);
- if (!newtbl)
- return;
write_lock_bh(&pathtbl_resize_lock);
+ newtbl = mesh_table_alloc(mpp_paths->size_order + 1);
+ if (!newtbl)
+ goto out;
oldtbl = mpp_paths;
if (mesh_table_grow(mpp_paths, newtbl) < 0) {
- rcu_read_unlock();
__mesh_table_free(newtbl);
- write_unlock_bh(&pathtbl_resize_lock);
- return;
+ goto out;
}
- rcu_read_unlock();
rcu_assign_pointer(mpp_paths, newtbl);
- write_unlock_bh(&pathtbl_resize_lock);
+ call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu);
- synchronize_rcu();
- mesh_table_free(oldtbl, false);
+ out:
+ write_unlock_bh(&pathtbl_resize_lock);
}
int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
--- a/net/mac80211/mesh.h 2011-05-14 10:52:14.000000000 +0200
+++ b/net/mac80211/mesh.h 2011-05-14 10:52:35.000000000 +0200
@@ -120,6 +120,7 @@ struct mesh_path {
* buckets
* @mean_chain_len: maximum average length for the hash buckets' list, if it is
* reached, the table will grow
+ * rcu_head: RCU head to free the table
*/
struct mesh_table {
/* Number of buckets will be 2^N */
@@ -132,6 +133,8 @@ struct mesh_table {
int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
int size_order;
int mean_chain_len;
+
+ struct rcu_head rcu_head;
};
/* Recent multicast cache */
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] mac80211: fix and simplify mesh locking
2011-05-14 9:00 [PATCH] mac80211: fix and simplify mesh locking Johannes Berg
@ 2011-05-14 9:20 ` Johannes Berg
2011-05-17 23:05 ` Javier Cardona
0 siblings, 1 reply; 7+ messages in thread
From: Johannes Berg @ 2011-05-14 9:20 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless, Javier Cardona
On Sat, 2011-05-14 at 11:00 +0200, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> The locking in mesh_{mpath,mpp}_table_grow not only
> has an rcu_read_unlock() missing, it's also racy
> (though really only technically since it's invoked
> from a single function only) since it obtains the
> new size of the table without any locking, so two
> invocations of the function could attempt the same
> resize.
Actually, it _can_ happen, if you have multiple mesh interfaces.
johannes
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] mac80211: fix and simplify mesh locking
2011-05-14 9:20 ` Johannes Berg
@ 2011-05-17 23:05 ` Javier Cardona
2011-05-17 23:13 ` [PATCH] mac80211: Don't sleep when growing the mesh path Javier Cardona
2011-05-18 22:45 ` [PATCH] mac80211: fix and simplify mesh locking Johannes Berg
0 siblings, 2 replies; 7+ messages in thread
From: Javier Cardona @ 2011-05-17 23:05 UTC (permalink / raw)
To: Johannes Berg; +Cc: John W. Linville, linux-wireless
On Sat, May 14, 2011 at 2:20 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Sat, 2011-05-14 at 11:00 +0200, Johannes Berg wrote:
>> From: Johannes Berg <johannes.berg@intel.com>
>>
>> The locking in mesh_{mpath,mpp}_table_grow not only
>> has an rcu_read_unlock() missing, it's also racy
>> (though really only technically since it's invoked
>> from a single function only) since it obtains the
>> new size of the table without any locking, so two
>> invocations of the function could attempt the same
>> resize.
>
> Actually, it _can_ happen, if you have multiple mesh interfaces.
I'm seeing this after trying your patch, probably because the
allocations mesh_table_alloc() can block. In the past I had tried to
allocate the table before entering the critical section. If that is
not possible for the race condition you mention, then I guess we'll
have to make those allocations GFP_ATOMIC?
363.767523] BUG: scheduling while atomic: kworker/u:2/621/0x10000200
[ 363.768239] 3 locks held by kworker/u:2/621:
[ 363.768516] #0: (name){.+.+.+}, at: [<c10429e7>]
process_one_work+0x17c/0x31d
[ 363.769605] #1: ((&sdata->work)){+.+.+.}, at: [<c10429e7>]
process_one_work+0x17c/0x31d
[ 363.770149] #2: (pathtbl_resize_lock){++.-+.}, at: [<c8fb01ce>]
mesh_mpath_table_grow+0xf/0x5c [mac80211]
[ 363.771122] Modules linked in: mac80211_hwsim mac80211
[ 363.771824] Pid: 621, comm: kworker/u:2 Not tainted 2.6.39-rc7-wl+ #399
[ 363.772304] Call Trace:
[ 363.772611] [<c8faf69f>] ? mesh_table_alloc+0x25/0xc2 [mac80211]
[ 363.772969] [<c102c049>] __schedule_bug+0x5e/0x65
[ 363.773350] [<c14672af>] schedule+0x68/0x699
[ 363.773608] [<c1058328>] ? __lock_acquire+0xab3/0xb59
[ 363.773900] [<c105694e>] ? valid_state+0x1a/0x13d
[ 363.774244] [<c1056c10>] ? mark_lock+0x19f/0x1d9
[ 363.774527] [<c105720b>] ? check_usage_forwards+0x68/0x68
[ 363.774873] [<c1056c8d>] ? mark_held_locks+0x43/0x5b
[ 363.775303] [<c8faf69f>] ? mesh_table_alloc+0x25/0xc2 [mac80211]
[ 363.775654] [<c102e544>] __cond_resched+0x16/0x26
[ 363.775918] [<c1467a92>] _cond_resched+0x1d/0x28
Javier
--
Javier Cardona
cozybit Inc.
http://www.cozybit.com
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH] mac80211: Don't sleep when growing the mesh path
2011-05-17 23:05 ` Javier Cardona
@ 2011-05-17 23:13 ` Javier Cardona
2011-05-18 22:45 ` [PATCH] mac80211: fix and simplify mesh locking Johannes Berg
1 sibling, 0 replies; 7+ messages in thread
From: Javier Cardona @ 2011-05-17 23:13 UTC (permalink / raw)
To: John W. Linville
Cc: Javier Cardona, Thomas Pedersen, devel, Johannes Berg,
linux-wireless, jlopex
After commit 1928ecab620907a0953f811316d05f367f3f4dba (mac80211: fix and
simplify mesh locking) mesh table allocation is performed with the
pathtbl_resize_lock taken. Under those conditions one should not sleep.
This patch makes the allocations GFP_ATOMIC to prevent that.
Signed-off-by: Javier Cardona <javier@cozybit.com>
---
net/mac80211/mesh_pathtbl.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 6abe25d..0d2faac 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -76,12 +76,12 @@ static struct mesh_table *mesh_table_alloc(int size_order)
int i;
struct mesh_table *newtbl;
- newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL);
+ newtbl = kmalloc(sizeof(struct mesh_table), GFP_ATOMIC);
if (!newtbl)
return NULL;
newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) *
- (1 << size_order), GFP_KERNEL);
+ (1 << size_order), GFP_ATOMIC);
if (!newtbl->hash_buckets) {
kfree(newtbl);
@@ -89,7 +89,7 @@ static struct mesh_table *mesh_table_alloc(int size_order)
}
newtbl->hashwlock = kmalloc(sizeof(spinlock_t) *
- (1 << size_order), GFP_KERNEL);
+ (1 << size_order), GFP_ATOMIC);
if (!newtbl->hashwlock) {
kfree(newtbl->hash_buckets);
kfree(newtbl);
--
1.7.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] mac80211: fix and simplify mesh locking
2011-05-17 23:05 ` Javier Cardona
2011-05-17 23:13 ` [PATCH] mac80211: Don't sleep when growing the mesh path Javier Cardona
@ 2011-05-18 22:45 ` Johannes Berg
2011-05-19 1:40 ` Javier Cardona
1 sibling, 1 reply; 7+ messages in thread
From: Johannes Berg @ 2011-05-18 22:45 UTC (permalink / raw)
To: Javier Cardona; +Cc: John W. Linville, linux-wireless
On Tue, 2011-05-17 at 16:05 -0700, Javier Cardona wrote:
> I'm seeing this after trying your patch, probably because the
> allocations mesh_table_alloc() can block. In the past I had tried to
> allocate the table before entering the critical section. If that is
> not possible for the race condition you mention, then I guess we'll
> have to make those allocations GFP_ATOMIC?
Err, now I'm confused, how could the code have done non-atomic
allocations while under rcu_read_lock()? I guess there was just no
verification there?
johannes
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] mac80211: fix and simplify mesh locking
2011-05-18 22:45 ` [PATCH] mac80211: fix and simplify mesh locking Johannes Berg
@ 2011-05-19 1:40 ` Javier Cardona
2011-05-19 4:14 ` Johannes Berg
0 siblings, 1 reply; 7+ messages in thread
From: Javier Cardona @ 2011-05-19 1:40 UTC (permalink / raw)
To: Johannes Berg; +Cc: John W. Linville, linux-wireless
On Wed, May 18, 2011 at 3:45 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Tue, 2011-05-17 at 16:05 -0700, Javier Cardona wrote:
>
>> I'm seeing this after trying your patch, probably because the
>> allocations mesh_table_alloc() can block. In the past I had tried to
>> allocate the table before entering the critical section. If that is
>> not possible for the race condition you mention, then I guess we'll
>> have to make those allocations GFP_ATOMIC?
>
> Err, now I'm confused, how could the code have done non-atomic
> allocations while under rcu_read_lock()? I guess there was just no
> verification there?
I'm not sure. I can tell you that the bug message is only triggered
after your patch was applied, same .config.
Maybe i have an rcu configuration that does not check that.
Is making the allocations atomic an acceptable solution?
Javier
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] mac80211: fix and simplify mesh locking
2011-05-19 1:40 ` Javier Cardona
@ 2011-05-19 4:14 ` Johannes Berg
0 siblings, 0 replies; 7+ messages in thread
From: Johannes Berg @ 2011-05-19 4:14 UTC (permalink / raw)
To: Javier Cardona; +Cc: John W. Linville, linux-wireless
On Wed, 18 May 2011 18:40:33 -0700, Javier Cardona wrote:
>>> I'm seeing this after trying your patch, probably because the
>>> allocations mesh_table_alloc() can block. In the past I had tried
>>> to
>>> allocate the table before entering the critical section. If that
>>> is
>>> not possible for the race condition you mention, then I guess
>>> we'll
>>> have to make those allocations GFP_ATOMIC?
>>
>> Err, now I'm confused, how could the code have done non-atomic
>> allocations while under rcu_read_lock()? I guess there was just no
>> verification there?
>
> I'm not sure. I can tell you that the bug message is only triggered
> after your patch was applied, same .config.
> Maybe i have an rcu configuration that does not check that.
>
> Is making the allocations atomic an acceptable solution?
It looks like it's the only solution :-)
Anyway they should've been atomic even before already, not sure why RCU
didn't complain but it was definitely not right to do GFP_KERNEL
allocations under RCU lock, but now that I think about it ISTR that
whether it warns or not might depend on the RCU implementation you
selected in the config.
johannes
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2011-05-19 4:14 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-14 9:00 [PATCH] mac80211: fix and simplify mesh locking Johannes Berg
2011-05-14 9:20 ` Johannes Berg
2011-05-17 23:05 ` Javier Cardona
2011-05-17 23:13 ` [PATCH] mac80211: Don't sleep when growing the mesh path Javier Cardona
2011-05-18 22:45 ` [PATCH] mac80211: fix and simplify mesh locking Johannes Berg
2011-05-19 1:40 ` Javier Cardona
2011-05-19 4:14 ` Johannes Berg
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.