NFS,RPC: RPC client now advertises maximum payload size The RPC client now reports the maximum payload size supported by the chosen transport method. This is something a little less than 64KB for RPC over UDP, and about 2GB - 1 for RPC over TCP. The effective rsize and wsize values are not allowed to exceed the reported maximum RPC payload size. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 7 +++++++ include/linux/sunrpc/clnt.h | 1 + include/linux/sunrpc/xprt.h | 3 +++ net/sunrpc/clnt.c | 15 +++++++++++++++ net/sunrpc/xprt.c | 5 ++++- 5 files changed, 30 insertions(+), 1 deletion(-) Index: linux-2.6.11-rc3/fs/nfs/inode.c =================================================================== --- linux-2.6.11-rc3.orig/fs/nfs/inode.c +++ linux-2.6.11-rc3/fs/nfs/inode.c @@ -249,6 +249,7 @@ nfs_sb_init(struct super_block *sb, rpc_ .fattr = &fattr, }; int no_root_error = 0; + unsigned long max_rpc_payload; /* We probably want something more informative here */ snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev)); @@ -285,6 +286,12 @@ nfs_sb_init(struct super_block *sb, rpc_ if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax) server->wsize = nfs_block_size(fsinfo.wtmax, NULL); + max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL); + if (server->rsize > max_rpc_payload) + server->rsize = max_rpc_payload; + if (server->wsize > max_rpc_payload) + server->wsize = max_rpc_payload; + server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; if (server->rpages > NFS_READ_MAXIOV) { server->rpages = NFS_READ_MAXIOV; Index: linux-2.6.11-rc3/include/linux/sunrpc/clnt.h =================================================================== --- linux-2.6.11-rc3.orig/include/linux/sunrpc/clnt.h +++ linux-2.6.11-rc3/include/linux/sunrpc/clnt.h @@ -128,6 +128,7 @@ void rpc_restart_call(struct rpc_task * void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset); void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset); void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); +size_t rpc_max_payload(struct rpc_clnt *); static __inline__ int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags) Index: linux-2.6.11-rc3/include/linux/sunrpc/xprt.h =================================================================== --- linux-2.6.11-rc3.orig/include/linux/sunrpc/xprt.h +++ linux-2.6.11-rc3/include/linux/sunrpc/xprt.h @@ -140,6 +140,9 @@ struct rpc_xprt { unsigned int rcvsize, /* socket receive buffer size */ sndsize; /* socket send buffer size */ + size_t max_payload; /* largest RPC payload size, + in bytes */ + struct rpc_wait_queue sending; /* requests waiting to send */ struct rpc_wait_queue resend; /* requests waiting to resend */ struct rpc_wait_queue pending; /* requests in flight */ Index: linux-2.6.11-rc3/net/sunrpc/clnt.c =================================================================== --- linux-2.6.11-rc3.orig/net/sunrpc/clnt.c +++ linux-2.6.11-rc3/net/sunrpc/clnt.c @@ -23,6 +23,7 @@ #include +#include #include #include #include @@ -452,6 +453,20 @@ rpc_setbufsize(struct rpc_clnt *clnt, un } /* + * Return size of largest payload RPC client can support, in bytes + * + * For stream transports, this is one RPC record fragment (see RFC + * 1831), as we don't support multi-record requests yet. For datagram + * transports, this is the size of an IP packet minus the IP, UDP, and + * RPC header sizes. + */ +size_t rpc_max_payload(struct rpc_clnt *clnt) +{ + return clnt->cl_xprt->max_payload; +} +EXPORT_SYMBOL(rpc_max_payload); + +/* * Restart an (async) RPC call. Usually called from within the * exit handler. */ Index: linux-2.6.11-rc3/net/sunrpc/xprt.c =================================================================== --- linux-2.6.11-rc3.orig/net/sunrpc/xprt.c +++ linux-2.6.11-rc3/net/sunrpc/xprt.c @@ -1460,8 +1460,11 @@ xprt_setup(int proto, struct sockaddr_in if (xprt->stream) { xprt->cwnd = RPC_MAXCWND(xprt); xprt->nocong = 1; - } else + xprt->max_payload = (1U << 31) - 1; + } else { xprt->cwnd = RPC_INITCWND; + xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); + } spin_lock_init(&xprt->sock_lock); spin_lock_init(&xprt->xprt_lock); init_waitqueue_head(&xprt->cong_wait);