diff options
author | Patrick McHardy <kaber@trash.net> | 2007-04-20 17:14:21 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 01:29:03 -0400 |
commit | af65bdfce98d7965fbe93a48b8128444a2eea024 (patch) | |
tree | e6ac5ff82a0d5067213135cdf049b912b02e824d /net/netlink/af_netlink.c | |
parent | b076deb8498e26c9aa2f44046fe5e9936ae2fb5a (diff) |
[NETLINK]: Switch cb_lock spinlock to mutex and allow to override it
Switch cb_lock to mutex and allow netlink kernel users to override it
with a subsystem specific mutex for consistent locking in dump callbacks.
All netlink_dump_start users have been audited not to rely on any
side-effects of the previously used spinlock.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink/af_netlink.c')
-rw-r--r-- | net/netlink/af_netlink.c | 38 |
1 files changed, 23 insertions, 15 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 2cbf1682f63d..ec16c9b7b3bd 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <linux/types.h> | 56 | #include <linux/types.h> |
57 | #include <linux/audit.h> | 57 | #include <linux/audit.h> |
58 | #include <linux/selinux.h> | 58 | #include <linux/selinux.h> |
59 | #include <linux/mutex.h> | ||
59 | 60 | ||
60 | #include <net/sock.h> | 61 | #include <net/sock.h> |
61 | #include <net/scm.h> | 62 | #include <net/scm.h> |
@@ -76,7 +77,8 @@ struct netlink_sock { | |||
76 | unsigned long state; | 77 | unsigned long state; |
77 | wait_queue_head_t wait; | 78 | wait_queue_head_t wait; |
78 | struct netlink_callback *cb; | 79 | struct netlink_callback *cb; |
79 | spinlock_t cb_lock; | 80 | struct mutex *cb_mutex; |
81 | struct mutex cb_def_mutex; | ||
80 | void (*data_ready)(struct sock *sk, int bytes); | 82 | void (*data_ready)(struct sock *sk, int bytes); |
81 | struct module *module; | 83 | struct module *module; |
82 | }; | 84 | }; |
@@ -108,6 +110,7 @@ struct netlink_table { | |||
108 | unsigned long *listeners; | 110 | unsigned long *listeners; |
109 | unsigned int nl_nonroot; | 111 | unsigned int nl_nonroot; |
110 | unsigned int groups; | 112 | unsigned int groups; |
113 | struct mutex *cb_mutex; | ||
111 | struct module *module; | 114 | struct module *module; |
112 | int registered; | 115 | int registered; |
113 | }; | 116 | }; |
@@ -370,7 +373,8 @@ static struct proto netlink_proto = { | |||
370 | .obj_size = sizeof(struct netlink_sock), | 373 | .obj_size = sizeof(struct netlink_sock), |
371 | }; | 374 | }; |
372 | 375 | ||
373 | static int __netlink_create(struct socket *sock, int protocol) | 376 | static int __netlink_create(struct socket *sock, struct mutex *cb_mutex, |
377 | int protocol) | ||
374 | { | 378 | { |
375 | struct sock *sk; | 379 | struct sock *sk; |
376 | struct netlink_sock *nlk; | 380 | struct netlink_sock *nlk; |
@@ -384,7 +388,8 @@ static int __netlink_create(struct socket *sock, int protocol) | |||
384 | sock_init_data(sock, sk); | 388 | sock_init_data(sock, sk); |
385 | 389 | ||
386 | nlk = nlk_sk(sk); | 390 | nlk = nlk_sk(sk); |
387 | spin_lock_init(&nlk->cb_lock); | 391 | nlk->cb_mutex = cb_mutex ? : &nlk->cb_def_mutex; |
392 | mutex_init(nlk->cb_mutex); | ||
388 | init_waitqueue_head(&nlk->wait); | 393 | init_waitqueue_head(&nlk->wait); |
389 | 394 | ||
390 | sk->sk_destruct = netlink_sock_destruct; | 395 | sk->sk_destruct = netlink_sock_destruct; |
@@ -395,6 +400,7 @@ static int __netlink_create(struct socket *sock, int protocol) | |||
395 | static int netlink_create(struct socket *sock, int protocol) | 400 | static int netlink_create(struct socket *sock, int protocol) |
396 | { | 401 | { |
397 | struct module *module = NULL; | 402 | struct module *module = NULL; |
403 | struct mutex *cb_mutex; | ||
398 | struct netlink_sock *nlk; | 404 | struct netlink_sock *nlk; |
399 | int err = 0; | 405 | int err = 0; |
400 | 406 | ||
@@ -417,9 +423,10 @@ static int netlink_create(struct socket *sock, int protocol) | |||
417 | if (nl_table[protocol].registered && | 423 | if (nl_table[protocol].registered && |
418 | try_module_get(nl_table[protocol].module)) | 424 | try_module_get(nl_table[protocol].module)) |
419 | module = nl_table[protocol].module; | 425 | module = nl_table[protocol].module; |
426 | cb_mutex = nl_table[protocol].cb_mutex; | ||
420 | netlink_unlock_table(); | 427 | netlink_unlock_table(); |
421 | 428 | ||
422 | if ((err = __netlink_create(sock, protocol)) < 0) | 429 | if ((err = __netlink_create(sock, cb_mutex, protocol)) < 0) |
423 | goto out_module; | 430 | goto out_module; |
424 | 431 | ||
425 | nlk = nlk_sk(sock->sk); | 432 | nlk = nlk_sk(sock->sk); |
@@ -444,14 +451,14 @@ static int netlink_release(struct socket *sock) | |||
444 | sock_orphan(sk); | 451 | sock_orphan(sk); |
445 | nlk = nlk_sk(sk); | 452 | nlk = nlk_sk(sk); |
446 | 453 | ||
447 | spin_lock(&nlk->cb_lock); | 454 | mutex_lock(nlk->cb_mutex); |
448 | if (nlk->cb) { | 455 | if (nlk->cb) { |
449 | if (nlk->cb->done) | 456 | if (nlk->cb->done) |
450 | nlk->cb->done(nlk->cb); | 457 | nlk->cb->done(nlk->cb); |
451 | netlink_destroy_callback(nlk->cb); | 458 | netlink_destroy_callback(nlk->cb); |
452 | nlk->cb = NULL; | 459 | nlk->cb = NULL; |
453 | } | 460 | } |
454 | spin_unlock(&nlk->cb_lock); | 461 | mutex_unlock(nlk->cb_mutex); |
455 | 462 | ||
456 | /* OK. Socket is unlinked, and, therefore, | 463 | /* OK. Socket is unlinked, and, therefore, |
457 | no new packets will arrive */ | 464 | no new packets will arrive */ |
@@ -1266,7 +1273,7 @@ static void netlink_data_ready(struct sock *sk, int len) | |||
1266 | struct sock * | 1273 | struct sock * |
1267 | netlink_kernel_create(int unit, unsigned int groups, | 1274 | netlink_kernel_create(int unit, unsigned int groups, |
1268 | void (*input)(struct sock *sk, int len), | 1275 | void (*input)(struct sock *sk, int len), |
1269 | struct module *module) | 1276 | struct mutex *cb_mutex, struct module *module) |
1270 | { | 1277 | { |
1271 | struct socket *sock; | 1278 | struct socket *sock; |
1272 | struct sock *sk; | 1279 | struct sock *sk; |
@@ -1281,7 +1288,7 @@ netlink_kernel_create(int unit, unsigned int groups, | |||
1281 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) | 1288 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) |
1282 | return NULL; | 1289 | return NULL; |
1283 | 1290 | ||
1284 | if (__netlink_create(sock, unit) < 0) | 1291 | if (__netlink_create(sock, cb_mutex, unit) < 0) |
1285 | goto out_sock_release; | 1292 | goto out_sock_release; |
1286 | 1293 | ||
1287 | if (groups < 32) | 1294 | if (groups < 32) |
@@ -1305,6 +1312,7 @@ netlink_kernel_create(int unit, unsigned int groups, | |||
1305 | netlink_table_grab(); | 1312 | netlink_table_grab(); |
1306 | nl_table[unit].groups = groups; | 1313 | nl_table[unit].groups = groups; |
1307 | nl_table[unit].listeners = listeners; | 1314 | nl_table[unit].listeners = listeners; |
1315 | nl_table[unit].cb_mutex = cb_mutex; | ||
1308 | nl_table[unit].module = module; | 1316 | nl_table[unit].module = module; |
1309 | nl_table[unit].registered = 1; | 1317 | nl_table[unit].registered = 1; |
1310 | netlink_table_ungrab(); | 1318 | netlink_table_ungrab(); |
@@ -1347,7 +1355,7 @@ static int netlink_dump(struct sock *sk) | |||
1347 | if (!skb) | 1355 | if (!skb) |
1348 | goto errout; | 1356 | goto errout; |
1349 | 1357 | ||
1350 | spin_lock(&nlk->cb_lock); | 1358 | mutex_lock(nlk->cb_mutex); |
1351 | 1359 | ||
1352 | cb = nlk->cb; | 1360 | cb = nlk->cb; |
1353 | if (cb == NULL) { | 1361 | if (cb == NULL) { |
@@ -1358,7 +1366,7 @@ static int netlink_dump(struct sock *sk) | |||
1358 | len = cb->dump(skb, cb); | 1366 | len = cb->dump(skb, cb); |
1359 | 1367 | ||
1360 | if (len > 0) { | 1368 | if (len > 0) { |
1361 | spin_unlock(&nlk->cb_lock); | 1369 | mutex_unlock(nlk->cb_mutex); |
1362 | skb_queue_tail(&sk->sk_receive_queue, skb); | 1370 | skb_queue_tail(&sk->sk_receive_queue, skb); |
1363 | sk->sk_data_ready(sk, len); | 1371 | sk->sk_data_ready(sk, len); |
1364 | return 0; | 1372 | return 0; |
@@ -1376,13 +1384,13 @@ static int netlink_dump(struct sock *sk) | |||
1376 | if (cb->done) | 1384 | if (cb->done) |
1377 | cb->done(cb); | 1385 | cb->done(cb); |
1378 | nlk->cb = NULL; | 1386 | nlk->cb = NULL; |
1379 | spin_unlock(&nlk->cb_lock); | 1387 | mutex_unlock(nlk->cb_mutex); |
1380 | 1388 | ||
1381 | netlink_destroy_callback(cb); | 1389 | netlink_destroy_callback(cb); |
1382 | return 0; | 1390 | return 0; |
1383 | 1391 | ||
1384 | errout_skb: | 1392 | errout_skb: |
1385 | spin_unlock(&nlk->cb_lock); | 1393 | mutex_unlock(nlk->cb_mutex); |
1386 | kfree_skb(skb); | 1394 | kfree_skb(skb); |
1387 | errout: | 1395 | errout: |
1388 | return err; | 1396 | return err; |
@@ -1414,15 +1422,15 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | |||
1414 | } | 1422 | } |
1415 | nlk = nlk_sk(sk); | 1423 | nlk = nlk_sk(sk); |
1416 | /* A dump or destruction is in progress... */ | 1424 | /* A dump or destruction is in progress... */ |
1417 | spin_lock(&nlk->cb_lock); | 1425 | mutex_lock(nlk->cb_mutex); |
1418 | if (nlk->cb || sock_flag(sk, SOCK_DEAD)) { | 1426 | if (nlk->cb || sock_flag(sk, SOCK_DEAD)) { |
1419 | spin_unlock(&nlk->cb_lock); | 1427 | mutex_unlock(nlk->cb_mutex); |
1420 | netlink_destroy_callback(cb); | 1428 | netlink_destroy_callback(cb); |
1421 | sock_put(sk); | 1429 | sock_put(sk); |
1422 | return -EBUSY; | 1430 | return -EBUSY; |
1423 | } | 1431 | } |
1424 | nlk->cb = cb; | 1432 | nlk->cb = cb; |
1425 | spin_unlock(&nlk->cb_lock); | 1433 | mutex_unlock(nlk->cb_mutex); |
1426 | 1434 | ||
1427 | netlink_dump(sk); | 1435 | netlink_dump(sk); |
1428 | sock_put(sk); | 1436 | sock_put(sk); |