diff options
author | David S. Miller <davem@davemloft.net> | 2015-01-27 19:59:56 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-01-27 19:59:56 -0500 |
commit | 95f873f2fff96c592c5d863e2a39825bd8bf0500 (patch) | |
tree | 0d2dd664964ba2c701aefea5b4d1e85b481045e1 /net/netlink | |
parent | 8ea65f4a2dfaaf494ef42a16cbf2fea39b07450f (diff) | |
parent | 59343cd7c4809cf7598789e1cd14563780ae4239 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Conflicts:
arch/arm/boot/dts/imx6sx-sdb.dts
net/sched/cls_bpf.c
Two simple sets of overlapping changes.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/af_netlink.c | 24 | ||||
-rw-r--r-- | net/netlink/af_netlink.h | 1 | ||||
-rw-r--r-- | net/netlink/genetlink.c | 18 |
3 files changed, 28 insertions, 15 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index d77b3467b1d4..2197af00673a 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -61,6 +61,7 @@ | |||
61 | #include <linux/rhashtable.h> | 61 | #include <linux/rhashtable.h> |
62 | #include <asm/cacheflush.h> | 62 | #include <asm/cacheflush.h> |
63 | #include <linux/hash.h> | 63 | #include <linux/hash.h> |
64 | #include <linux/genetlink.h> | ||
64 | 65 | ||
65 | #include <net/net_namespace.h> | 66 | #include <net/net_namespace.h> |
66 | #include <net/sock.h> | 67 | #include <net/sock.h> |
@@ -1091,6 +1092,8 @@ static void netlink_remove(struct sock *sk) | |||
1091 | __sk_del_bind_node(sk); | 1092 | __sk_del_bind_node(sk); |
1092 | netlink_update_listeners(sk); | 1093 | netlink_update_listeners(sk); |
1093 | } | 1094 | } |
1095 | if (sk->sk_protocol == NETLINK_GENERIC) | ||
1096 | atomic_inc(&genl_sk_destructing_cnt); | ||
1094 | netlink_table_ungrab(); | 1097 | netlink_table_ungrab(); |
1095 | } | 1098 | } |
1096 | 1099 | ||
@@ -1214,6 +1217,20 @@ static int netlink_release(struct socket *sock) | |||
1214 | * will be purged. | 1217 | * will be purged. |
1215 | */ | 1218 | */ |
1216 | 1219 | ||
1220 | /* must not acquire netlink_table_lock in any way again before unbind | ||
1221 | * and notifying genetlink is done as otherwise it might deadlock | ||
1222 | */ | ||
1223 | if (nlk->netlink_unbind) { | ||
1224 | int i; | ||
1225 | |||
1226 | for (i = 0; i < nlk->ngroups; i++) | ||
1227 | if (test_bit(i, nlk->groups)) | ||
1228 | nlk->netlink_unbind(sock_net(sk), i + 1); | ||
1229 | } | ||
1230 | if (sk->sk_protocol == NETLINK_GENERIC && | ||
1231 | atomic_dec_return(&genl_sk_destructing_cnt) == 0) | ||
1232 | wake_up(&genl_sk_destructing_waitq); | ||
1233 | |||
1217 | sock->sk = NULL; | 1234 | sock->sk = NULL; |
1218 | wake_up_interruptible_all(&nlk->wait); | 1235 | wake_up_interruptible_all(&nlk->wait); |
1219 | 1236 | ||
@@ -1249,13 +1266,6 @@ static int netlink_release(struct socket *sock) | |||
1249 | netlink_table_ungrab(); | 1266 | netlink_table_ungrab(); |
1250 | } | 1267 | } |
1251 | 1268 | ||
1252 | if (nlk->netlink_unbind) { | ||
1253 | int i; | ||
1254 | |||
1255 | for (i = 0; i < nlk->ngroups; i++) | ||
1256 | if (test_bit(i, nlk->groups)) | ||
1257 | nlk->netlink_unbind(sock_net(sk), i + 1); | ||
1258 | } | ||
1259 | kfree(nlk->groups); | 1269 | kfree(nlk->groups); |
1260 | nlk->groups = NULL; | 1270 | nlk->groups = NULL; |
1261 | 1271 | ||
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h index 7518375782f5..89008405d6b4 100644 --- a/net/netlink/af_netlink.h +++ b/net/netlink/af_netlink.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define _AF_NETLINK_H | 2 | #define _AF_NETLINK_H |
3 | 3 | ||
4 | #include <linux/rhashtable.h> | 4 | #include <linux/rhashtable.h> |
5 | #include <linux/atomic.h> | ||
5 | #include <net/sock.h> | 6 | #include <net/sock.h> |
6 | 7 | ||
7 | #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) | 8 | #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) |
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index f52a7d5734cd..2ed5f964772e 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
@@ -23,6 +23,9 @@ | |||
23 | static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */ | 23 | static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */ |
24 | static DECLARE_RWSEM(cb_lock); | 24 | static DECLARE_RWSEM(cb_lock); |
25 | 25 | ||
26 | atomic_t genl_sk_destructing_cnt = ATOMIC_INIT(0); | ||
27 | DECLARE_WAIT_QUEUE_HEAD(genl_sk_destructing_waitq); | ||
28 | |||
26 | void genl_lock(void) | 29 | void genl_lock(void) |
27 | { | 30 | { |
28 | mutex_lock(&genl_mutex); | 31 | mutex_lock(&genl_mutex); |
@@ -435,15 +438,18 @@ int genl_unregister_family(struct genl_family *family) | |||
435 | 438 | ||
436 | genl_lock_all(); | 439 | genl_lock_all(); |
437 | 440 | ||
438 | genl_unregister_mc_groups(family); | ||
439 | |||
440 | list_for_each_entry(rc, genl_family_chain(family->id), family_list) { | 441 | list_for_each_entry(rc, genl_family_chain(family->id), family_list) { |
441 | if (family->id != rc->id || strcmp(rc->name, family->name)) | 442 | if (family->id != rc->id || strcmp(rc->name, family->name)) |
442 | continue; | 443 | continue; |
443 | 444 | ||
445 | genl_unregister_mc_groups(family); | ||
446 | |||
444 | list_del(&rc->family_list); | 447 | list_del(&rc->family_list); |
445 | family->n_ops = 0; | 448 | family->n_ops = 0; |
446 | genl_unlock_all(); | 449 | up_write(&cb_lock); |
450 | wait_event(genl_sk_destructing_waitq, | ||
451 | atomic_read(&genl_sk_destructing_cnt) == 0); | ||
452 | genl_unlock(); | ||
447 | 453 | ||
448 | kfree(family->attrbuf); | 454 | kfree(family->attrbuf); |
449 | genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0); | 455 | genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0); |
@@ -987,7 +993,7 @@ static struct genl_multicast_group genl_ctrl_groups[] = { | |||
987 | 993 | ||
988 | static int genl_bind(struct net *net, int group) | 994 | static int genl_bind(struct net *net, int group) |
989 | { | 995 | { |
990 | int i, err = 0; | 996 | int i, err = -ENOENT; |
991 | 997 | ||
992 | down_read(&cb_lock); | 998 | down_read(&cb_lock); |
993 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { | 999 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { |
@@ -1016,7 +1022,6 @@ static int genl_bind(struct net *net, int group) | |||
1016 | static void genl_unbind(struct net *net, int group) | 1022 | static void genl_unbind(struct net *net, int group) |
1017 | { | 1023 | { |
1018 | int i; | 1024 | int i; |
1019 | bool found = false; | ||
1020 | 1025 | ||
1021 | down_read(&cb_lock); | 1026 | down_read(&cb_lock); |
1022 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { | 1027 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { |
@@ -1029,14 +1034,11 @@ static void genl_unbind(struct net *net, int group) | |||
1029 | 1034 | ||
1030 | if (f->mcast_unbind) | 1035 | if (f->mcast_unbind) |
1031 | f->mcast_unbind(net, fam_grp); | 1036 | f->mcast_unbind(net, fam_grp); |
1032 | found = true; | ||
1033 | break; | 1037 | break; |
1034 | } | 1038 | } |
1035 | } | 1039 | } |
1036 | } | 1040 | } |
1037 | up_read(&cb_lock); | 1041 | up_read(&cb_lock); |
1038 | |||
1039 | WARN_ON(!found); | ||
1040 | } | 1042 | } |
1041 | 1043 | ||
1042 | static int __net_init genl_pernet_init(struct net *net) | 1044 | static int __net_init genl_pernet_init(struct net *net) |