From: chas williams <3chas3@gmail.com>
To: netdev@vger.kernel.org
Subject: [RFC] net: ipv6: hold locks around mrt->mfc6_cache_array[]
Date: Mon, 06 Apr 2015 19:18:50 -0400 [thread overview]
Message-ID: <1428362330.1872.9.camel@gmail.com> (raw)
It appears to me that the locking of the mfc6_cache_array is a little
bit broken. The list heads in this array appear be mainly protected
by the rtnl in most cases but there are a few were this isn't the case.
Regardless, based on the comments at the head of the code, that probably
wasn't the author's intent:
/* We return to original Alan's scheme. Hash table of resolved
entries is changed only in process context and protected
with weak lock mrt_lock. Queue of unresolved entries is protected
with strong spinlock mfc_unres_lock.
In this case data path is free of exclusive locks at all.
*/
setsocketopt() -> ip6mr_mfc_add() -> ip6mr_cache_resolved() -> ip6_mr_foward()
needs some lock since it is going to read the cache array.
ipm4_mfc_add() probably should hold the write lock to prevent races when
adding entries.
mroute_clean_tables() should also probably hold the write lock across
the entire iteration, otherwise readers have a small chance to get a
reference while the entry is being removed.
Comments?
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index f9a3fd3..1210f5c 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -1306,12 +1306,12 @@ static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc,
line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr);
+ write_lock_bh(&mrt_lock);
list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) {
if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
ipv6_addr_equal(&c->mf6c_mcastgrp,
&mfc->mf6cc_mcastgrp.sin6_addr) &&
(parent == -1 || parent == c->mf6c_parent)) {
- write_lock_bh(&mrt_lock);
list_del(&c->list);
write_unlock_bh(&mrt_lock);
@@ -1320,6 +1320,7 @@ static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc,
return 0;
}
}
+ write_unlock_bh(&mrt_lock);
return -ENOENT;
}
@@ -1465,6 +1466,7 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr);
+ write_lock_bh(&mrt_lock);
list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) {
if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
ipv6_addr_equal(&c->mf6c_mcastgrp,
@@ -1476,7 +1478,6 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
}
if (found) {
- write_lock_bh(&mrt_lock);
c->mf6c_parent = mfc->mf6cc_parent;
ip6mr_update_thresholds(mrt, c, ttls);
if (!mrtsock)
@@ -1501,7 +1502,6 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
if (!mrtsock)
c->mfc_flags |= MFC_STATIC;
- write_lock_bh(&mrt_lock);
list_add(&c->list, &mrt->mfc6_cache_array[line]);
write_unlock_bh(&mrt_lock);
@@ -1525,8 +1525,10 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
spin_unlock_bh(&mfc_unres_lock);
if (found) {
+ read_lock(&mrt_lock);
ip6mr_cache_resolve(net, mrt, uc, c);
ip6mr_cache_free(uc);
+ read_unlock(&mrt_lock);
}
mr6_netlink_event(mrt, c, RTM_NEWROUTE);
return 0;
@@ -1554,18 +1556,18 @@ static void mroute_clean_tables(struct mr6_table *mrt)
/*
* Wipe the cache
*/
+ write_lock_bh(&mrt_lock);
for (i = 0; i < MFC6_LINES; i++) {
list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[i], list) {
if (c->mfc_flags & MFC_STATIC)
continue;
- write_lock_bh(&mrt_lock);
list_del(&c->list);
- write_unlock_bh(&mrt_lock);
mr6_netlink_event(mrt, c, RTM_DELROUTE);
ip6mr_cache_free(c);
}
}
+ write_unlock_bh(&mrt_lock);
if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
spin_lock_bh(&mfc_unres_lock);
next reply other threads:[~2015-04-06 23:18 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-04-06 23:18 chas williams [this message]
2015-04-07 22:24 ` [RFC] net: ipv6: hold locks around mrt->mfc6_cache_array[] David Miller
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=1428362330.1872.9.camel@gmail.com \
--to=3chas3@gmail.com \
--cc=netdev@vger.kernel.org \
/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 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.