svc: Add transport hdr size for defer/revisit

Some transports have a header in front of the RPC header. The current
defer/revisit processing considers only the iov_len and arg_len to
determine how much to back up when saving the original request
to revisit. Add a field to the rqstp structure to save the size
of the transport header so svc_defer can correctly compute
the start of a request.

Signed-off-by: Tom Tucker <tom@opengridcomputing.com>
Acked-by: Neil Brown <neilb@suse.de>
Reviewed-by: Chuck Lever <chuck.lever@oracle.com>
Reviewed-by: Greg Banks <gnb@sgi.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>

authored by Tom Tucker and committed by J. Bruce Fields 260c1d12 0f0257ea

+31 -9
+2
include/linux/sunrpc/svc.h
··· 217 void * rq_xprt_ctxt; /* transport specific context ptr */ 218 struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */ 219 220 struct xdr_buf rq_arg; 221 struct xdr_buf rq_res; 222 struct page * rq_pages[RPCSVC_MAXPAGES]; ··· 323 size_t addrlen; 324 union svc_addr_u daddr; /* where reply must come from */ 325 struct cache_deferred_req handle; 326 int argslen; 327 __be32 args[0]; 328 };
··· 217 void * rq_xprt_ctxt; /* transport specific context ptr */ 218 struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */ 219 220 + size_t rq_xprt_hlen; /* xprt header len */ 221 struct xdr_buf rq_arg; 222 struct xdr_buf rq_res; 223 struct page * rq_pages[RPCSVC_MAXPAGES]; ··· 322 size_t addrlen; 323 union svc_addr_u daddr; /* where reply must come from */ 324 struct cache_deferred_req handle; 325 + size_t xprt_hlen; 326 int argslen; 327 __be32 args[0]; 328 };
+27 -9
net/sunrpc/svc_xprt.c
··· 29 #include <linux/sunrpc/types.h> 30 #include <linux/sunrpc/clnt.h> 31 #include <linux/sunrpc/xdr.h> 32 - #include <linux/sunrpc/svcsock.h> 33 #include <linux/sunrpc/stats.h> 34 #include <linux/sunrpc/svc_xprt.h> 35 ··· 858 svc_xprt_put(xprt); 859 } 860 861 static struct cache_deferred_req *svc_defer(struct cache_req *req) 862 { 863 struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle); 864 - int size = sizeof(struct svc_deferred_req) + (rqstp->rq_arg.len); 865 struct svc_deferred_req *dr; 866 867 if (rqstp->rq_arg.page_len) ··· 878 dr = rqstp->rq_deferred; 879 rqstp->rq_deferred = NULL; 880 } else { 881 - int skip = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len; 882 /* FIXME maybe discard if size too large */ 883 dr = kmalloc(size, GFP_KERNEL); 884 if (dr == NULL) 885 return NULL; ··· 892 dr->addrlen = rqstp->rq_addrlen; 893 dr->daddr = rqstp->rq_daddr; 894 dr->argslen = rqstp->rq_arg.len >> 2; 895 - memcpy(dr->args, rqstp->rq_arg.head[0].iov_base-skip, 896 - dr->argslen<<2); 897 } 898 svc_xprt_get(rqstp->rq_xprt); 899 dr->xprt = rqstp->rq_xprt; ··· 913 { 914 struct svc_deferred_req *dr = rqstp->rq_deferred; 915 916 - rqstp->rq_arg.head[0].iov_base = dr->args; 917 - rqstp->rq_arg.head[0].iov_len = dr->argslen<<2; 918 rqstp->rq_arg.page_len = 0; 919 - rqstp->rq_arg.len = dr->argslen<<2; 920 rqstp->rq_prot = dr->prot; 921 memcpy(&rqstp->rq_addr, &dr->addr, dr->addrlen); 922 rqstp->rq_addrlen = dr->addrlen; 923 rqstp->rq_daddr = dr->daddr; 924 rqstp->rq_respages = rqstp->rq_pages; 925 - return dr->argslen<<2; 926 } 927 928
··· 29 #include <linux/sunrpc/types.h> 30 #include <linux/sunrpc/clnt.h> 31 #include <linux/sunrpc/xdr.h> 32 #include <linux/sunrpc/stats.h> 33 #include <linux/sunrpc/svc_xprt.h> 34 ··· 859 svc_xprt_put(xprt); 860 } 861 862 + /* 863 + * Save the request off for later processing. The request buffer looks 864 + * like this: 865 + * 866 + * <xprt-header><rpc-header><rpc-pagelist><rpc-tail> 867 + * 868 + * This code can only handle requests that consist of an xprt-header 869 + * and rpc-header. 870 + */ 871 static struct cache_deferred_req *svc_defer(struct cache_req *req) 872 { 873 struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle); 874 struct svc_deferred_req *dr; 875 876 if (rqstp->rq_arg.page_len) ··· 871 dr = rqstp->rq_deferred; 872 rqstp->rq_deferred = NULL; 873 } else { 874 + size_t skip; 875 + size_t size; 876 /* FIXME maybe discard if size too large */ 877 + size = sizeof(struct svc_deferred_req) + rqstp->rq_arg.len; 878 dr = kmalloc(size, GFP_KERNEL); 879 if (dr == NULL) 880 return NULL; ··· 883 dr->addrlen = rqstp->rq_addrlen; 884 dr->daddr = rqstp->rq_daddr; 885 dr->argslen = rqstp->rq_arg.len >> 2; 886 + dr->xprt_hlen = rqstp->rq_xprt_hlen; 887 + 888 + /* back up head to the start of the buffer and copy */ 889 + skip = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len; 890 + memcpy(dr->args, rqstp->rq_arg.head[0].iov_base - skip, 891 + dr->argslen << 2); 892 } 893 svc_xprt_get(rqstp->rq_xprt); 894 dr->xprt = rqstp->rq_xprt; ··· 900 { 901 struct svc_deferred_req *dr = rqstp->rq_deferred; 902 903 + /* setup iov_base past transport header */ 904 + rqstp->rq_arg.head[0].iov_base = dr->args + (dr->xprt_hlen>>2); 905 + /* The iov_len does not include the transport header bytes */ 906 + rqstp->rq_arg.head[0].iov_len = (dr->argslen<<2) - dr->xprt_hlen; 907 rqstp->rq_arg.page_len = 0; 908 + /* The rq_arg.len includes the transport header bytes */ 909 + rqstp->rq_arg.len = dr->argslen<<2; 910 rqstp->rq_prot = dr->prot; 911 memcpy(&rqstp->rq_addr, &dr->addr, dr->addrlen); 912 rqstp->rq_addrlen = dr->addrlen; 913 + /* Save off transport header len in case we get deferred again */ 914 + rqstp->rq_xprt_hlen = dr->xprt_hlen; 915 rqstp->rq_daddr = dr->daddr; 916 rqstp->rq_respages = rqstp->rq_pages; 917 + return (dr->argslen<<2) - dr->xprt_hlen; 918 } 919 920
+2
net/sunrpc/svcsock.c
··· 315 }; 316 int len; 317 318 len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen, 319 msg.msg_flags); 320
··· 315 }; 316 int len; 317 318 + rqstp->rq_xprt_hlen = 0; 319 + 320 len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen, 321 msg.msg_flags); 322