diff options
author | Arnd Bergmann <arnd@arndb.de> | 2011-01-22 17:44:59 -0500 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2011-03-05 04:55:45 -0500 |
commit | 77b2283604bdd7053494a97b0e2fee97148206c6 (patch) | |
tree | 4d5c54156d64fd80de765cc18dc7e4a68b5ec5e1 | |
parent | 788257d6101d986ac8f2741aaa35974af47f574c (diff) |
x25: remove the BKL
This replaces all instances of lock_kernel in x25
with lock_sock, taking care to release the socket
lock around sleeping functions (sock_alloc_send_skb
and skb_recv_datagram). It is not clear whether
this is a correct solution, but it seem to be what
other protocols do in the same situation.
Includes a fix suggested by Eric Dumazet.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: David S. Miller <davem@davemloft.net>
Tested-by: Andrew Hendry <andrew.hendry@gmail.com>
Cc: linux-x25@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: Eric Dumazet <eric.dumazet@gmail.com>
-rw-r--r-- | net/x25/Kconfig | 1 | ||||
-rw-r--r-- | net/x25/af_x25.c | 58 | ||||
-rw-r--r-- | net/x25/x25_out.c | 7 |
3 files changed, 23 insertions, 43 deletions
diff --git a/net/x25/Kconfig b/net/x25/Kconfig index 2196e55e4f61..e6759c9660bb 100644 --- a/net/x25/Kconfig +++ b/net/x25/Kconfig | |||
@@ -5,7 +5,6 @@ | |||
5 | config X25 | 5 | config X25 |
6 | tristate "CCITT X.25 Packet Layer (EXPERIMENTAL)" | 6 | tristate "CCITT X.25 Packet Layer (EXPERIMENTAL)" |
7 | depends on EXPERIMENTAL | 7 | depends on EXPERIMENTAL |
8 | depends on BKL # should be fixable | ||
9 | ---help--- | 8 | ---help--- |
10 | X.25 is a set of standardized network protocols, similar in scope to | 9 | X.25 is a set of standardized network protocols, similar in scope to |
11 | frame relay; the one physical line from your box to the X.25 network | 10 | frame relay; the one physical line from your box to the X.25 network |
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index ad96ee90fe27..4680b1e4c79c 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #include <linux/errno.h> | 40 | #include <linux/errno.h> |
41 | #include <linux/kernel.h> | 41 | #include <linux/kernel.h> |
42 | #include <linux/sched.h> | 42 | #include <linux/sched.h> |
43 | #include <linux/smp_lock.h> | ||
44 | #include <linux/timer.h> | 43 | #include <linux/timer.h> |
45 | #include <linux/string.h> | 44 | #include <linux/string.h> |
46 | #include <linux/net.h> | 45 | #include <linux/net.h> |
@@ -432,15 +431,6 @@ void x25_destroy_socket_from_timer(struct sock *sk) | |||
432 | sock_put(sk); | 431 | sock_put(sk); |
433 | } | 432 | } |
434 | 433 | ||
435 | static void x25_destroy_socket(struct sock *sk) | ||
436 | { | ||
437 | sock_hold(sk); | ||
438 | lock_sock(sk); | ||
439 | __x25_destroy_socket(sk); | ||
440 | release_sock(sk); | ||
441 | sock_put(sk); | ||
442 | } | ||
443 | |||
444 | /* | 434 | /* |
445 | * Handling for system calls applied via the various interfaces to a | 435 | * Handling for system calls applied via the various interfaces to a |
446 | * X.25 socket object. | 436 | * X.25 socket object. |
@@ -647,18 +637,19 @@ static int x25_release(struct socket *sock) | |||
647 | struct sock *sk = sock->sk; | 637 | struct sock *sk = sock->sk; |
648 | struct x25_sock *x25; | 638 | struct x25_sock *x25; |
649 | 639 | ||
650 | lock_kernel(); | ||
651 | if (!sk) | 640 | if (!sk) |
652 | goto out; | 641 | return 0; |
653 | 642 | ||
654 | x25 = x25_sk(sk); | 643 | x25 = x25_sk(sk); |
655 | 644 | ||
645 | sock_hold(sk); | ||
646 | lock_sock(sk); | ||
656 | switch (x25->state) { | 647 | switch (x25->state) { |
657 | 648 | ||
658 | case X25_STATE_0: | 649 | case X25_STATE_0: |
659 | case X25_STATE_2: | 650 | case X25_STATE_2: |
660 | x25_disconnect(sk, 0, 0, 0); | 651 | x25_disconnect(sk, 0, 0, 0); |
661 | x25_destroy_socket(sk); | 652 | __x25_destroy_socket(sk); |
662 | goto out; | 653 | goto out; |
663 | 654 | ||
664 | case X25_STATE_1: | 655 | case X25_STATE_1: |
@@ -678,7 +669,8 @@ static int x25_release(struct socket *sock) | |||
678 | 669 | ||
679 | sock_orphan(sk); | 670 | sock_orphan(sk); |
680 | out: | 671 | out: |
681 | unlock_kernel(); | 672 | release_sock(sk); |
673 | sock_put(sk); | ||
682 | return 0; | 674 | return 0; |
683 | } | 675 | } |
684 | 676 | ||
@@ -1085,7 +1077,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
1085 | size_t size; | 1077 | size_t size; |
1086 | int qbit = 0, rc = -EINVAL; | 1078 | int qbit = 0, rc = -EINVAL; |
1087 | 1079 | ||
1088 | lock_kernel(); | 1080 | lock_sock(sk); |
1089 | if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_OOB|MSG_EOR|MSG_CMSG_COMPAT)) | 1081 | if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_OOB|MSG_EOR|MSG_CMSG_COMPAT)) |
1090 | goto out; | 1082 | goto out; |
1091 | 1083 | ||
@@ -1148,7 +1140,9 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
1148 | 1140 | ||
1149 | size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN; | 1141 | size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN; |
1150 | 1142 | ||
1143 | release_sock(sk); | ||
1151 | skb = sock_alloc_send_skb(sk, size, noblock, &rc); | 1144 | skb = sock_alloc_send_skb(sk, size, noblock, &rc); |
1145 | lock_sock(sk); | ||
1152 | if (!skb) | 1146 | if (!skb) |
1153 | goto out; | 1147 | goto out; |
1154 | X25_SKB_CB(skb)->flags = msg->msg_flags; | 1148 | X25_SKB_CB(skb)->flags = msg->msg_flags; |
@@ -1231,26 +1225,10 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
1231 | len++; | 1225 | len++; |
1232 | } | 1226 | } |
1233 | 1227 | ||
1234 | /* | ||
1235 | * lock_sock() is currently only used to serialize this x25_kick() | ||
1236 | * against input-driven x25_kick() calls. It currently only blocks | ||
1237 | * incoming packets for this socket and does not protect against | ||
1238 | * any other socket state changes and is not called from anywhere | ||
1239 | * else. As x25_kick() cannot block and as long as all socket | ||
1240 | * operations are BKL-wrapped, we don't need take to care about | ||
1241 | * purging the backlog queue in x25_release(). | ||
1242 | * | ||
1243 | * Using lock_sock() to protect all socket operations entirely | ||
1244 | * (and making the whole x25 stack SMP aware) unfortunately would | ||
1245 | * require major changes to {send,recv}msg and skb allocation methods. | ||
1246 | * -> 2.5 ;) | ||
1247 | */ | ||
1248 | lock_sock(sk); | ||
1249 | x25_kick(sk); | 1228 | x25_kick(sk); |
1250 | release_sock(sk); | ||
1251 | rc = len; | 1229 | rc = len; |
1252 | out: | 1230 | out: |
1253 | unlock_kernel(); | 1231 | release_sock(sk); |
1254 | return rc; | 1232 | return rc; |
1255 | out_kfree_skb: | 1233 | out_kfree_skb: |
1256 | kfree_skb(skb); | 1234 | kfree_skb(skb); |
@@ -1271,7 +1249,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1271 | unsigned char *asmptr; | 1249 | unsigned char *asmptr; |
1272 | int rc = -ENOTCONN; | 1250 | int rc = -ENOTCONN; |
1273 | 1251 | ||
1274 | lock_kernel(); | 1252 | lock_sock(sk); |
1275 | /* | 1253 | /* |
1276 | * This works for seqpacket too. The receiver has ordered the queue for | 1254 | * This works for seqpacket too. The receiver has ordered the queue for |
1277 | * us! We do one quick check first though | 1255 | * us! We do one quick check first though |
@@ -1300,8 +1278,10 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1300 | msg->msg_flags |= MSG_OOB; | 1278 | msg->msg_flags |= MSG_OOB; |
1301 | } else { | 1279 | } else { |
1302 | /* Now we can treat all alike */ | 1280 | /* Now we can treat all alike */ |
1281 | release_sock(sk); | ||
1303 | skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, | 1282 | skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, |
1304 | flags & MSG_DONTWAIT, &rc); | 1283 | flags & MSG_DONTWAIT, &rc); |
1284 | lock_sock(sk); | ||
1305 | if (!skb) | 1285 | if (!skb) |
1306 | goto out; | 1286 | goto out; |
1307 | 1287 | ||
@@ -1338,14 +1318,12 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1338 | 1318 | ||
1339 | msg->msg_namelen = sizeof(struct sockaddr_x25); | 1319 | msg->msg_namelen = sizeof(struct sockaddr_x25); |
1340 | 1320 | ||
1341 | lock_sock(sk); | ||
1342 | x25_check_rbuf(sk); | 1321 | x25_check_rbuf(sk); |
1343 | release_sock(sk); | ||
1344 | rc = copied; | 1322 | rc = copied; |
1345 | out_free_dgram: | 1323 | out_free_dgram: |
1346 | skb_free_datagram(sk, skb); | 1324 | skb_free_datagram(sk, skb); |
1347 | out: | 1325 | out: |
1348 | unlock_kernel(); | 1326 | release_sock(sk); |
1349 | return rc; | 1327 | return rc; |
1350 | } | 1328 | } |
1351 | 1329 | ||
@@ -1581,18 +1559,18 @@ out_cud_release: | |||
1581 | 1559 | ||
1582 | case SIOCX25CALLACCPTAPPRV: { | 1560 | case SIOCX25CALLACCPTAPPRV: { |
1583 | rc = -EINVAL; | 1561 | rc = -EINVAL; |
1584 | lock_kernel(); | 1562 | lock_sock(sk); |
1585 | if (sk->sk_state != TCP_CLOSE) | 1563 | if (sk->sk_state != TCP_CLOSE) |
1586 | break; | 1564 | break; |
1587 | clear_bit(X25_ACCPT_APPRV_FLAG, &x25->flags); | 1565 | clear_bit(X25_ACCPT_APPRV_FLAG, &x25->flags); |
1588 | unlock_kernel(); | 1566 | release_sock(sk); |
1589 | rc = 0; | 1567 | rc = 0; |
1590 | break; | 1568 | break; |
1591 | } | 1569 | } |
1592 | 1570 | ||
1593 | case SIOCX25SENDCALLACCPT: { | 1571 | case SIOCX25SENDCALLACCPT: { |
1594 | rc = -EINVAL; | 1572 | rc = -EINVAL; |
1595 | lock_kernel(); | 1573 | lock_sock(sk); |
1596 | if (sk->sk_state != TCP_ESTABLISHED) | 1574 | if (sk->sk_state != TCP_ESTABLISHED) |
1597 | break; | 1575 | break; |
1598 | /* must call accptapprv above */ | 1576 | /* must call accptapprv above */ |
@@ -1600,7 +1578,7 @@ out_cud_release: | |||
1600 | break; | 1578 | break; |
1601 | x25_write_internal(sk, X25_CALL_ACCEPTED); | 1579 | x25_write_internal(sk, X25_CALL_ACCEPTED); |
1602 | x25->state = X25_STATE_3; | 1580 | x25->state = X25_STATE_3; |
1603 | unlock_kernel(); | 1581 | release_sock(sk); |
1604 | rc = 0; | 1582 | rc = 0; |
1605 | break; | 1583 | break; |
1606 | } | 1584 | } |
diff --git a/net/x25/x25_out.c b/net/x25/x25_out.c index d00649fb251d..0144271d2184 100644 --- a/net/x25/x25_out.c +++ b/net/x25/x25_out.c | |||
@@ -68,8 +68,11 @@ int x25_output(struct sock *sk, struct sk_buff *skb) | |||
68 | frontlen = skb_headroom(skb); | 68 | frontlen = skb_headroom(skb); |
69 | 69 | ||
70 | while (skb->len > 0) { | 70 | while (skb->len > 0) { |
71 | if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, | 71 | release_sock(sk); |
72 | noblock, &err)) == NULL){ | 72 | skbn = sock_alloc_send_skb(sk, frontlen + max_len, |
73 | noblock, &err); | ||
74 | lock_sock(sk); | ||
75 | if (!skbn) { | ||
73 | if (err == -EWOULDBLOCK && noblock){ | 76 | if (err == -EWOULDBLOCK && noblock){ |
74 | kfree_skb(skb); | 77 | kfree_skb(skb); |
75 | return sent; | 78 | return sent; |