From b595bb15061567441546be1af883b256bcdfff9c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:56:42 -0400 Subject: SUNRPC: Fix a signed v. unsigned comparison in net/sunrpc/xprtsock.c Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 4ae7eed7f617..56b226797ae3 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -523,7 +523,8 @@ static int xs_tcp_send_request(struct rpc_task *task) struct rpc_xprt *xprt = req->rq_xprt; struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); struct xdr_buf *xdr = &req->rq_snd_buf; - int status, retry = 0; + int status; + unsigned int retry = 0; xs_encode_tcp_record_marker(&req->rq_snd_buf); -- cgit v1.2.3 From bda243df2f5beebce92bae22bc01960544783984 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:56:52 -0400 Subject: SUNRPC: Use standard macros for printing IP addresses include/linux/kernel.h gives us some nice macros for formatting IP addresses. Use them. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 56b226797ae3..015f29edb619 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -267,7 +267,7 @@ static void xs_format_peer_addresses(struct rpc_xprt *xprt) buf = kzalloc(20, GFP_KERNEL); if (buf) { - snprintf(buf, 20, "%u.%u.%u.%u", + snprintf(buf, 20, NIPQUAD_FMT, NIPQUAD(addr->sin_addr.s_addr)); } xprt->address_strings[RPC_DISPLAY_ADDR] = buf; @@ -286,7 +286,7 @@ static void xs_format_peer_addresses(struct rpc_xprt *xprt) buf = kzalloc(48, GFP_KERNEL); if (buf) { - snprintf(buf, 48, "addr=%u.%u.%u.%u port=%u proto=%s", + snprintf(buf, 48, "addr="NIPQUAD_FMT" port=%u proto=%s", NIPQUAD(addr->sin_addr.s_addr), ntohs(addr->sin_port), xprt->prot == IPPROTO_UDP ? "udp" : "tcp"); -- cgit v1.2.3 From 0c43b3d81cca46ab2469f8802f8bd68b49f1b2a5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:56:57 -0400 Subject: SUNRPC: Free address buffers in a loop Use more generic logic to free buffers holding formatted addresses. This makes it less likely a bug will be introduced when adding additional buffer types in xs_format_peer_address(). Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 015f29edb619..b3f40b8dbcba 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -279,10 +279,14 @@ static void xs_format_peer_addresses(struct rpc_xprt *xprt) } xprt->address_strings[RPC_DISPLAY_PORT] = buf; - if (xprt->prot == IPPROTO_UDP) - xprt->address_strings[RPC_DISPLAY_PROTO] = "udp"; - else - xprt->address_strings[RPC_DISPLAY_PROTO] = "tcp"; + buf = kzalloc(8, GFP_KERNEL); + if (buf) { + if (xprt->prot == IPPROTO_UDP) + snprintf(buf, 8, "udp"); + else + snprintf(buf, 8, "tcp"); + } + xprt->address_strings[RPC_DISPLAY_PROTO] = buf; buf = kzalloc(48, GFP_KERNEL); if (buf) { @@ -296,9 +300,10 @@ static void xs_format_peer_addresses(struct rpc_xprt *xprt) static void xs_free_peer_addresses(struct rpc_xprt *xprt) { - kfree(xprt->address_strings[RPC_DISPLAY_ADDR]); - kfree(xprt->address_strings[RPC_DISPLAY_PORT]); - kfree(xprt->address_strings[RPC_DISPLAY_ALL]); + int i; + + for (i = 0; i < RPC_DISPLAY_MAX; i++) + kfree(xprt->address_strings[i]); } #define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL) -- cgit v1.2.3 From fbfe3cc677c1a62ca6472abf24d03d4bf9f03a55 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:57:02 -0400 Subject: SUNRPC: Add hex-formatted address support to rpc_peeraddr2str() Add support for the NFS client's need to export volume information with IP addresses formatted in hex instead of decimal. This isn't used yet, but subsequent patches (not in this series) will change the NFS client to use this functionality. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 2 ++ net/sunrpc/xprtsock.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+) (limited to 'net/sunrpc/xprtsock.c') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index d11cedd14f0f..4596c26f97aa 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -53,6 +53,8 @@ enum rpc_display_format_t { RPC_DISPLAY_PORT, RPC_DISPLAY_PROTO, RPC_DISPLAY_ALL, + RPC_DISPLAY_HEX_ADDR, + RPC_DISPLAY_HEX_PORT, RPC_DISPLAY_MAX, }; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index b3f40b8dbcba..8a684d873111 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -296,6 +296,20 @@ static void xs_format_peer_addresses(struct rpc_xprt *xprt) xprt->prot == IPPROTO_UDP ? "udp" : "tcp"); } xprt->address_strings[RPC_DISPLAY_ALL] = buf; + + buf = kzalloc(10, GFP_KERNEL); + if (buf) { + snprintf(buf, 10, "%02x%02x%02x%02x", + NIPQUAD(addr->sin_addr.s_addr)); + } + xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf; + + buf = kzalloc(8, GFP_KERNEL); + if (buf) { + snprintf(buf, 8, "%4hx", + ntohs(addr->sin_port)); + } + xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf; } static void xs_free_peer_addresses(struct rpc_xprt *xprt) -- cgit v1.2.3 From ba10f2c23471b2ef106eb0c71ead4e9862766b8d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:57:07 -0400 Subject: SUNRPC: Rename xs_format_peer_addresses Prepare to add an IPv6 version of xs_format_peer_addresses by renaming it to xs_format_ipv4_peer_addresses. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 8a684d873111..45fac56b40f9 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -260,7 +260,7 @@ struct sock_xprt { #define TCP_RCV_COPY_XID (1UL << 2) #define TCP_RCV_COPY_DATA (1UL << 3) -static void xs_format_peer_addresses(struct rpc_xprt *xprt) +static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt) { struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr; char *buf; @@ -1600,7 +1600,7 @@ struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args) else xprt_set_timeout(&xprt->timeout, 5, 5 * HZ); - xs_format_peer_addresses(xprt); + xs_format_ipv4_peer_addresses(xprt); dprintk("RPC: set up transport to address %s\n", xprt->address_strings[RPC_DISPLAY_ALL]); @@ -1642,7 +1642,7 @@ struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args) else xprt_set_timeout(&xprt->timeout, 2, 60 * HZ); - xs_format_peer_addresses(xprt); + xs_format_ipv4_peer_addresses(xprt); dprintk("RPC: set up transport to address %s\n", xprt->address_strings[RPC_DISPLAY_ALL]); -- cgit v1.2.3 From 4b6473fba4e832ee1d15737bc38779501c349a61 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:57:12 -0400 Subject: SUNRPC: add a function to format IPv6 addresses Clone xs_format_ipv4_peer_addresses into an IPv6 version. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 45fac56b40f9..23e5865d984c 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -312,6 +312,58 @@ static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt) xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf; } +static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt) +{ + struct sockaddr_in6 *addr = (struct sockaddr_in6 *) &xprt->addr; + char *buf; + + buf = kzalloc(40, GFP_KERNEL); + if (buf) { + snprintf(buf, 40, NIP6_FMT, + NIP6(addr->sin6_addr)); + } + xprt->address_strings[RPC_DISPLAY_ADDR] = buf; + + buf = kzalloc(8, GFP_KERNEL); + if (buf) { + snprintf(buf, 8, "%u", + ntohs(addr->sin6_port)); + } + xprt->address_strings[RPC_DISPLAY_PORT] = buf; + + buf = kzalloc(8, GFP_KERNEL); + if (buf) { + if (xprt->prot == IPPROTO_UDP) + snprintf(buf, 8, "udp"); + else + snprintf(buf, 8, "tcp"); + } + xprt->address_strings[RPC_DISPLAY_PROTO] = buf; + + buf = kzalloc(64, GFP_KERNEL); + if (buf) { + snprintf(buf, 64, "addr="NIP6_FMT" port=%u proto=%s", + NIP6(addr->sin6_addr), + ntohs(addr->sin6_port), + xprt->prot == IPPROTO_UDP ? "udp" : "tcp"); + } + xprt->address_strings[RPC_DISPLAY_ALL] = buf; + + buf = kzalloc(36, GFP_KERNEL); + if (buf) { + snprintf(buf, 36, NIP6_SEQFMT, + NIP6(addr->sin6_addr)); + } + xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf; + + buf = kzalloc(8, GFP_KERNEL); + if (buf) { + snprintf(buf, 8, "%4hx", + ntohs(addr->sin6_port)); + } + xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf; +} + static void xs_free_peer_addresses(struct rpc_xprt *xprt) { int i; -- cgit v1.2.3 From 20612005c51a5ba1bb17902276b9216825958724 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:57:23 -0400 Subject: SUNRPC: Introduce support for setting the port number in IPv6 addresses We could clone xs_set_port, but this is easier overall. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 23e5865d984c..a2dddec5325e 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1211,11 +1211,20 @@ static unsigned short xs_get_random_port(void) */ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port) { - struct sockaddr_in *sap = (struct sockaddr_in *) &xprt->addr; + struct sockaddr *addr = (struct sockaddr *) &xprt->addr; dprintk("RPC: setting port for xprt %p to %u\n", xprt, port); - sap->sin_port = htons(port); + switch (addr->sa_family) { + case AF_INET: + ((struct sockaddr_in *)addr)->sin_port = htons(port); + break; + case AF_INET6: + ((struct sockaddr_in6 *)addr)->sin6_port = htons(port); + break; + default: + BUG(); + } } static int xs_bind(struct sock_xprt *transport, struct socket *sock) -- cgit v1.2.3 From 7dc753f0391ad94868609376f37be4833671b57d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:57:28 -0400 Subject: SUNRPC: Rename xs_bind() to prepare for IPv6-specific bind method Prepare for introduction of IPv6-specific socket bind function. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index a2dddec5325e..cd7c18b24527 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1227,7 +1227,7 @@ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port) } } -static int xs_bind(struct sock_xprt *transport, struct socket *sock) +static int xs_bind4(struct sock_xprt *transport, struct socket *sock) { struct sockaddr_in myaddr = { .sin_family = AF_INET, @@ -1255,8 +1255,9 @@ static int xs_bind(struct sock_xprt *transport, struct socket *sock) else port--; } while (err == -EADDRINUSE && port != transport->port); - dprintk("RPC: xs_bind "NIPQUAD_FMT":%u: %s (%d)\n", - NIPQUAD(myaddr.sin_addr), port, err ? "failed" : "ok", err); + dprintk("RPC: %s "NIPQUAD_FMT":%u: %s (%d)\n", + __FUNCTION__, NIPQUAD(myaddr.sin_addr), + port, err ? "failed" : "ok", err); return err; } @@ -1315,7 +1316,7 @@ static void xs_udp_connect_worker(struct work_struct *work) } xs_reclassify_socket(sock); - if (xs_bind(transport, sock)) { + if (xs_bind4(transport, sock)) { sock_release(sock); goto out; } @@ -1402,7 +1403,7 @@ static void xs_tcp_connect_worker(struct work_struct *work) } xs_reclassify_socket(sock); - if (xs_bind(transport, sock)) { + if (xs_bind4(transport, sock)) { sock_release(sock); goto out; } -- cgit v1.2.3 From 90058d37c30ffce0e033ea3dcc6a539111483a58 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:57:33 -0400 Subject: SUNRPC: create an IPv6-savvy mechanism for binding to a reserved port Clone xs_bindresvport into two functions, one that can handle IPv4 addresses, and one that can handle IPv6 addresses. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index cd7c18b24527..8295ae28391a 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1261,6 +1261,39 @@ static int xs_bind4(struct sock_xprt *transport, struct socket *sock) return err; } +static int xs_bind6(struct sock_xprt *transport, struct socket *sock) +{ + struct sockaddr_in6 myaddr = { + .sin6_family = AF_INET6, + }; + struct sockaddr_in6 *sa; + int err; + unsigned short port = transport->port; + + if (!transport->xprt.resvport) + port = 0; + sa = (struct sockaddr_in6 *)&transport->addr; + myaddr.sin6_addr = sa->sin6_addr; + do { + myaddr.sin6_port = htons(port); + err = kernel_bind(sock, (struct sockaddr *) &myaddr, + sizeof(myaddr)); + if (!transport->xprt.resvport) + break; + if (err == 0) { + transport->port = port; + break; + } + if (port <= xprt_min_resvport) + port = xprt_max_resvport; + else + port--; + } while (err == -EADDRINUSE && port != transport->port); + dprintk("RPC: xs_bind6 "NIP6_FMT":%u: %s (%d)\n", + NIP6(myaddr.sin6_addr), port, err ? "failed" : "ok", err); + return err; +} + #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key xs_key[2]; static struct lock_class_key xs_slock_key[2]; -- cgit v1.2.3 From 16be2d20d999cb65daebfdaf0e560225e28fcb9d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:57:38 -0400 Subject: SUNRPC: Refactor a part of socket connect logic into a helper function Finishing a socket connect is the same for IPv4 and IPv6, so split it out into a helper. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 131 +++++++++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 59 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 8295ae28391a..e8a5edf59912 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1323,6 +1323,35 @@ static inline void xs_reclassify_socket(struct socket *sock) } #endif +static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) +{ + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); + + if (!transport->inet) { + struct sock *sk = sock->sk; + + write_lock_bh(&sk->sk_callback_lock); + + sk->sk_user_data = xprt; + transport->old_data_ready = sk->sk_data_ready; + transport->old_state_change = sk->sk_state_change; + transport->old_write_space = sk->sk_write_space; + sk->sk_data_ready = xs_udp_data_ready; + sk->sk_write_space = xs_udp_write_space; + sk->sk_no_check = UDP_CSUM_NORCV; + sk->sk_allocation = GFP_ATOMIC; + + xprt_set_connected(xprt); + + /* Reset to new socket */ + transport->sock = sock; + transport->inet = sk; + + write_unlock_bh(&sk->sk_callback_lock); + } + xs_udp_do_set_buffer_size(xprt); +} + /** * xs_udp_connect_worker - set up a UDP socket * @work: RPC transport to connect @@ -1357,29 +1386,7 @@ static void xs_udp_connect_worker(struct work_struct *work) dprintk("RPC: worker connecting xprt %p to address: %s\n", xprt, xprt->address_strings[RPC_DISPLAY_ALL]); - if (!transport->inet) { - struct sock *sk = sock->sk; - - write_lock_bh(&sk->sk_callback_lock); - - sk->sk_user_data = xprt; - transport->old_data_ready = sk->sk_data_ready; - transport->old_state_change = sk->sk_state_change; - transport->old_write_space = sk->sk_write_space; - sk->sk_data_ready = xs_udp_data_ready; - sk->sk_write_space = xs_udp_write_space; - sk->sk_no_check = UDP_CSUM_NORCV; - sk->sk_allocation = GFP_ATOMIC; - - xprt_set_connected(xprt); - - /* Reset to new socket */ - transport->sock = sock; - transport->inet = sk; - - write_unlock_bh(&sk->sk_callback_lock); - } - xs_udp_do_set_buffer_size(xprt); + xs_udp_finish_connecting(xprt, sock); status = 0; out: xprt_wake_pending_tasks(xprt, status); @@ -1410,42 +1417,9 @@ static void xs_tcp_reuse_connection(struct rpc_xprt *xprt) result); } -/** - * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint - * @work: RPC transport to connect - * - * Invoked by a work queue tasklet. - */ -static void xs_tcp_connect_worker(struct work_struct *work) +static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) { - struct sock_xprt *transport = - container_of(work, struct sock_xprt, connect_worker.work); - struct rpc_xprt *xprt = &transport->xprt; - struct socket *sock = transport->sock; - int err, status = -EIO; - - if (xprt->shutdown || !xprt_bound(xprt)) - goto out; - - if (!sock) { - /* start from scratch */ - if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) { - dprintk("RPC: can't create TCP transport " - "socket (%d).\n", -err); - goto out; - } - xs_reclassify_socket(sock); - - if (xs_bind4(transport, sock)) { - sock_release(sock); - goto out; - } - } else - /* "close" the socket, preserving the local port */ - xs_tcp_reuse_connection(xprt); - - dprintk("RPC: worker connecting xprt %p to address: %s\n", - xprt, xprt->address_strings[RPC_DISPLAY_ALL]); + struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); if (!transport->inet) { struct sock *sk = sock->sk; @@ -1479,8 +1453,47 @@ static void xs_tcp_connect_worker(struct work_struct *work) /* Tell the socket layer to start connecting... */ xprt->stat.connect_count++; xprt->stat.connect_start = jiffies; - status = kernel_connect(sock, (struct sockaddr *) &xprt->addr, + return kernel_connect(sock, (struct sockaddr *) &xprt->addr, xprt->addrlen, O_NONBLOCK); +} + +/** + * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint + * @work: RPC transport to connect + * + * Invoked by a work queue tasklet. + */ +static void xs_tcp_connect_worker(struct work_struct *work) +{ + struct sock_xprt *transport = + container_of(work, struct sock_xprt, connect_worker.work); + struct rpc_xprt *xprt = &transport->xprt; + struct socket *sock = transport->sock; + int err, status = -EIO; + + if (xprt->shutdown || !xprt_bound(xprt)) + goto out; + + if (!sock) { + /* start from scratch */ + if ((err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) { + dprintk("RPC: can't create TCP transport socket (%d).\n", -err); + goto out; + } + xs_reclassify_socket(sock); + + if (xs_bind4(transport, sock) < 0) { + sock_release(sock); + goto out; + } + } else + /* "close" the socket, preserving the local port */ + xs_tcp_reuse_connection(xprt); + + dprintk("RPC: worker connecting xprt %p to address: %s\n", + xprt, xprt->address_strings[RPC_DISPLAY_ALL]); + + status = xs_tcp_finish_connecting(xprt, sock); dprintk("RPC: %p connect status %d connected %d sock state %d\n", xprt, -status, xprt_connected(xprt), sock->sk->sk_state); -- cgit v1.2.3 From 9c3d72de28eed3e882becd7054da2118f8a73131 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:57:43 -0400 Subject: SUNRPC: Rename IPv4 connect workers Prepare for introduction of IPv6 versions of same. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index e8a5edf59912..a0c26b9ebb34 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1353,12 +1353,12 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) } /** - * xs_udp_connect_worker - set up a UDP socket + * xs_udp_connect_worker4 - set up a UDP socket * @work: RPC transport to connect * * Invoked by a work queue tasklet. */ -static void xs_udp_connect_worker(struct work_struct *work) +static void xs_udp_connect_worker4(struct work_struct *work) { struct sock_xprt *transport = container_of(work, struct sock_xprt, connect_worker.work); @@ -1458,12 +1458,12 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) } /** - * xs_tcp_connect_worker - connect a TCP socket to a remote endpoint + * xs_tcp_connect_worker4 - connect a TCP socket to a remote endpoint * @work: RPC transport to connect * * Invoked by a work queue tasklet. */ -static void xs_tcp_connect_worker(struct work_struct *work) +static void xs_tcp_connect_worker4(struct work_struct *work) { struct sock_xprt *transport = container_of(work, struct sock_xprt, connect_worker.work); @@ -1695,7 +1695,7 @@ struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args) /* XXX: header size can vary due to auth type, IPv6, etc. */ xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); - INIT_DELAYED_WORK(&transport->connect_worker, xs_udp_connect_worker); + INIT_DELAYED_WORK(&transport->connect_worker, xs_udp_connect_worker4); xprt->bind_timeout = XS_BIND_TO; xprt->connect_timeout = XS_UDP_CONN_TO; xprt->reestablish_timeout = XS_UDP_REEST_TO; @@ -1737,7 +1737,7 @@ struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args) xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; - INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker); + INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker4); xprt->bind_timeout = XS_BIND_TO; xprt->connect_timeout = XS_TCP_CONN_TO; xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; -- cgit v1.2.3 From 68e220bd5c9fc52d8029275cd42e08f573ce3600 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:57:48 -0400 Subject: SUNRPC: create connect workers for IPv6 Clone separate connect worker functions for connecting AF_INET6 sockets. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index a0c26b9ebb34..cc4db1763aa4 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1393,6 +1393,47 @@ out: xprt_clear_connecting(xprt); } +/** + * xs_udp_connect_worker6 - set up a UDP socket + * @work: RPC transport to connect + * + * Invoked by a work queue tasklet. + */ +static void xs_udp_connect_worker6(struct work_struct *work) +{ + struct sock_xprt *transport = + container_of(work, struct sock_xprt, connect_worker.work); + struct rpc_xprt *xprt = &transport->xprt; + struct socket *sock = transport->sock; + int err, status = -EIO; + + if (xprt->shutdown || !xprt_bound(xprt)) + goto out; + + /* Start by resetting any existing state */ + xs_close(xprt); + + if ((err = sock_create_kern(PF_INET6, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) { + dprintk("RPC: can't create UDP transport socket (%d).\n", -err); + goto out; + } + xs_reclassify_socket(sock); + + if (xs_bind6(transport, sock) < 0) { + sock_release(sock); + goto out; + } + + dprintk("RPC: worker connecting xprt %p to address: %s\n", + xprt, xprt->address_strings[RPC_DISPLAY_ALL]); + + xs_udp_finish_connecting(xprt, sock); + status = 0; +out: + xprt_wake_pending_tasks(xprt, status); + xprt_clear_connecting(xprt); +} + /* * We need to preserve the port number so the reply cache on the server can * find our cached RPC replies when we get around to reconnecting. @@ -1518,6 +1559,66 @@ out_clear: xprt_clear_connecting(xprt); } +/** + * xs_tcp_connect_worker6 - connect a TCP socket to a remote endpoint + * @work: RPC transport to connect + * + * Invoked by a work queue tasklet. + */ +static void xs_tcp_connect_worker6(struct work_struct *work) +{ + struct sock_xprt *transport = + container_of(work, struct sock_xprt, connect_worker.work); + struct rpc_xprt *xprt = &transport->xprt; + struct socket *sock = transport->sock; + int err, status = -EIO; + + if (xprt->shutdown || !xprt_bound(xprt)) + goto out; + + if (!sock) { + /* start from scratch */ + if ((err = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &sock)) < 0) { + dprintk("RPC: can't create TCP transport socket (%d).\n", -err); + goto out; + } + xs_reclassify_socket(sock); + + if (xs_bind6(transport, sock) < 0) { + sock_release(sock); + goto out; + } + } else + /* "close" the socket, preserving the local port */ + xs_tcp_reuse_connection(xprt); + + dprintk("RPC: worker connecting xprt %p to address: %s\n", + xprt, xprt->address_strings[RPC_DISPLAY_ALL]); + + status = xs_tcp_finish_connecting(xprt, sock); + dprintk("RPC: %p connect status %d connected %d sock state %d\n", + xprt, -status, xprt_connected(xprt), sock->sk->sk_state); + if (status < 0) { + switch (status) { + case -EINPROGRESS: + case -EALREADY: + goto out_clear; + case -ECONNREFUSED: + case -ECONNRESET: + /* retry with existing socket, after a delay */ + break; + default: + /* get rid of existing socket, and retry */ + xs_close(xprt); + break; + } + } +out: + xprt_wake_pending_tasks(xprt, status); +out_clear: + xprt_clear_connecting(xprt); +} + /** * xs_connect - connect a socket to a remote endpoint * @task: address of RPC task that manages state of connect request -- cgit v1.2.3 From 8f9d5b1a2e717fb9e0c4d2c60a224ecce905bd23 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:57:53 -0400 Subject: SUNRPC: Add IPv6 address support to net/sunrpc/xprtsock.c Finalize support for setting up RPC client transports to remote RPC services addressed via IPv6. Based on work done by Gilles Quillard at Bull Open Source. Signed-off-by: Chuck Lever Cc: Aurelien Charbon Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 57 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 10 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index cc4db1763aa4..d9e65765f6c4 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -13,6 +13,9 @@ * (C) 1999 Trond Myklebust * * IP socket transport implementation, (C) 2005 Chuck Lever + * + * IPv6 support contributed by Gilles Quillard, Bull Open Source, 2005. + * */ #include @@ -1780,6 +1783,7 @@ static struct rpc_xprt *xs_setup_xprt(struct rpc_xprtsock_create *args, unsigned */ struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args) { + struct sockaddr *addr = args->dstaddr; struct rpc_xprt *xprt; struct sock_xprt *transport; @@ -1788,15 +1792,11 @@ struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args) return xprt; transport = container_of(xprt, struct sock_xprt, xprt); - if (ntohs(((struct sockaddr_in *)args->dstaddr)->sin_port) != 0) - xprt_set_bound(xprt); - xprt->prot = IPPROTO_UDP; xprt->tsh_size = 0; /* XXX: header size can vary due to auth type, IPv6, etc. */ xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); - INIT_DELAYED_WORK(&transport->connect_worker, xs_udp_connect_worker4); xprt->bind_timeout = XS_BIND_TO; xprt->connect_timeout = XS_UDP_CONN_TO; xprt->reestablish_timeout = XS_UDP_REEST_TO; @@ -1809,7 +1809,28 @@ struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args) else xprt_set_timeout(&xprt->timeout, 5, 5 * HZ); - xs_format_ipv4_peer_addresses(xprt); + switch (addr->sa_family) { + case AF_INET: + if (((struct sockaddr_in *)addr)->sin_port != htons(0)) + xprt_set_bound(xprt); + + INIT_DELAYED_WORK(&transport->connect_worker, + xs_udp_connect_worker4); + xs_format_ipv4_peer_addresses(xprt); + break; + case AF_INET6: + if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0)) + xprt_set_bound(xprt); + + INIT_DELAYED_WORK(&transport->connect_worker, + xs_udp_connect_worker6); + xs_format_ipv6_peer_addresses(xprt); + break; + default: + kfree(xprt); + return ERR_PTR(-EAFNOSUPPORT); + } + dprintk("RPC: set up transport to address %s\n", xprt->address_strings[RPC_DISPLAY_ALL]); @@ -1823,6 +1844,7 @@ struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args) */ struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args) { + struct sockaddr *addr = args->dstaddr; struct rpc_xprt *xprt; struct sock_xprt *transport; @@ -1831,14 +1853,10 @@ struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args) return xprt; transport = container_of(xprt, struct sock_xprt, xprt); - if (ntohs(((struct sockaddr_in *)args->dstaddr)->sin_port) != 0) - xprt_set_bound(xprt); - xprt->prot = IPPROTO_TCP; xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32); xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; - INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker4); xprt->bind_timeout = XS_BIND_TO; xprt->connect_timeout = XS_TCP_CONN_TO; xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; @@ -1851,7 +1869,26 @@ struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args) else xprt_set_timeout(&xprt->timeout, 2, 60 * HZ); - xs_format_ipv4_peer_addresses(xprt); + switch (addr->sa_family) { + case AF_INET: + if (((struct sockaddr_in *)addr)->sin_port != htons(0)) + xprt_set_bound(xprt); + + INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker4); + xs_format_ipv4_peer_addresses(xprt); + break; + case AF_INET6: + if (((struct sockaddr_in6 *)addr)->sin6_port != htons(0)) + xprt_set_bound(xprt); + + INIT_DELAYED_WORK(&transport->connect_worker, xs_tcp_connect_worker6); + xs_format_ipv6_peer_addresses(xprt); + break; + default: + kfree(xprt); + return ERR_PTR(-EAFNOSUPPORT); + } + dprintk("RPC: set up transport to address %s\n", xprt->address_strings[RPC_DISPLAY_ALL]); -- cgit v1.2.3 From 95392c593e13fa7546857425971f87e4ded6e0c1 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:57:58 -0400 Subject: SUNRPC: Add a helper for extracting the address using the correct type Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index d9e65765f6c4..fcbfae82cb12 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -263,9 +263,24 @@ struct sock_xprt { #define TCP_RCV_COPY_XID (1UL << 2) #define TCP_RCV_COPY_DATA (1UL << 3) +static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) +{ + return (struct sockaddr *) &xprt->addr; +} + +static inline struct sockaddr_in *xs_addr_in(struct rpc_xprt *xprt) +{ + return (struct sockaddr_in *) &xprt->addr; +} + +static inline struct sockaddr_in6 *xs_addr_in6(struct rpc_xprt *xprt) +{ + return (struct sockaddr_in6 *) &xprt->addr; +} + static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt) { - struct sockaddr_in *addr = (struct sockaddr_in *) &xprt->addr; + struct sockaddr_in *addr = xs_addr_in(xprt); char *buf; buf = kzalloc(20, GFP_KERNEL); @@ -317,7 +332,7 @@ static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt) static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt) { - struct sockaddr_in6 *addr = (struct sockaddr_in6 *) &xprt->addr; + struct sockaddr_in6 *addr = xs_addr_in6(xprt); char *buf; buf = kzalloc(40, GFP_KERNEL); @@ -537,7 +552,7 @@ static int xs_udp_send_request(struct rpc_task *task) req->rq_xtime = jiffies; status = xs_sendpages(transport->sock, - (struct sockaddr *) &xprt->addr, + xs_addr(xprt), xprt->addrlen, xdr, req->rq_bytes_sent); @@ -1214,7 +1229,7 @@ static unsigned short xs_get_random_port(void) */ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port) { - struct sockaddr *addr = (struct sockaddr *) &xprt->addr; + struct sockaddr *addr = xs_addr(xprt); dprintk("RPC: setting port for xprt %p to %u\n", xprt, port); @@ -1497,8 +1512,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) /* Tell the socket layer to start connecting... */ xprt->stat.connect_count++; xprt->stat.connect_start = jiffies; - return kernel_connect(sock, (struct sockaddr *) &xprt->addr, - xprt->addrlen, O_NONBLOCK); + return kernel_connect(sock, xs_addr(xprt), xprt->addrlen, O_NONBLOCK); } /** -- cgit v1.2.3 From 8945ee5e27156ef9708bc3a11da87ba689aa38b6 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 6 Aug 2007 11:58:04 -0400 Subject: SUNRPC: Split xs_reclassify_socket into an IPv4 and IPv6 version Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index fcbfae82cb12..01121a4f0851 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1316,27 +1316,29 @@ static int xs_bind6(struct sock_xprt *transport, struct socket *sock) static struct lock_class_key xs_key[2]; static struct lock_class_key xs_slock_key[2]; -static inline void xs_reclassify_socket(struct socket *sock) +static inline void xs_reclassify_socket4(struct socket *sock) { struct sock *sk = sock->sk; + BUG_ON(sk->sk_lock.owner != NULL); - switch (sk->sk_family) { - case AF_INET: - sock_lock_init_class_and_name(sk, "slock-AF_INET-NFS", - &xs_slock_key[0], "sk_lock-AF_INET-NFS", &xs_key[0]); - break; + sock_lock_init_class_and_name(sk, "slock-AF_INET-RPC", + &xs_slock_key[0], "sk_lock-AF_INET-RPC", &xs_key[0]); +} - case AF_INET6: - sock_lock_init_class_and_name(sk, "slock-AF_INET6-NFS", - &xs_slock_key[1], "sk_lock-AF_INET6-NFS", &xs_key[1]); - break; +static inline void xs_reclassify_socket6(struct socket *sock) +{ + struct sock *sk = sock->sk; - default: - BUG(); - } + BUG_ON(sk->sk_lock.owner != NULL); + sock_lock_init_class_and_name(sk, "slock-AF_INET6-RPC", + &xs_slock_key[1], "sk_lock-AF_INET6-RPC", &xs_key[1]); } #else -static inline void xs_reclassify_socket(struct socket *sock) +static inline void xs_reclassify_socket4(struct socket *sock) +{ +} + +static inline void xs_reclassify_socket6(struct socket *sock) { } #endif @@ -1394,7 +1396,7 @@ static void xs_udp_connect_worker4(struct work_struct *work) dprintk("RPC: can't create UDP transport socket (%d).\n", -err); goto out; } - xs_reclassify_socket(sock); + xs_reclassify_socket4(sock); if (xs_bind4(transport, sock)) { sock_release(sock); @@ -1435,7 +1437,7 @@ static void xs_udp_connect_worker6(struct work_struct *work) dprintk("RPC: can't create UDP transport socket (%d).\n", -err); goto out; } - xs_reclassify_socket(sock); + xs_reclassify_socket6(sock); if (xs_bind6(transport, sock) < 0) { sock_release(sock); @@ -1538,7 +1540,7 @@ static void xs_tcp_connect_worker4(struct work_struct *work) dprintk("RPC: can't create TCP transport socket (%d).\n", -err); goto out; } - xs_reclassify_socket(sock); + xs_reclassify_socket4(sock); if (xs_bind4(transport, sock) < 0) { sock_release(sock); @@ -1599,7 +1601,7 @@ static void xs_tcp_connect_worker6(struct work_struct *work) dprintk("RPC: can't create TCP transport socket (%d).\n", -err); goto out; } - xs_reclassify_socket(sock); + xs_reclassify_socket6(sock); if (xs_bind6(transport, sock) < 0) { sock_release(sock); -- cgit v1.2.3 From 756805e7a76bcd2aae07fe31786fe453375e60b1 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 16 Aug 2007 16:03:26 -0400 Subject: SUNRPC: Add support for formatted universal addresses "Universal addresses" are a string representation of an IP address and port. They are described fully in RFC 3530, section 2.2. Add support for generating them in the RPC client's socket transport module. Signed-off-by: Chuck Lever --- include/linux/sunrpc/xprt.h | 1 + net/sunrpc/xprtsock.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'net/sunrpc/xprtsock.c') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 4596c26f97aa..902a9c0a2d9a 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -55,6 +55,7 @@ enum rpc_display_format_t { RPC_DISPLAY_ALL, RPC_DISPLAY_HEX_ADDR, RPC_DISPLAY_HEX_PORT, + RPC_DISPLAY_UNIVERSAL_ADDR, RPC_DISPLAY_MAX, }; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 01121a4f0851..7a154e4b70f5 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -328,6 +328,15 @@ static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt) ntohs(addr->sin_port)); } xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf; + + buf = kzalloc(30, GFP_KERNEL); + if (buf) { + snprintf(buf, 30, NIPQUAD_FMT".%u.%u", + NIPQUAD(addr->sin_addr.s_addr), + ntohs(addr->sin_port) >> 8, + ntohs(addr->sin_port) & 0xff); + } + xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf; } static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt) @@ -380,6 +389,15 @@ static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt) ntohs(addr->sin6_port)); } xprt->address_strings[RPC_DISPLAY_HEX_PORT] = buf; + + buf = kzalloc(50, GFP_KERNEL); + if (buf) { + snprintf(buf, 50, NIP6_FMT".%u.%u", + NIP6(addr->sin6_addr), + ntohs(addr->sin6_port) >> 8, + ntohs(addr->sin6_port) & 0xff); + } + xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf; } static void xs_free_peer_addresses(struct rpc_xprt *xprt) -- cgit v1.2.3 From 4417c8c41a51a2ae95b2a2fa2811640b368c4151 Mon Sep 17 00:00:00 2001 From: "\\\"Talpey, Thomas\\" Date: Mon, 10 Sep 2007 13:43:05 -0400 Subject: SUNRPC: export per-transport rpcbind netid's The rpcbind (v3+) netid is provided by each RPC client transport. This fixes an omission in IPv6 rpcbind client support, and enables future extension. Signed-off-by: Tom Talpey Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 1 + net/sunrpc/rpcb_clnt.c | 3 +-- net/sunrpc/xprtsock.c | 8 ++++++++ 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 902a9c0a2d9a..513b0657e14d 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -56,6 +56,7 @@ enum rpc_display_format_t { RPC_DISPLAY_HEX_ADDR, RPC_DISPLAY_HEX_PORT, RPC_DISPLAY_UNIVERSAL_ADDR, + RPC_DISPLAY_NETID, RPC_DISPLAY_MAX, }; diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index b028a0ecd593..6f0af08a51dc 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -388,8 +388,7 @@ void rpcb_getport_async(struct rpc_task *task) map->r_prot = xprt->prot; map->r_port = 0; map->r_xprt = xprt_get(xprt); - map->r_netid = (xprt->prot == IPPROTO_TCP) ? RPCBIND_NETID_TCP : - RPCBIND_NETID_UDP; + map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); memcpy(map->r_addr, rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR), sizeof(map->r_addr)); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 7a154e4b70f5..5bdce8fa2d56 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -337,6 +337,10 @@ static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt) ntohs(addr->sin_port) & 0xff); } xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf; + + xprt->address_strings[RPC_DISPLAY_NETID] = + kstrdup(xprt->prot == IPPROTO_UDP ? + RPCBIND_NETID_UDP : RPCBIND_NETID_TCP, GFP_KERNEL); } static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt) @@ -398,6 +402,10 @@ static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt) ntohs(addr->sin6_port) & 0xff); } xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf; + + xprt->address_strings[RPC_DISPLAY_NETID] = + kstrdup(xprt->prot == IPPROTO_UDP ? + RPCBIND_NETID_UDP6 : RPCBIND_NETID_TCP6, GFP_KERNEL); } static void xs_free_peer_addresses(struct rpc_xprt *xprt) -- cgit v1.2.3 From bc25571e21e8bd053554209f5b1b228ad71e6b99 Mon Sep 17 00:00:00 2001 From: "\\\"Talpey, Thomas\\" Date: Mon, 10 Sep 2007 13:46:39 -0400 Subject: SUNRPC: Finish API to load RPC transport implementations dynamically Allow RPC client transport implementations to be loaded as needed, or as they become available from distributors or third-party vendors. Note that we leave the IP sockets implementation in sunrpc.o permanently, as IP functionality is always available in any kernel that runs NFS. Signed-off-by: Chuck Lever Signed-off-by: Tom Talpey Signed-off-by: Trond Myklebust --- net/sunrpc/xprt.c | 26 +++++++++++++++----------- net/sunrpc/xprtsock.c | 47 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 16 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 520859622af5..7f8c60b84396 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -983,19 +983,23 @@ struct rpc_xprt *xprt_create_transport(struct rpc_xprtsock_create *args) { struct rpc_xprt *xprt; struct rpc_rqst *req; + struct xprt_class *t; - switch (args->proto) { - case IPPROTO_UDP: - xprt = xs_setup_udp(args); - break; - case IPPROTO_TCP: - xprt = xs_setup_tcp(args); - break; - default: - printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n", - args->proto); - return ERR_PTR(-EIO); + spin_lock(&xprt_list_lock); + list_for_each_entry(t, &xprt_list, list) { + if ((t->family == args->dstaddr->sa_family) && + (t->protocol == args->proto)) { + spin_unlock(&xprt_list_lock); + goto found; + } } + spin_unlock(&xprt_list_lock); + printk(KERN_ERR "RPC: transport (%u/%d) not supported\n", + args->dstaddr->sa_family, args->proto); + return ERR_PTR(-EIO); + +found: + xprt = t->setup(args); if (IS_ERR(xprt)) { dprintk("RPC: xprt_create_transport: failed, %ld\n", -PTR_ERR(xprt)); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 5bdce8fa2d56..3bc9c921c82f 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -777,6 +778,7 @@ static void xs_destroy(struct rpc_xprt *xprt) xs_free_peer_addresses(xprt); kfree(xprt->slot); kfree(xprt); + module_put(THIS_MODULE); } static inline struct rpc_xprt *xprt_from_sock(struct sock *sk) @@ -1782,7 +1784,8 @@ static struct rpc_xprt_ops xs_tcp_ops = { .print_stats = xs_tcp_print_stats, }; -static struct rpc_xprt *xs_setup_xprt(struct rpc_xprtsock_create *args, unsigned int slot_table_size) +static struct rpc_xprt *xs_setup_xprt(struct rpc_xprtsock_create *args, + unsigned int slot_table_size) { struct rpc_xprt *xprt; struct sock_xprt *new; @@ -1876,7 +1879,12 @@ struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args) dprintk("RPC: set up transport to address %s\n", xprt->address_strings[RPC_DISPLAY_ALL]); - return xprt; + if (try_module_get(THIS_MODULE)) + return xprt; + + kfree(xprt->slot); + kfree(xprt); + return ERR_PTR(-EINVAL); } /** @@ -1934,11 +1942,34 @@ struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args) dprintk("RPC: set up transport to address %s\n", xprt->address_strings[RPC_DISPLAY_ALL]); - return xprt; + if (try_module_get(THIS_MODULE)) + return xprt; + + kfree(xprt->slot); + kfree(xprt); + return ERR_PTR(-EINVAL); } +static struct xprt_class xs_udp_transport = { + .list = LIST_HEAD_INIT(xs_udp_transport.list), + .name = "udp", + .owner = THIS_MODULE, + .family = AF_INET, + .protocol = IPPROTO_UDP, + .setup = xs_setup_udp, +}; + +static struct xprt_class xs_tcp_transport = { + .list = LIST_HEAD_INIT(xs_tcp_transport.list), + .name = "tcp", + .owner = THIS_MODULE, + .family = AF_INET, + .protocol = IPPROTO_TCP, + .setup = xs_setup_tcp, +}; + /** - * init_socket_xprt - set up xprtsock's sysctls + * init_socket_xprt - set up xprtsock's sysctls, register with RPC client * */ int init_socket_xprt(void) @@ -1948,11 +1979,14 @@ int init_socket_xprt(void) sunrpc_table_header = register_sysctl_table(sunrpc_table); #endif + xprt_register_transport(&xs_udp_transport); + xprt_register_transport(&xs_tcp_transport); + return 0; } /** - * cleanup_socket_xprt - remove xprtsock's sysctls + * cleanup_socket_xprt - remove xprtsock's sysctls, unregister * */ void cleanup_socket_xprt(void) @@ -1963,4 +1997,7 @@ void cleanup_socket_xprt(void) sunrpc_table_header = NULL; } #endif + + xprt_unregister_transport(&xs_udp_transport); + xprt_unregister_transport(&xs_tcp_transport); } -- cgit v1.2.3 From 3c341b0b925eee01daae2c594b81e673f659d7cd Mon Sep 17 00:00:00 2001 From: "\\\"Talpey, Thomas\\" Date: Mon, 10 Sep 2007 13:47:07 -0400 Subject: SUNRPC: rename the rpc_xprtsock_create structure To prepare for including non-sockets-based RPC transports, change the overly suggestive name of the transport creation arguments struct. Signed-off-by: Tom Talpey Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 10 +++++----- net/sunrpc/clnt.c | 2 +- net/sunrpc/xprt.c | 2 +- net/sunrpc/xprtsock.c | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 7b6b137eca97..6992ff02d737 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -200,7 +200,7 @@ struct rpc_xprt { char * address_strings[RPC_DISPLAY_MAX]; }; -struct rpc_xprtsock_create { +struct xprt_create { int proto; /* IPPROTO_UDP or IPPROTO_TCP */ struct sockaddr * srcaddr; /* optional local address */ struct sockaddr * dstaddr; /* remote peer address */ @@ -212,7 +212,7 @@ struct xprt_class { struct list_head list; unsigned short family; int protocol; - struct rpc_xprt * (*setup)(struct rpc_xprtsock_create *); + struct rpc_xprt * (*setup)(struct xprt_create *); struct module *owner; char name[32]; }; @@ -225,7 +225,7 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long /* * Generic internal transport functions */ -struct rpc_xprt * xprt_create_transport(struct rpc_xprtsock_create *args); +struct rpc_xprt *xprt_create_transport(struct xprt_create *args); void xprt_connect(struct rpc_task *task); void xprt_reserve(struct rpc_task *task); int xprt_reserve_xprt(struct rpc_task *task); @@ -265,8 +265,8 @@ void xprt_disconnect(struct rpc_xprt *xprt); /* * Socket transport setup operations */ -struct rpc_xprt * xs_setup_udp(struct rpc_xprtsock_create *args); -struct rpc_xprt * xs_setup_tcp(struct rpc_xprtsock_create *args); +struct rpc_xprt *xs_setup_udp(struct xprt_create *args); +struct rpc_xprt *xs_setup_tcp(struct xprt_create *args); int init_socket_xprt(void); void cleanup_socket_xprt(void); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 19c129ed6467..e86958c61a20 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -240,7 +240,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) { struct rpc_xprt *xprt; struct rpc_clnt *clnt; - struct rpc_xprtsock_create xprtargs = { + struct xprt_create xprtargs = { .proto = args->protocol, .srcaddr = args->saddress, .dstaddr = args->address, diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 7f8c60b84396..473b48ff4523 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -979,7 +979,7 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long i * @args: rpc transport creation arguments * */ -struct rpc_xprt *xprt_create_transport(struct rpc_xprtsock_create *args) +struct rpc_xprt *xprt_create_transport(struct xprt_create *args) { struct rpc_xprt *xprt; struct rpc_rqst *req; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 3bc9c921c82f..4f1a57b28a49 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1784,7 +1784,7 @@ static struct rpc_xprt_ops xs_tcp_ops = { .print_stats = xs_tcp_print_stats, }; -static struct rpc_xprt *xs_setup_xprt(struct rpc_xprtsock_create *args, +static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, unsigned int slot_table_size) { struct rpc_xprt *xprt; @@ -1826,7 +1826,7 @@ static struct rpc_xprt *xs_setup_xprt(struct rpc_xprtsock_create *args, * @args: rpc transport creation arguments * */ -struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args) +struct rpc_xprt *xs_setup_udp(struct xprt_create *args) { struct sockaddr *addr = args->dstaddr; struct rpc_xprt *xprt; @@ -1892,7 +1892,7 @@ struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args) * @args: rpc transport creation arguments * */ -struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args) +struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) { struct sockaddr *addr = args->dstaddr; struct rpc_xprt *xprt; -- cgit v1.2.3 From 49c36fcc441baf6a4d698e3645d1adf28edaf57b Mon Sep 17 00:00:00 2001 From: "\\\"Talpey, Thomas\\" Date: Mon, 10 Sep 2007 13:47:31 -0400 Subject: SUNRPC: rearrange RPC sockets definitions To prepare for including non-sockets-based RPC transports, move the sockets-dependent definitions into their own file. Signed-off-by: Tom Talpey Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 22 ---------------------- include/linux/sunrpc/xprtsock.h | 40 ++++++++++++++++++++++++++++++++++++++++ net/sunrpc/sunrpc_syms.c | 2 +- net/sunrpc/xprtsock.c | 1 + 4 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 include/linux/sunrpc/xprtsock.h (limited to 'net/sunrpc/xprtsock.c') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 6992ff02d737..d7b8fcd312cc 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -19,24 +19,10 @@ #ifdef __KERNEL__ -extern unsigned int xprt_udp_slot_table_entries; -extern unsigned int xprt_tcp_slot_table_entries; - #define RPC_MIN_SLOT_TABLE (2U) #define RPC_DEF_SLOT_TABLE (16U) #define RPC_MAX_SLOT_TABLE (128U) -/* - * Parameters for choosing a free port - */ -extern unsigned int xprt_min_resvport; -extern unsigned int xprt_max_resvport; - -#define RPC_MIN_RESVPORT (1U) -#define RPC_MAX_RESVPORT (65535U) -#define RPC_DEF_MIN_RESVPORT (665U) -#define RPC_DEF_MAX_RESVPORT (1023U) - /* * This describes a timeout strategy */ @@ -262,14 +248,6 @@ void xprt_complete_rqst(struct rpc_task *task, int copied); void xprt_release_rqst_cong(struct rpc_task *task); void xprt_disconnect(struct rpc_xprt *xprt); -/* - * Socket transport setup operations - */ -struct rpc_xprt *xs_setup_udp(struct xprt_create *args); -struct rpc_xprt *xs_setup_tcp(struct xprt_create *args); -int init_socket_xprt(void); -void cleanup_socket_xprt(void); - /* * Reserved bit positions in xprt->state */ diff --git a/include/linux/sunrpc/xprtsock.h b/include/linux/sunrpc/xprtsock.h new file mode 100644 index 000000000000..9bde77061e4f --- /dev/null +++ b/include/linux/sunrpc/xprtsock.h @@ -0,0 +1,40 @@ +/* + * linux/include/linux/sunrpc/xprtsock.h + * + * Declarations for the RPC transport socket provider. + */ + +#ifndef _LINUX_SUNRPC_XPRTSOCK_H +#define _LINUX_SUNRPC_XPRTSOCK_H + +#ifdef __KERNEL__ + +/* + * Socket transport setup operations + */ +struct rpc_xprt *xs_setup_udp(struct xprt_create *args); +struct rpc_xprt *xs_setup_tcp(struct xprt_create *args); + +int init_socket_xprt(void); +void cleanup_socket_xprt(void); + +/* + * RPC slot table sizes for UDP, TCP transports + */ +extern unsigned int xprt_udp_slot_table_entries; +extern unsigned int xprt_tcp_slot_table_entries; + +/* + * Parameters for choosing a free port + */ +extern unsigned int xprt_min_resvport; +extern unsigned int xprt_max_resvport; + +#define RPC_MIN_RESVPORT (1U) +#define RPC_MAX_RESVPORT (65535U) +#define RPC_DEF_MIN_RESVPORT (665U) +#define RPC_DEF_MAX_RESVPORT (1023U) + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_SUNRPC_XPRTSOCK_H */ diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 384c4ad5ab86..33d89e842c85 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -20,7 +20,7 @@ #include #include #include - +#include /* RPC scheduler */ EXPORT_SYMBOL(rpc_execute); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 4f1a57b28a49..192a06e3b8c5 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 4fa016eb248cac875541fa199af550a8aefa0e90 Mon Sep 17 00:00:00 2001 From: "\\\"Talpey, Thomas\\" Date: Mon, 10 Sep 2007 13:47:57 -0400 Subject: NFS/SUNRPC: support transport protocol naming To prepare for including non-sockets-based RPC transports, select RPC transports by an identifier (to be used in following patches). Signed-off-by: Tom Talpey Signed-off-by: Trond Myklebust --- include/linux/sunrpc/xprt.h | 5 ++--- include/linux/sunrpc/xprtsock.h | 11 +++++++++++ net/sunrpc/clnt.c | 2 +- net/sunrpc/xprt.c | 8 +++----- net/sunrpc/xprtsock.c | 6 ++---- 5 files changed, 19 insertions(+), 13 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index d7b8fcd312cc..30b17b3bc1a9 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -187,7 +187,7 @@ struct rpc_xprt { }; struct xprt_create { - int proto; /* IPPROTO_UDP or IPPROTO_TCP */ + int ident; /* XPRT_TRANSPORT identifier */ struct sockaddr * srcaddr; /* optional local address */ struct sockaddr * dstaddr; /* remote peer address */ size_t addrlen; @@ -196,8 +196,7 @@ struct xprt_create { struct xprt_class { struct list_head list; - unsigned short family; - int protocol; + int ident; /* XPRT_TRANSPORT identifier */ struct rpc_xprt * (*setup)(struct xprt_create *); struct module *owner; char name[32]; diff --git a/include/linux/sunrpc/xprtsock.h b/include/linux/sunrpc/xprtsock.h index 9bde77061e4f..2c6c2c2783d8 100644 --- a/include/linux/sunrpc/xprtsock.h +++ b/include/linux/sunrpc/xprtsock.h @@ -18,6 +18,17 @@ struct rpc_xprt *xs_setup_tcp(struct xprt_create *args); int init_socket_xprt(void); void cleanup_socket_xprt(void); +/* + * RPC transport identifiers for UDP, TCP + * + * To preserve compatibility with the historical use of raw IP protocol + * id's for transport selection, these are specified with the previous + * values. No such restriction exists for new transports, except that + * they may not collide with these values (17 and 6, respectively). + */ +#define XPRT_TRANSPORT_UDP IPPROTO_UDP +#define XPRT_TRANSPORT_TCP IPPROTO_TCP + /* * RPC slot table sizes for UDP, TCP transports */ diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index e86958c61a20..6cdf53c489b7 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -241,7 +241,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) struct rpc_xprt *xprt; struct rpc_clnt *clnt; struct xprt_create xprtargs = { - .proto = args->protocol, + .ident = args->protocol, .srcaddr = args->saddress, .dstaddr = args->address, .addrlen = args->addrsize, diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 473b48ff4523..282a9a2ec90c 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -104,7 +104,7 @@ int xprt_register_transport(struct xprt_class *transport) spin_lock(&xprt_list_lock); list_for_each_entry(t, &xprt_list, list) { /* don't register the same transport class twice */ - if (t == transport) + if (t->ident == transport->ident) goto out; } @@ -987,15 +987,13 @@ struct rpc_xprt *xprt_create_transport(struct xprt_create *args) spin_lock(&xprt_list_lock); list_for_each_entry(t, &xprt_list, list) { - if ((t->family == args->dstaddr->sa_family) && - (t->protocol == args->proto)) { + if (t->ident == args->ident) { spin_unlock(&xprt_list_lock); goto found; } } spin_unlock(&xprt_list_lock); - printk(KERN_ERR "RPC: transport (%u/%d) not supported\n", - args->dstaddr->sa_family, args->proto); + printk(KERN_ERR "RPC: transport (%d) not supported\n", args->ident); return ERR_PTR(-EIO); found: diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 192a06e3b8c5..b81494a97a5e 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1955,8 +1955,7 @@ static struct xprt_class xs_udp_transport = { .list = LIST_HEAD_INIT(xs_udp_transport.list), .name = "udp", .owner = THIS_MODULE, - .family = AF_INET, - .protocol = IPPROTO_UDP, + .ident = IPPROTO_UDP, .setup = xs_setup_udp, }; @@ -1964,8 +1963,7 @@ static struct xprt_class xs_tcp_transport = { .list = LIST_HEAD_INIT(xs_tcp_transport.list), .name = "tcp", .owner = THIS_MODULE, - .family = AF_INET, - .protocol = IPPROTO_TCP, + .ident = IPPROTO_TCP, .setup = xs_setup_tcp, }; -- cgit v1.2.3 From 1321d8d971028e796978f6a48d195c09158b3bcd Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 24 Sep 2007 15:40:00 -0400 Subject: SUNRPC: Fix bytes-per-op accounting for RPC over UDP NFS performance metrics reported zero bytes sent per op when mounting with UDP. The UDP socket transport wasn't properly counting the number of bytes sent. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index b81494a97a5e..e97e4ca43ef3 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -587,6 +587,7 @@ static int xs_udp_send_request(struct rpc_task *task) dprintk("RPC: xs_udp_send_request(%u) = %d\n", xdr->len - req->rq_bytes_sent, status); + task->tk_bytes_sent += status; if (likely(status >= (int) req->rq_slen)) return 0; -- cgit v1.2.3 From 2199700f1d660494d2552278354422c51becb686 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 1 Oct 2007 11:43:37 -0400 Subject: SUNRPC: Fix buggy UDP transmission xs_sendpages() may return a negative result. We sure as hell don't want to add that to the 'tk_bytes_sent' tally... Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net/sunrpc/xprtsock.c') diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index e97e4ca43ef3..6f32cc57f429 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -587,13 +587,13 @@ static int xs_udp_send_request(struct rpc_task *task) dprintk("RPC: xs_udp_send_request(%u) = %d\n", xdr->len - req->rq_bytes_sent, status); - task->tk_bytes_sent += status; - if (likely(status >= (int) req->rq_slen)) - return 0; - - /* Still some bytes left; set up for a retry later. */ - if (status > 0) + if (status >= 0) { + task->tk_bytes_sent += status; + if (status >= req->rq_slen) + return 0; + /* Still some bytes left; set up for a retry later. */ status = -EAGAIN; + } switch (status) { case -ENETUNREACH: -- cgit v1.2.3