diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/svc_xprt.c | 36 | ||||
-rw-r--r-- | net/sunrpc/svcsock.c | 2 |
2 files changed, 29 insertions, 9 deletions
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 23165aef59d9..000c7dc3b82c 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
@@ -29,7 +29,6 @@ | |||
29 | #include <linux/sunrpc/types.h> | 29 | #include <linux/sunrpc/types.h> |
30 | #include <linux/sunrpc/clnt.h> | 30 | #include <linux/sunrpc/clnt.h> |
31 | #include <linux/sunrpc/xdr.h> | 31 | #include <linux/sunrpc/xdr.h> |
32 | #include <linux/sunrpc/svcsock.h> | ||
33 | #include <linux/sunrpc/stats.h> | 32 | #include <linux/sunrpc/stats.h> |
34 | #include <linux/sunrpc/svc_xprt.h> | 33 | #include <linux/sunrpc/svc_xprt.h> |
35 | 34 | ||
@@ -859,10 +858,18 @@ static void svc_revisit(struct cache_deferred_req *dreq, int too_many) | |||
859 | svc_xprt_put(xprt); | 858 | svc_xprt_put(xprt); |
860 | } | 859 | } |
861 | 860 | ||
861 | /* | ||
862 | * Save the request off for later processing. The request buffer looks | ||
863 | * like this: | ||
864 | * | ||
865 | * <xprt-header><rpc-header><rpc-pagelist><rpc-tail> | ||
866 | * | ||
867 | * This code can only handle requests that consist of an xprt-header | ||
868 | * and rpc-header. | ||
869 | */ | ||
862 | static struct cache_deferred_req *svc_defer(struct cache_req *req) | 870 | static struct cache_deferred_req *svc_defer(struct cache_req *req) |
863 | { | 871 | { |
864 | struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle); | 872 | struct svc_rqst *rqstp = container_of(req, struct svc_rqst, rq_chandle); |
865 | int size = sizeof(struct svc_deferred_req) + (rqstp->rq_arg.len); | ||
866 | struct svc_deferred_req *dr; | 873 | struct svc_deferred_req *dr; |
867 | 874 | ||
868 | if (rqstp->rq_arg.page_len) | 875 | if (rqstp->rq_arg.page_len) |
@@ -871,8 +878,10 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req) | |||
871 | dr = rqstp->rq_deferred; | 878 | dr = rqstp->rq_deferred; |
872 | rqstp->rq_deferred = NULL; | 879 | rqstp->rq_deferred = NULL; |
873 | } else { | 880 | } else { |
874 | int skip = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len; | 881 | size_t skip; |
882 | size_t size; | ||
875 | /* FIXME maybe discard if size too large */ | 883 | /* FIXME maybe discard if size too large */ |
884 | size = sizeof(struct svc_deferred_req) + rqstp->rq_arg.len; | ||
876 | dr = kmalloc(size, GFP_KERNEL); | 885 | dr = kmalloc(size, GFP_KERNEL); |
877 | if (dr == NULL) | 886 | if (dr == NULL) |
878 | return NULL; | 887 | return NULL; |
@@ -883,8 +892,12 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req) | |||
883 | dr->addrlen = rqstp->rq_addrlen; | 892 | dr->addrlen = rqstp->rq_addrlen; |
884 | dr->daddr = rqstp->rq_daddr; | 893 | dr->daddr = rqstp->rq_daddr; |
885 | dr->argslen = rqstp->rq_arg.len >> 2; | 894 | dr->argslen = rqstp->rq_arg.len >> 2; |
886 | memcpy(dr->args, rqstp->rq_arg.head[0].iov_base-skip, | 895 | dr->xprt_hlen = rqstp->rq_xprt_hlen; |
887 | dr->argslen<<2); | 896 | |
897 | /* back up head to the start of the buffer and copy */ | ||
898 | skip = rqstp->rq_arg.len - rqstp->rq_arg.head[0].iov_len; | ||
899 | memcpy(dr->args, rqstp->rq_arg.head[0].iov_base - skip, | ||
900 | dr->argslen << 2); | ||
888 | } | 901 | } |
889 | svc_xprt_get(rqstp->rq_xprt); | 902 | svc_xprt_get(rqstp->rq_xprt); |
890 | dr->xprt = rqstp->rq_xprt; | 903 | dr->xprt = rqstp->rq_xprt; |
@@ -900,16 +913,21 @@ static int svc_deferred_recv(struct svc_rqst *rqstp) | |||
900 | { | 913 | { |
901 | struct svc_deferred_req *dr = rqstp->rq_deferred; | 914 | struct svc_deferred_req *dr = rqstp->rq_deferred; |
902 | 915 | ||
903 | rqstp->rq_arg.head[0].iov_base = dr->args; | 916 | /* setup iov_base past transport header */ |
904 | rqstp->rq_arg.head[0].iov_len = dr->argslen<<2; | 917 | rqstp->rq_arg.head[0].iov_base = dr->args + (dr->xprt_hlen>>2); |
918 | /* The iov_len does not include the transport header bytes */ | ||
919 | rqstp->rq_arg.head[0].iov_len = (dr->argslen<<2) - dr->xprt_hlen; | ||
905 | rqstp->rq_arg.page_len = 0; | 920 | rqstp->rq_arg.page_len = 0; |
906 | rqstp->rq_arg.len = dr->argslen<<2; | 921 | /* The rq_arg.len includes the transport header bytes */ |
922 | rqstp->rq_arg.len = dr->argslen<<2; | ||
907 | rqstp->rq_prot = dr->prot; | 923 | rqstp->rq_prot = dr->prot; |
908 | memcpy(&rqstp->rq_addr, &dr->addr, dr->addrlen); | 924 | memcpy(&rqstp->rq_addr, &dr->addr, dr->addrlen); |
909 | rqstp->rq_addrlen = dr->addrlen; | 925 | rqstp->rq_addrlen = dr->addrlen; |
926 | /* Save off transport header len in case we get deferred again */ | ||
927 | rqstp->rq_xprt_hlen = dr->xprt_hlen; | ||
910 | rqstp->rq_daddr = dr->daddr; | 928 | rqstp->rq_daddr = dr->daddr; |
911 | rqstp->rq_respages = rqstp->rq_pages; | 929 | rqstp->rq_respages = rqstp->rq_pages; |
912 | return dr->argslen<<2; | 930 | return (dr->argslen<<2) - dr->xprt_hlen; |
913 | } | 931 | } |
914 | 932 | ||
915 | 933 | ||
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 343a85b700f0..1d3e5fcc2cc4 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -315,6 +315,8 @@ static int svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr, | |||
315 | }; | 315 | }; |
316 | int len; | 316 | int len; |
317 | 317 | ||
318 | rqstp->rq_xprt_hlen = 0; | ||
319 | |||
318 | len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen, | 320 | len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen, |
319 | msg.msg_flags); | 321 | msg.msg_flags); |
320 | 322 | ||