diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-20 17:04:11 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-20 17:04:11 -0500 |
commit | 982197277c85018cc6eb77f1d3bef17933b0c5fd (patch) | |
tree | 805fcef9ec7c1e83867b89332fd37f751594fae3 /net/sunrpc | |
parent | 40889e8d9fc6355980cf2bc94ef4356c10dec4ec (diff) | |
parent | 24ffb93872f7363a01ad639e3c8a9889b46c3f0a (diff) |
Merge branch 'for-3.8' of git://linux-nfs.org/~bfields/linux
Pull nfsd update from Bruce Fields:
"Included this time:
- more nfsd containerization work from Stanislav Kinsbursky: we're
not quite there yet, but should be by 3.9.
- NFSv4.1 progress: implementation of basic backchannel security
negotiation and the mandatory BACKCHANNEL_CTL operation. See
http://wiki.linux-nfs.org/wiki/index.php/Server_4.0_and_4.1_issues
for remaining TODO's
- Fixes for some bugs that could be triggered by unusual compounds.
Our xdr code wasn't designed with v4 compounds in mind, and it
shows. A more thorough rewrite is still a todo.
- If you've ever seen "RPC: multiple fragments per record not
supported" logged while using some sort of odd userland NFS client,
that should now be fixed.
- Further work from Jeff Layton on our mechanism for storing
information about NFSv4 clients across reboots.
- Further work from Bryan Schumaker on his fault-injection mechanism
(which allows us to discard selective NFSv4 state, to excercise
rarely-taken recovery code paths in the client.)
- The usual mix of miscellaneous bugs and cleanup.
Thanks to everyone who tested or contributed this cycle."
* 'for-3.8' of git://linux-nfs.org/~bfields/linux: (111 commits)
nfsd4: don't leave freed stateid hashed
nfsd4: free_stateid can use the current stateid
nfsd4: cleanup: replace rq_resused count by rq_next_page pointer
nfsd: warn on odd reply state in nfsd_vfs_read
nfsd4: fix oops on unusual readlike compound
nfsd4: disable zero-copy on non-final read ops
svcrpc: fix some printks
NFSD: Correct the size calculation in fault_inject_write
NFSD: Pass correct buffer size to rpc_ntop
nfsd: pass proper net to nfsd_destroy() from NFSd kthreads
nfsd: simplify service shutdown
nfsd: replace boolean nfsd_up flag by users counter
nfsd: simplify NFSv4 state init and shutdown
nfsd: introduce helpers for generic resources init and shutdown
nfsd: make NFSd service structure allocated per net
nfsd: make NFSd service boot time per-net
nfsd: per-net NFSd up flag introduced
nfsd: move per-net startup code to separated function
nfsd: pass net to __write_ports() and down
nfsd: pass net to nfsd_set_nrthreads()
...
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 1 | ||||
-rw-r--r-- | net/sunrpc/svc.c | 8 | ||||
-rw-r--r-- | net/sunrpc/svcsock.c | 98 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 10 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/svc_rdma_sendto.c | 4 |
5 files changed, 61 insertions, 60 deletions
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 411f332de0b3..795a0f4e920b 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
24 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/nsproxy.h> | ||
27 | #include <net/ipv6.h> | 26 | #include <net/ipv6.h> |
28 | 27 | ||
29 | #include <linux/sunrpc/clnt.h> | 28 | #include <linux/sunrpc/clnt.h> |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index dfa4ba69ff45..dbf12ac5ecb7 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/kthread.h> | 21 | #include <linux/kthread.h> |
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/nsproxy.h> | ||
24 | 23 | ||
25 | #include <linux/sunrpc/types.h> | 24 | #include <linux/sunrpc/types.h> |
26 | #include <linux/sunrpc/xdr.h> | 25 | #include <linux/sunrpc/xdr.h> |
@@ -1041,7 +1040,7 @@ static void svc_unregister(const struct svc_serv *serv, struct net *net) | |||
1041 | } | 1040 | } |
1042 | 1041 | ||
1043 | /* | 1042 | /* |
1044 | * Printk the given error with the address of the client that caused it. | 1043 | * dprintk the given error with the address of the client that caused it. |
1045 | */ | 1044 | */ |
1046 | static __printf(2, 3) | 1045 | static __printf(2, 3) |
1047 | void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) | 1046 | void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) |
@@ -1055,8 +1054,7 @@ void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) | |||
1055 | vaf.fmt = fmt; | 1054 | vaf.fmt = fmt; |
1056 | vaf.va = &args; | 1055 | vaf.va = &args; |
1057 | 1056 | ||
1058 | net_warn_ratelimited("svc: %s: %pV", | 1057 | dprintk("svc: %s: %pV", svc_print_addr(rqstp, buf, sizeof(buf)), &vaf); |
1059 | svc_print_addr(rqstp, buf, sizeof(buf)), &vaf); | ||
1060 | 1058 | ||
1061 | va_end(args); | 1059 | va_end(args); |
1062 | } | 1060 | } |
@@ -1305,7 +1303,7 @@ svc_process(struct svc_rqst *rqstp) | |||
1305 | * Setup response xdr_buf. | 1303 | * Setup response xdr_buf. |
1306 | * Initially it has just one page | 1304 | * Initially it has just one page |
1307 | */ | 1305 | */ |
1308 | rqstp->rq_resused = 1; | 1306 | rqstp->rq_next_page = &rqstp->rq_respages[1]; |
1309 | resv->iov_base = page_address(rqstp->rq_respages[0]); | 1307 | resv->iov_base = page_address(rqstp->rq_respages[0]); |
1310 | resv->iov_len = 0; | 1308 | resv->iov_len = 0; |
1311 | rqstp->rq_res.pages = rqstp->rq_respages + 1; | 1309 | rqstp->rq_res.pages = rqstp->rq_respages + 1; |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index cc3020d16789..0a148c9d2a5c 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -605,6 +605,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
605 | rqstp->rq_respages = rqstp->rq_pages + 1 + | 605 | rqstp->rq_respages = rqstp->rq_pages + 1 + |
606 | DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE); | 606 | DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE); |
607 | } | 607 | } |
608 | rqstp->rq_next_page = rqstp->rq_respages+1; | ||
608 | 609 | ||
609 | if (serv->sv_stats) | 610 | if (serv->sv_stats) |
610 | serv->sv_stats->netudpcnt++; | 611 | serv->sv_stats->netudpcnt++; |
@@ -878,9 +879,9 @@ static unsigned int svc_tcp_restore_pages(struct svc_sock *svsk, struct svc_rqst | |||
878 | { | 879 | { |
879 | unsigned int i, len, npages; | 880 | unsigned int i, len, npages; |
880 | 881 | ||
881 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | 882 | if (svsk->sk_datalen == 0) |
882 | return 0; | 883 | return 0; |
883 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | 884 | len = svsk->sk_datalen; |
884 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 885 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
885 | for (i = 0; i < npages; i++) { | 886 | for (i = 0; i < npages; i++) { |
886 | if (rqstp->rq_pages[i] != NULL) | 887 | if (rqstp->rq_pages[i] != NULL) |
@@ -897,9 +898,9 @@ static void svc_tcp_save_pages(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
897 | { | 898 | { |
898 | unsigned int i, len, npages; | 899 | unsigned int i, len, npages; |
899 | 900 | ||
900 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | 901 | if (svsk->sk_datalen == 0) |
901 | return; | 902 | return; |
902 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | 903 | len = svsk->sk_datalen; |
903 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 904 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
904 | for (i = 0; i < npages; i++) { | 905 | for (i = 0; i < npages; i++) { |
905 | svsk->sk_pages[i] = rqstp->rq_pages[i]; | 906 | svsk->sk_pages[i] = rqstp->rq_pages[i]; |
@@ -911,9 +912,9 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk) | |||
911 | { | 912 | { |
912 | unsigned int i, len, npages; | 913 | unsigned int i, len, npages; |
913 | 914 | ||
914 | if (svsk->sk_tcplen <= sizeof(rpc_fraghdr)) | 915 | if (svsk->sk_datalen == 0) |
915 | goto out; | 916 | goto out; |
916 | len = svsk->sk_tcplen - sizeof(rpc_fraghdr); | 917 | len = svsk->sk_datalen; |
917 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 918 | npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
918 | for (i = 0; i < npages; i++) { | 919 | for (i = 0; i < npages; i++) { |
919 | BUG_ON(svsk->sk_pages[i] == NULL); | 920 | BUG_ON(svsk->sk_pages[i] == NULL); |
@@ -922,13 +923,12 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk) | |||
922 | } | 923 | } |
923 | out: | 924 | out: |
924 | svsk->sk_tcplen = 0; | 925 | svsk->sk_tcplen = 0; |
926 | svsk->sk_datalen = 0; | ||
925 | } | 927 | } |
926 | 928 | ||
927 | /* | 929 | /* |
928 | * Receive data. | 930 | * Receive fragment record header. |
929 | * If we haven't gotten the record length yet, get the next four bytes. | 931 | * If we haven't gotten the record length yet, get the next four bytes. |
930 | * Otherwise try to gobble up as much as possible up to the complete | ||
931 | * record length. | ||
932 | */ | 932 | */ |
933 | static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) | 933 | static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) |
934 | { | 934 | { |
@@ -954,32 +954,16 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
954 | return -EAGAIN; | 954 | return -EAGAIN; |
955 | } | 955 | } |
956 | 956 | ||
957 | svsk->sk_reclen = ntohl(svsk->sk_reclen); | 957 | dprintk("svc: TCP record, %d bytes\n", svc_sock_reclen(svsk)); |
958 | if (!(svsk->sk_reclen & RPC_LAST_STREAM_FRAGMENT)) { | 958 | if (svc_sock_reclen(svsk) + svsk->sk_datalen > |
959 | /* FIXME: technically, a record can be fragmented, | 959 | serv->sv_max_mesg) { |
960 | * and non-terminal fragments will not have the top | 960 | net_notice_ratelimited("RPC: fragment too large: %d\n", |
961 | * bit set in the fragment length header. | 961 | svc_sock_reclen(svsk)); |
962 | * But apparently no known nfs clients send fragmented | ||
963 | * records. */ | ||
964 | net_notice_ratelimited("RPC: multiple fragments per record not supported\n"); | ||
965 | goto err_delete; | ||
966 | } | ||
967 | |||
968 | svsk->sk_reclen &= RPC_FRAGMENT_SIZE_MASK; | ||
969 | dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen); | ||
970 | if (svsk->sk_reclen > serv->sv_max_mesg) { | ||
971 | net_notice_ratelimited("RPC: fragment too large: 0x%08lx\n", | ||
972 | (unsigned long)svsk->sk_reclen); | ||
973 | goto err_delete; | 962 | goto err_delete; |
974 | } | 963 | } |
975 | } | 964 | } |
976 | 965 | ||
977 | if (svsk->sk_reclen < 8) | 966 | return svc_sock_reclen(svsk); |
978 | goto err_delete; /* client is nuts. */ | ||
979 | |||
980 | len = svsk->sk_reclen; | ||
981 | |||
982 | return len; | ||
983 | error: | 967 | error: |
984 | dprintk("RPC: TCP recv_record got %d\n", len); | 968 | dprintk("RPC: TCP recv_record got %d\n", len); |
985 | return len; | 969 | return len; |
@@ -1023,7 +1007,7 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
1023 | if (dst->iov_len < src->iov_len) | 1007 | if (dst->iov_len < src->iov_len) |
1024 | return -EAGAIN; /* whatever; just giving up. */ | 1008 | return -EAGAIN; /* whatever; just giving up. */ |
1025 | memcpy(dst->iov_base, src->iov_base, src->iov_len); | 1009 | memcpy(dst->iov_base, src->iov_base, src->iov_len); |
1026 | xprt_complete_rqst(req->rq_task, svsk->sk_reclen); | 1010 | xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len); |
1027 | rqstp->rq_arg.len = 0; | 1011 | rqstp->rq_arg.len = 0; |
1028 | return 0; | 1012 | return 0; |
1029 | } | 1013 | } |
@@ -1042,6 +1026,17 @@ static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len) | |||
1042 | return i; | 1026 | return i; |
1043 | } | 1027 | } |
1044 | 1028 | ||
1029 | static void svc_tcp_fragment_received(struct svc_sock *svsk) | ||
1030 | { | ||
1031 | /* If we have more data, signal svc_xprt_enqueue() to try again */ | ||
1032 | if (svc_recv_available(svsk) > sizeof(rpc_fraghdr)) | ||
1033 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); | ||
1034 | dprintk("svc: TCP %s record (%d bytes)\n", | ||
1035 | svc_sock_final_rec(svsk) ? "final" : "nonfinal", | ||
1036 | svc_sock_reclen(svsk)); | ||
1037 | svsk->sk_tcplen = 0; | ||
1038 | svsk->sk_reclen = 0; | ||
1039 | } | ||
1045 | 1040 | ||
1046 | /* | 1041 | /* |
1047 | * Receive data from a TCP socket. | 1042 | * Receive data from a TCP socket. |
@@ -1068,29 +1063,39 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
1068 | goto error; | 1063 | goto error; |
1069 | 1064 | ||
1070 | base = svc_tcp_restore_pages(svsk, rqstp); | 1065 | base = svc_tcp_restore_pages(svsk, rqstp); |
1071 | want = svsk->sk_reclen - base; | 1066 | want = svc_sock_reclen(svsk) - (svsk->sk_tcplen - sizeof(rpc_fraghdr)); |
1072 | 1067 | ||
1073 | vec = rqstp->rq_vec; | 1068 | vec = rqstp->rq_vec; |
1074 | 1069 | ||
1075 | pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], | 1070 | pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0], |
1076 | svsk->sk_reclen); | 1071 | svsk->sk_datalen + want); |
1077 | 1072 | ||
1078 | rqstp->rq_respages = &rqstp->rq_pages[pnum]; | 1073 | rqstp->rq_respages = &rqstp->rq_pages[pnum]; |
1074 | rqstp->rq_next_page = rqstp->rq_respages + 1; | ||
1079 | 1075 | ||
1080 | /* Now receive data */ | 1076 | /* Now receive data */ |
1081 | len = svc_partial_recvfrom(rqstp, vec, pnum, want, base); | 1077 | len = svc_partial_recvfrom(rqstp, vec, pnum, want, base); |
1082 | if (len >= 0) | 1078 | if (len >= 0) { |
1083 | svsk->sk_tcplen += len; | 1079 | svsk->sk_tcplen += len; |
1084 | if (len != want) { | 1080 | svsk->sk_datalen += len; |
1081 | } | ||
1082 | if (len != want || !svc_sock_final_rec(svsk)) { | ||
1085 | svc_tcp_save_pages(svsk, rqstp); | 1083 | svc_tcp_save_pages(svsk, rqstp); |
1086 | if (len < 0 && len != -EAGAIN) | 1084 | if (len < 0 && len != -EAGAIN) |
1087 | goto err_other; | 1085 | goto err_delete; |
1088 | dprintk("svc: incomplete TCP record (%d of %d)\n", | 1086 | if (len == want) |
1089 | svsk->sk_tcplen, svsk->sk_reclen); | 1087 | svc_tcp_fragment_received(svsk); |
1088 | else | ||
1089 | dprintk("svc: incomplete TCP record (%d of %d)\n", | ||
1090 | (int)(svsk->sk_tcplen - sizeof(rpc_fraghdr)), | ||
1091 | svc_sock_reclen(svsk)); | ||
1090 | goto err_noclose; | 1092 | goto err_noclose; |
1091 | } | 1093 | } |
1092 | 1094 | ||
1093 | rqstp->rq_arg.len = svsk->sk_reclen; | 1095 | if (svc_sock_reclen(svsk) < 8) |
1096 | goto err_delete; /* client is nuts. */ | ||
1097 | |||
1098 | rqstp->rq_arg.len = svsk->sk_datalen; | ||
1094 | rqstp->rq_arg.page_base = 0; | 1099 | rqstp->rq_arg.page_base = 0; |
1095 | if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { | 1100 | if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) { |
1096 | rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; | 1101 | rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len; |
@@ -1107,11 +1112,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
1107 | len = receive_cb_reply(svsk, rqstp); | 1112 | len = receive_cb_reply(svsk, rqstp); |
1108 | 1113 | ||
1109 | /* Reset TCP read info */ | 1114 | /* Reset TCP read info */ |
1110 | svsk->sk_reclen = 0; | 1115 | svsk->sk_datalen = 0; |
1111 | svsk->sk_tcplen = 0; | 1116 | svc_tcp_fragment_received(svsk); |
1112 | /* If we have more data, signal svc_xprt_enqueue() to try again */ | ||
1113 | if (svc_recv_available(svsk) > sizeof(rpc_fraghdr)) | ||
1114 | set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags); | ||
1115 | 1117 | ||
1116 | if (len < 0) | 1118 | if (len < 0) |
1117 | goto error; | 1119 | goto error; |
@@ -1120,15 +1122,14 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) | |||
1120 | if (serv->sv_stats) | 1122 | if (serv->sv_stats) |
1121 | serv->sv_stats->nettcpcnt++; | 1123 | serv->sv_stats->nettcpcnt++; |
1122 | 1124 | ||
1123 | dprintk("svc: TCP complete record (%d bytes)\n", rqstp->rq_arg.len); | ||
1124 | return rqstp->rq_arg.len; | 1125 | return rqstp->rq_arg.len; |
1125 | 1126 | ||
1126 | error: | 1127 | error: |
1127 | if (len != -EAGAIN) | 1128 | if (len != -EAGAIN) |
1128 | goto err_other; | 1129 | goto err_delete; |
1129 | dprintk("RPC: TCP recvfrom got EAGAIN\n"); | 1130 | dprintk("RPC: TCP recvfrom got EAGAIN\n"); |
1130 | return 0; | 1131 | return 0; |
1131 | err_other: | 1132 | err_delete: |
1132 | printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", | 1133 | printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", |
1133 | svsk->sk_xprt.xpt_server->sv_name, -len); | 1134 | svsk->sk_xprt.xpt_server->sv_name, -len); |
1134 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); | 1135 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); |
@@ -1305,6 +1306,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv) | |||
1305 | 1306 | ||
1306 | svsk->sk_reclen = 0; | 1307 | svsk->sk_reclen = 0; |
1307 | svsk->sk_tcplen = 0; | 1308 | svsk->sk_tcplen = 0; |
1309 | svsk->sk_datalen = 0; | ||
1308 | memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages)); | 1310 | memset(&svsk->sk_pages[0], 0, sizeof(svsk->sk_pages)); |
1309 | 1311 | ||
1310 | tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF; | 1312 | tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF; |
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 41cb63b623df..0ce75524ed21 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | |||
@@ -521,11 +521,11 @@ next_sge: | |||
521 | rqstp->rq_pages[ch_no] = NULL; | 521 | rqstp->rq_pages[ch_no] = NULL; |
522 | 522 | ||
523 | /* | 523 | /* |
524 | * Detach res pages. svc_release must see a resused count of | 524 | * Detach res pages. If svc_release sees any it will attempt to |
525 | * zero or it will attempt to put them. | 525 | * put them. |
526 | */ | 526 | */ |
527 | while (rqstp->rq_resused) | 527 | while (rqstp->rq_next_page != rqstp->rq_respages) |
528 | rqstp->rq_respages[--rqstp->rq_resused] = NULL; | 528 | *(--rqstp->rq_next_page) = NULL; |
529 | 529 | ||
530 | return err; | 530 | return err; |
531 | } | 531 | } |
@@ -550,7 +550,7 @@ static int rdma_read_complete(struct svc_rqst *rqstp, | |||
550 | 550 | ||
551 | /* rq_respages starts after the last arg page */ | 551 | /* rq_respages starts after the last arg page */ |
552 | rqstp->rq_respages = &rqstp->rq_arg.pages[page_no]; | 552 | rqstp->rq_respages = &rqstp->rq_arg.pages[page_no]; |
553 | rqstp->rq_resused = 0; | 553 | rqstp->rq_next_page = &rqstp->rq_arg.pages[page_no]; |
554 | 554 | ||
555 | /* Rebuild rq_arg head and tail. */ | 555 | /* Rebuild rq_arg head and tail. */ |
556 | rqstp->rq_arg.head[0] = head->arg.head[0]; | 556 | rqstp->rq_arg.head[0] = head->arg.head[0]; |
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 42eb7ba0b903..c1d124dc772b 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c | |||
@@ -548,6 +548,7 @@ static int send_reply(struct svcxprt_rdma *rdma, | |||
548 | int sge_no; | 548 | int sge_no; |
549 | int sge_bytes; | 549 | int sge_bytes; |
550 | int page_no; | 550 | int page_no; |
551 | int pages; | ||
551 | int ret; | 552 | int ret; |
552 | 553 | ||
553 | /* Post a recv buffer to handle another request. */ | 554 | /* Post a recv buffer to handle another request. */ |
@@ -611,7 +612,8 @@ static int send_reply(struct svcxprt_rdma *rdma, | |||
611 | * respages array. They are our pages until the I/O | 612 | * respages array. They are our pages until the I/O |
612 | * completes. | 613 | * completes. |
613 | */ | 614 | */ |
614 | for (page_no = 0; page_no < rqstp->rq_resused; page_no++) { | 615 | pages = rqstp->rq_next_page - rqstp->rq_respages; |
616 | for (page_no = 0; page_no < pages; page_no++) { | ||
615 | ctxt->pages[page_no+1] = rqstp->rq_respages[page_no]; | 617 | ctxt->pages[page_no+1] = rqstp->rq_respages[page_no]; |
616 | ctxt->count++; | 618 | ctxt->count++; |
617 | rqstp->rq_respages[page_no] = NULL; | 619 | rqstp->rq_respages[page_no] = NULL; |