| From foo@baz Wed Dec 3 17:06:53 PST 2014 |
| From: Jiri Bohac <jbohac@suse.cz> |
| Date: Wed, 19 Nov 2014 23:05:49 +0100 |
| Subject: ipx: fix locking regression in ipx_sendmsg and ipx_recvmsg |
| |
| From: Jiri Bohac <jbohac@suse.cz> |
| |
| [ Upstream commit 01462405f0c093b2f8dfddafcadcda6c9e4c5cdf ] |
| |
| This fixes an old regression introduced by commit |
| b0d0d915 (ipx: remove the BKL). |
| |
| When a recvmsg syscall blocks waiting for new data, no data can be sent on the |
| same socket with sendmsg because ipx_recvmsg() sleeps with the socket locked. |
| |
| This breaks mars-nwe (NetWare emulator): |
| - the ncpserv process reads the request using recvmsg |
| - ncpserv forks and spawns nwconn |
| - ncpserv calls a (blocking) recvmsg and waits for new requests |
| - nwconn deadlocks in sendmsg on the same socket |
| |
| Commit b0d0d915 has simply replaced BKL locking with |
| lock_sock/release_sock. Unlike now, BKL got unlocked while |
| sleeping, so a blocking recvmsg did not block a concurrent |
| sendmsg. |
| |
| Only keep the socket locked while actually working with the socket data and |
| release it prior to calling skb_recv_datagram(). |
| |
| Signed-off-by: Jiri Bohac <jbohac@suse.cz> |
| Reviewed-by: Arnd Bergmann <arnd@arndb.de> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipx/af_ipx.c | 6 +++++- |
| 1 file changed, 5 insertions(+), 1 deletion(-) |
| |
| --- a/net/ipx/af_ipx.c |
| +++ b/net/ipx/af_ipx.c |
| @@ -1763,6 +1763,7 @@ static int ipx_recvmsg(struct kiocb *ioc |
| struct ipxhdr *ipx = NULL; |
| struct sk_buff *skb; |
| int copied, rc; |
| + bool locked = true; |
| |
| lock_sock(sk); |
| /* put the autobinding in */ |
| @@ -1789,6 +1790,8 @@ static int ipx_recvmsg(struct kiocb *ioc |
| if (sock_flag(sk, SOCK_ZAPPED)) |
| goto out; |
| |
| + release_sock(sk); |
| + locked = false; |
| skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, |
| flags & MSG_DONTWAIT, &rc); |
| if (!skb) |
| @@ -1822,7 +1825,8 @@ static int ipx_recvmsg(struct kiocb *ioc |
| out_free: |
| skb_free_datagram(sk, skb); |
| out: |
| - release_sock(sk); |
| + if (locked) |
| + release_sock(sk); |
| return rc; |
| } |
| |