Skip to content

Commit

Permalink
SUNRPC: Use shutdown() instead of close() when disconnecting a TCP so…
Browse files Browse the repository at this point in the history
…cket

By using shutdown() rather than close() we allow the RPC client to wait
for the TCP close handshake to complete before we start trying to reconnect
using the same port.
We use shutdown(SHUT_WR) only instead of shutting down both directions,
however we wait until the server has closed the connection on its side.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Trond Myklebust authored and Trond Myklebust committed Jan 30, 2008
1 parent ef80367 commit e06799f
Showing 1 changed file with 34 additions and 7 deletions.
41 changes: 34 additions & 7 deletions net/sunrpc/xprtsock.c
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,22 @@ static int xs_udp_send_request(struct rpc_task *task)
return status;
}

/**
* xs_tcp_shutdown - gracefully shut down a TCP socket
* @xprt: transport
*
* Initiates a graceful shutdown of the TCP socket by calling the
* equivalent of shutdown(SHUT_WR);
*/
static void xs_tcp_shutdown(struct rpc_xprt *xprt)
{
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
struct socket *sock = transport->sock;

if (sock != NULL)
kernel_sock_shutdown(sock, SHUT_WR);
}

static inline void xs_encode_tcp_record_marker(struct xdr_buf *buf)
{
u32 reclen = buf->len - sizeof(rpc_fraghdr);
Expand Down Expand Up @@ -691,7 +707,7 @@ static int xs_tcp_send_request(struct rpc_task *task)
default:
dprintk("RPC: sendmsg returned unrecognized error %d\n",
-status);
xprt_disconnect(xprt);
xs_tcp_shutdown(xprt);
break;
}

Expand Down Expand Up @@ -1637,8 +1653,7 @@ static void xs_tcp_connect_worker4(struct work_struct *work)
break;
default:
/* get rid of existing socket, and retry */
xs_close(xprt);
break;
xs_tcp_shutdown(xprt);
}
}
out:
Expand Down Expand Up @@ -1697,8 +1712,7 @@ static void xs_tcp_connect_worker6(struct work_struct *work)
break;
default:
/* get rid of existing socket, and retry */
xs_close(xprt);
break;
xs_tcp_shutdown(xprt);
}
}
out:
Expand Down Expand Up @@ -1745,6 +1759,19 @@ static void xs_connect(struct rpc_task *task)
}
}

static void xs_tcp_connect(struct rpc_task *task)
{
struct rpc_xprt *xprt = task->tk_xprt;

/* Initiate graceful shutdown of the socket if not already done */
if (test_bit(XPRT_CONNECTED, &xprt->state))
xs_tcp_shutdown(xprt);
/* Exit if we need to wait for socket shutdown to complete */
if (test_bit(XPRT_CLOSING, &xprt->state))
return;
xs_connect(task);
}

/**
* xs_udp_print_stats - display UDP socket-specifc stats
* @xprt: rpc_xprt struct containing statistics
Expand Down Expand Up @@ -1815,12 +1842,12 @@ static struct rpc_xprt_ops xs_tcp_ops = {
.release_xprt = xs_tcp_release_xprt,
.rpcbind = rpcb_getport_async,
.set_port = xs_set_port,
.connect = xs_connect,
.connect = xs_tcp_connect,
.buf_alloc = rpc_malloc,
.buf_free = rpc_free,
.send_request = xs_tcp_send_request,
.set_retrans_timeout = xprt_set_retrans_timeout_def,
.close = xs_close,
.close = xs_tcp_shutdown,
.destroy = xs_destroy,
.print_stats = xs_tcp_print_stats,
};
Expand Down

0 comments on commit e06799f

Please sign in to comment.