aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlink/af_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/netlink/af_netlink.c')
-rw-r--r--net/netlink/af_netlink.c28
1 files changed, 19 insertions, 9 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 84ea76ca3f1f..75532efa51cd 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>
@@ -1095,6 +1096,8 @@ static void netlink_remove(struct sock *sk)
1095 __sk_del_bind_node(sk); 1096 __sk_del_bind_node(sk);
1096 netlink_update_listeners(sk); 1097 netlink_update_listeners(sk);
1097 } 1098 }
1099 if (sk->sk_protocol == NETLINK_GENERIC)
1100 atomic_inc(&genl_sk_destructing_cnt);
1098 netlink_table_ungrab(); 1101 netlink_table_ungrab();
1099} 1102}
1100 1103
@@ -1211,6 +1214,20 @@ static int netlink_release(struct socket *sock)
1211 * will be purged. 1214 * will be purged.
1212 */ 1215 */
1213 1216
1217 /* must not acquire netlink_table_lock in any way again before unbind
1218 * and notifying genetlink is done as otherwise it might deadlock
1219 */
1220 if (nlk->netlink_unbind) {
1221 int i;
1222
1223 for (i = 0; i < nlk->ngroups; i++)
1224 if (test_bit(i, nlk->groups))
1225 nlk->netlink_unbind(sock_net(sk), i + 1);
1226 }
1227 if (sk->sk_protocol == NETLINK_GENERIC &&
1228 atomic_dec_return(&genl_sk_destructing_cnt) == 0)
1229 wake_up(&genl_sk_destructing_waitq);
1230
1214 sock->sk = NULL; 1231 sock->sk = NULL;
1215 wake_up_interruptible_all(&nlk->wait); 1232 wake_up_interruptible_all(&nlk->wait);
1216 1233
@@ -1246,13 +1263,6 @@ static int netlink_release(struct socket *sock)
1246 netlink_table_ungrab(); 1263 netlink_table_ungrab();
1247 } 1264 }
1248 1265
1249 if (nlk->netlink_unbind) {
1250 int i;
1251
1252 for (i = 0; i < nlk->ngroups; i++)
1253 if (test_bit(i, nlk->groups))
1254 nlk->netlink_unbind(sock_net(sk), i + 1);
1255 }
1256 kfree(nlk->groups); 1266 kfree(nlk->groups);
1257 nlk->groups = NULL; 1267 nlk->groups = NULL;
1258 1268
@@ -1428,7 +1438,7 @@ static void netlink_undo_bind(int group, long unsigned int groups,
1428 1438
1429 for (undo = 0; undo < group; undo++) 1439 for (undo = 0; undo < group; undo++)
1430 if (test_bit(undo, &groups)) 1440 if (test_bit(undo, &groups))
1431 nlk->netlink_unbind(sock_net(sk), undo); 1441 nlk->netlink_unbind(sock_net(sk), undo + 1);
1432} 1442}
1433 1443
1434static int netlink_bind(struct socket *sock, struct sockaddr *addr, 1444static int netlink_bind(struct socket *sock, struct sockaddr *addr,
@@ -1466,7 +1476,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
1466 for (group = 0; group < nlk->ngroups; group++) { 1476 for (group = 0; group < nlk->ngroups; group++) {
1467 if (!test_bit(group, &groups)) 1477 if (!test_bit(group, &groups))
1468 continue; 1478 continue;
1469 err = nlk->netlink_bind(net, group); 1479 err = nlk->netlink_bind(net, group + 1);
1470 if (!err) 1480 if (!err)
1471 continue; 1481 continue;
1472 netlink_undo_bind(group, groups, sk); 1482 netlink_undo_bind(group, groups, sk);