diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-25 22:26:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-25 22:26:16 -0400 |
commit | fec4fba6e44407cfbdeed7d48f6f37e6ddfe19d7 (patch) | |
tree | af9f5a5debec880ff3c3d4ef23d6eace821185ca | |
parent | 2ab3f29dddfb444c9fcc0a2f3a56ed4bdba41969 (diff) | |
parent | e498daa81295d02f7359af313c2b7f87e1062207 (diff) |
Merge tag 'nfs-for-3.7-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS bugfixes from Trond Myklebust:
- Fix the NFSv2/v3 kernel statd protocol, which broke due to net
namespace related changes.
- Fix a number of races in the SUNRPC TCP disconnect/reconnect code.
* tag 'nfs-for-3.7-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
LOCKD: Clear ln->nsm_clnt only when ln->nsm_users is zero
LOCKD: fix races in nsm_client_get
SUNRPC: Get rid of the xs_error_report socket callback
SUNRPC: Prevent races in xs_abort_connection()
Revert "SUNRPC: Ensure we close the socket on EPIPE errors too..."
SUNRPC: Clear the connect flag when socket state is TCP_CLOSE_WAIT
-rw-r--r-- | fs/lockd/mon.c | 57 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 41 |
2 files changed, 42 insertions, 56 deletions
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index e4fb3ba5a58a..3d7e09bcc0e9 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -85,29 +85,38 @@ static struct rpc_clnt *nsm_create(struct net *net) | |||
85 | return rpc_create(&args); | 85 | return rpc_create(&args); |
86 | } | 86 | } |
87 | 87 | ||
88 | static struct rpc_clnt *nsm_client_set(struct lockd_net *ln, | ||
89 | struct rpc_clnt *clnt) | ||
90 | { | ||
91 | spin_lock(&ln->nsm_clnt_lock); | ||
92 | if (ln->nsm_users == 0) { | ||
93 | if (clnt == NULL) | ||
94 | goto out; | ||
95 | ln->nsm_clnt = clnt; | ||
96 | } | ||
97 | clnt = ln->nsm_clnt; | ||
98 | ln->nsm_users++; | ||
99 | out: | ||
100 | spin_unlock(&ln->nsm_clnt_lock); | ||
101 | return clnt; | ||
102 | } | ||
103 | |||
88 | static struct rpc_clnt *nsm_client_get(struct net *net) | 104 | static struct rpc_clnt *nsm_client_get(struct net *net) |
89 | { | 105 | { |
90 | static DEFINE_MUTEX(nsm_create_mutex); | 106 | struct rpc_clnt *clnt, *new; |
91 | struct rpc_clnt *clnt; | ||
92 | struct lockd_net *ln = net_generic(net, lockd_net_id); | 107 | struct lockd_net *ln = net_generic(net, lockd_net_id); |
93 | 108 | ||
94 | spin_lock(&ln->nsm_clnt_lock); | 109 | clnt = nsm_client_set(ln, NULL); |
95 | if (ln->nsm_users) { | 110 | if (clnt != NULL) |
96 | ln->nsm_users++; | ||
97 | clnt = ln->nsm_clnt; | ||
98 | spin_unlock(&ln->nsm_clnt_lock); | ||
99 | goto out; | 111 | goto out; |
100 | } | ||
101 | spin_unlock(&ln->nsm_clnt_lock); | ||
102 | 112 | ||
103 | mutex_lock(&nsm_create_mutex); | 113 | clnt = new = nsm_create(net); |
104 | clnt = nsm_create(net); | 114 | if (IS_ERR(clnt)) |
105 | if (!IS_ERR(clnt)) { | 115 | goto out; |
106 | ln->nsm_clnt = clnt; | 116 | |
107 | smp_wmb(); | 117 | clnt = nsm_client_set(ln, new); |
108 | ln->nsm_users = 1; | 118 | if (clnt != new) |
109 | } | 119 | rpc_shutdown_client(new); |
110 | mutex_unlock(&nsm_create_mutex); | ||
111 | out: | 120 | out: |
112 | return clnt; | 121 | return clnt; |
113 | } | 122 | } |
@@ -115,18 +124,16 @@ out: | |||
115 | static void nsm_client_put(struct net *net) | 124 | static void nsm_client_put(struct net *net) |
116 | { | 125 | { |
117 | struct lockd_net *ln = net_generic(net, lockd_net_id); | 126 | struct lockd_net *ln = net_generic(net, lockd_net_id); |
118 | struct rpc_clnt *clnt = ln->nsm_clnt; | 127 | struct rpc_clnt *clnt = NULL; |
119 | int shutdown = 0; | ||
120 | 128 | ||
121 | spin_lock(&ln->nsm_clnt_lock); | 129 | spin_lock(&ln->nsm_clnt_lock); |
122 | if (ln->nsm_users) { | 130 | ln->nsm_users--; |
123 | if (--ln->nsm_users) | 131 | if (ln->nsm_users == 0) { |
124 | ln->nsm_clnt = NULL; | 132 | clnt = ln->nsm_clnt; |
125 | shutdown = !ln->nsm_users; | 133 | ln->nsm_clnt = NULL; |
126 | } | 134 | } |
127 | spin_unlock(&ln->nsm_clnt_lock); | 135 | spin_unlock(&ln->nsm_clnt_lock); |
128 | 136 | if (clnt != NULL) | |
129 | if (shutdown) | ||
130 | rpc_shutdown_client(clnt); | 137 | rpc_shutdown_client(clnt); |
131 | } | 138 | } |
132 | 139 | ||
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index aaaadfbe36e9..75853cabf4c9 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -254,7 +254,6 @@ struct sock_xprt { | |||
254 | void (*old_data_ready)(struct sock *, int); | 254 | void (*old_data_ready)(struct sock *, int); |
255 | void (*old_state_change)(struct sock *); | 255 | void (*old_state_change)(struct sock *); |
256 | void (*old_write_space)(struct sock *); | 256 | void (*old_write_space)(struct sock *); |
257 | void (*old_error_report)(struct sock *); | ||
258 | }; | 257 | }; |
259 | 258 | ||
260 | /* | 259 | /* |
@@ -737,10 +736,10 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
737 | dprintk("RPC: sendmsg returned unrecognized error %d\n", | 736 | dprintk("RPC: sendmsg returned unrecognized error %d\n", |
738 | -status); | 737 | -status); |
739 | case -ECONNRESET: | 738 | case -ECONNRESET: |
740 | case -EPIPE: | ||
741 | xs_tcp_shutdown(xprt); | 739 | xs_tcp_shutdown(xprt); |
742 | case -ECONNREFUSED: | 740 | case -ECONNREFUSED: |
743 | case -ENOTCONN: | 741 | case -ENOTCONN: |
742 | case -EPIPE: | ||
744 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); | 743 | clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags); |
745 | } | 744 | } |
746 | 745 | ||
@@ -781,7 +780,6 @@ static void xs_save_old_callbacks(struct sock_xprt *transport, struct sock *sk) | |||
781 | transport->old_data_ready = sk->sk_data_ready; | 780 | transport->old_data_ready = sk->sk_data_ready; |
782 | transport->old_state_change = sk->sk_state_change; | 781 | transport->old_state_change = sk->sk_state_change; |
783 | transport->old_write_space = sk->sk_write_space; | 782 | transport->old_write_space = sk->sk_write_space; |
784 | transport->old_error_report = sk->sk_error_report; | ||
785 | } | 783 | } |
786 | 784 | ||
787 | static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *sk) | 785 | static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *sk) |
@@ -789,7 +787,6 @@ static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *s | |||
789 | sk->sk_data_ready = transport->old_data_ready; | 787 | sk->sk_data_ready = transport->old_data_ready; |
790 | sk->sk_state_change = transport->old_state_change; | 788 | sk->sk_state_change = transport->old_state_change; |
791 | sk->sk_write_space = transport->old_write_space; | 789 | sk->sk_write_space = transport->old_write_space; |
792 | sk->sk_error_report = transport->old_error_report; | ||
793 | } | 790 | } |
794 | 791 | ||
795 | static void xs_reset_transport(struct sock_xprt *transport) | 792 | static void xs_reset_transport(struct sock_xprt *transport) |
@@ -1453,7 +1450,7 @@ static void xs_tcp_cancel_linger_timeout(struct rpc_xprt *xprt) | |||
1453 | xprt_clear_connecting(xprt); | 1450 | xprt_clear_connecting(xprt); |
1454 | } | 1451 | } |
1455 | 1452 | ||
1456 | static void xs_sock_mark_closed(struct rpc_xprt *xprt) | 1453 | static void xs_sock_reset_connection_flags(struct rpc_xprt *xprt) |
1457 | { | 1454 | { |
1458 | smp_mb__before_clear_bit(); | 1455 | smp_mb__before_clear_bit(); |
1459 | clear_bit(XPRT_CONNECTION_ABORT, &xprt->state); | 1456 | clear_bit(XPRT_CONNECTION_ABORT, &xprt->state); |
@@ -1461,6 +1458,11 @@ static void xs_sock_mark_closed(struct rpc_xprt *xprt) | |||
1461 | clear_bit(XPRT_CLOSE_WAIT, &xprt->state); | 1458 | clear_bit(XPRT_CLOSE_WAIT, &xprt->state); |
1462 | clear_bit(XPRT_CLOSING, &xprt->state); | 1459 | clear_bit(XPRT_CLOSING, &xprt->state); |
1463 | smp_mb__after_clear_bit(); | 1460 | smp_mb__after_clear_bit(); |
1461 | } | ||
1462 | |||
1463 | static void xs_sock_mark_closed(struct rpc_xprt *xprt) | ||
1464 | { | ||
1465 | xs_sock_reset_connection_flags(xprt); | ||
1464 | /* Mark transport as closed and wake up all pending tasks */ | 1466 | /* Mark transport as closed and wake up all pending tasks */ |
1465 | xprt_disconnect_done(xprt); | 1467 | xprt_disconnect_done(xprt); |
1466 | } | 1468 | } |
@@ -1516,6 +1518,7 @@ static void xs_tcp_state_change(struct sock *sk) | |||
1516 | case TCP_CLOSE_WAIT: | 1518 | case TCP_CLOSE_WAIT: |
1517 | /* The server initiated a shutdown of the socket */ | 1519 | /* The server initiated a shutdown of the socket */ |
1518 | xprt->connect_cookie++; | 1520 | xprt->connect_cookie++; |
1521 | clear_bit(XPRT_CONNECTED, &xprt->state); | ||
1519 | xs_tcp_force_close(xprt); | 1522 | xs_tcp_force_close(xprt); |
1520 | case TCP_CLOSING: | 1523 | case TCP_CLOSING: |
1521 | /* | 1524 | /* |
@@ -1540,25 +1543,6 @@ static void xs_tcp_state_change(struct sock *sk) | |||
1540 | read_unlock_bh(&sk->sk_callback_lock); | 1543 | read_unlock_bh(&sk->sk_callback_lock); |
1541 | } | 1544 | } |
1542 | 1545 | ||
1543 | /** | ||
1544 | * xs_error_report - callback mainly for catching socket errors | ||
1545 | * @sk: socket | ||
1546 | */ | ||
1547 | static void xs_error_report(struct sock *sk) | ||
1548 | { | ||
1549 | struct rpc_xprt *xprt; | ||
1550 | |||
1551 | read_lock_bh(&sk->sk_callback_lock); | ||
1552 | if (!(xprt = xprt_from_sock(sk))) | ||
1553 | goto out; | ||
1554 | dprintk("RPC: %s client %p...\n" | ||
1555 | "RPC: error %d\n", | ||
1556 | __func__, xprt, sk->sk_err); | ||
1557 | xprt_wake_pending_tasks(xprt, -EAGAIN); | ||
1558 | out: | ||
1559 | read_unlock_bh(&sk->sk_callback_lock); | ||
1560 | } | ||
1561 | |||
1562 | static void xs_write_space(struct sock *sk) | 1546 | static void xs_write_space(struct sock *sk) |
1563 | { | 1547 | { |
1564 | struct socket *sock; | 1548 | struct socket *sock; |
@@ -1858,7 +1842,6 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt, | |||
1858 | sk->sk_user_data = xprt; | 1842 | sk->sk_user_data = xprt; |
1859 | sk->sk_data_ready = xs_local_data_ready; | 1843 | sk->sk_data_ready = xs_local_data_ready; |
1860 | sk->sk_write_space = xs_udp_write_space; | 1844 | sk->sk_write_space = xs_udp_write_space; |
1861 | sk->sk_error_report = xs_error_report; | ||
1862 | sk->sk_allocation = GFP_ATOMIC; | 1845 | sk->sk_allocation = GFP_ATOMIC; |
1863 | 1846 | ||
1864 | xprt_clear_connected(xprt); | 1847 | xprt_clear_connected(xprt); |
@@ -1983,7 +1966,6 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) | |||
1983 | sk->sk_user_data = xprt; | 1966 | sk->sk_user_data = xprt; |
1984 | sk->sk_data_ready = xs_udp_data_ready; | 1967 | sk->sk_data_ready = xs_udp_data_ready; |
1985 | sk->sk_write_space = xs_udp_write_space; | 1968 | sk->sk_write_space = xs_udp_write_space; |
1986 | sk->sk_error_report = xs_error_report; | ||
1987 | sk->sk_no_check = UDP_CSUM_NORCV; | 1969 | sk->sk_no_check = UDP_CSUM_NORCV; |
1988 | sk->sk_allocation = GFP_ATOMIC; | 1970 | sk->sk_allocation = GFP_ATOMIC; |
1989 | 1971 | ||
@@ -2050,10 +2032,8 @@ static void xs_abort_connection(struct sock_xprt *transport) | |||
2050 | any.sa_family = AF_UNSPEC; | 2032 | any.sa_family = AF_UNSPEC; |
2051 | result = kernel_connect(transport->sock, &any, sizeof(any), 0); | 2033 | result = kernel_connect(transport->sock, &any, sizeof(any), 0); |
2052 | if (!result) | 2034 | if (!result) |
2053 | xs_sock_mark_closed(&transport->xprt); | 2035 | xs_sock_reset_connection_flags(&transport->xprt); |
2054 | else | 2036 | dprintk("RPC: AF_UNSPEC connect return code %d\n", result); |
2055 | dprintk("RPC: AF_UNSPEC connect return code %d\n", | ||
2056 | result); | ||
2057 | } | 2037 | } |
2058 | 2038 | ||
2059 | static void xs_tcp_reuse_connection(struct sock_xprt *transport) | 2039 | static void xs_tcp_reuse_connection(struct sock_xprt *transport) |
@@ -2098,7 +2078,6 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) | |||
2098 | sk->sk_data_ready = xs_tcp_data_ready; | 2078 | sk->sk_data_ready = xs_tcp_data_ready; |
2099 | sk->sk_state_change = xs_tcp_state_change; | 2079 | sk->sk_state_change = xs_tcp_state_change; |
2100 | sk->sk_write_space = xs_tcp_write_space; | 2080 | sk->sk_write_space = xs_tcp_write_space; |
2101 | sk->sk_error_report = xs_error_report; | ||
2102 | sk->sk_allocation = GFP_ATOMIC; | 2081 | sk->sk_allocation = GFP_ATOMIC; |
2103 | 2082 | ||
2104 | /* socket options */ | 2083 | /* socket options */ |