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 217 void * rq_xprt_ctxt; /* transport specific context ptr */ 218 218 struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */ 219 219 220 + size_t rq_xprt_hlen; /* xprt header len */ 220 221 struct xdr_buf rq_arg; 221 222 struct xdr_buf rq_res; 222 223 struct page * rq_pages[RPCSVC_MAXPAGES]; ··· 323 322 size_t addrlen; 324 323 union svc_addr_u daddr; /* where reply must come from */ 325 324 struct cache_deferred_req handle; 325 + size_t xprt_hlen; 326 326 int argslen; 327 327 __be32 args[0]; 328 328 };
+27 -9
net/sunrpc/svc_xprt.c
··· 29 29 #include <linux/sunrpc/types.h> 30 30 #include <linux/sunrpc/clnt.h> 31 31 #include <linux/sunrpc/xdr.h> 32 - #include <linux/sunrpc/svcsock.h> 33 32 #include <linux/sunrpc/stats.h> 34 33 #include <linux/sunrpc/svc_xprt.h> 35 34 ··· 858 859 svc_xprt_put(xprt); 859 860 } 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 + */ 861 871 static struct cache_deferred_req *svc_defer(struct cache_req *req) 862 872 { 863 873 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 874 struct svc_deferred_req *dr; 866 875 867 876 if (rqstp->rq_arg.page_len) ··· 878 871 dr = rqstp->rq_deferred; 879 872 rqstp->rq_deferred = NULL; 880 873 } else { 881 - int skip = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len; 874 + size_t skip; 875 + size_t size; 882 876 /* FIXME maybe discard if size too large */ 877 + size = sizeof(struct svc_deferred_req) + rqstp->rq_arg.len; 883 878 dr = kmalloc(size, GFP_KERNEL); 884 879 if (dr == NULL) 885 880 return NULL; ··· 892 883 dr->addrlen = rqstp->rq_addrlen; 893 884 dr->daddr = rqstp->rq_daddr; 894 885 dr->argslen = rqstp->rq_arg.len >> 2; 895 - memcpy(dr->args, rqstp->rq_arg.head[0].iov_base-skip, 896 - dr->argslen<<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); 897 892 } 898 893 svc_xprt_get(rqstp->rq_xprt); 899 894 dr->xprt = rqstp->rq_xprt; ··· 913 900 { 914 901 struct svc_deferred_req *dr = rqstp->rq_deferred; 915 902 916 - rqstp->rq_arg.head[0].iov_base = dr->args; 917 - rqstp->rq_arg.head[0].iov_len = dr->argslen<<2; 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; 918 907 rqstp->rq_arg.page_len = 0; 919 - rqstp->rq_arg.len = dr->argslen<<2; 908 + /* The rq_arg.len includes the transport header bytes */ 909 + rqstp->rq_arg.len = dr->argslen<<2; 920 910 rqstp->rq_prot = dr->prot; 921 911 memcpy(&rqstp->rq_addr, &dr->addr, dr->addrlen); 922 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; 923 915 rqstp->rq_daddr = dr->daddr; 924 916 rqstp->rq_respages = rqstp->rq_pages; 925 - return dr->argslen<<2; 917 + return (dr->argslen<<2) - dr->xprt_hlen; 926 918 } 927 919 928 920
+2
net/sunrpc/svcsock.c
··· 315 315 }; 316 316 int len; 317 317 318 + rqstp->rq_xprt_hlen = 0; 319 + 318 320 len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen, 319 321 msg.msg_flags); 320 322