diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-17 20:40:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-17 20:40:00 -0400 |
commit | 179198373cf374f0ef793f1023c1cdd83b53674d (patch) | |
tree | 9c7f9e82b936864b9d8cf91b3d4121a3c8d2671c /net/sunrpc | |
parent | 374e55251cacfb68d331bb8a574b2de8160aacc2 (diff) | |
parent | 8e26de238fd794c8ea56a5c98bf67c40cfeb051d (diff) |
Merge branch 'nfs-for-2.6.39' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* 'nfs-for-2.6.39' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6: (54 commits)
RPC: killing RPC tasks races fixed
xprt: remove redundant check
SUNRPC: Convert struct rpc_xprt to use atomic_t counters
SUNRPC: Ensure we always run the tk_callback before tk_action
sunrpc: fix printk format warning
xprt: remove redundant null check
nfs: BKL is no longer needed, so remove the include
NFS: Fix a warning in fs/nfs/idmap.c
Cleanup: Factor out some cut-and-paste code.
cleanup: save 60 lines/100 bytes by combining two mostly duplicate functions.
NFS: account direct-io into task io accounting
gss:krb5 only include enctype numbers in gm_upcall_enctypes
RPCRDMA: Fix FRMR registration/invalidate handling.
RPCRDMA: Fix to XDR page base interpretation in marshalling logic.
NFSv4: Send unmapped uid/gids to the server when using auth_sys
NFSv4: Propagate the error NFS4ERR_BADOWNER to nfs4_do_setattr
NFSv4: cleanup idmapper functions to take an nfs_server argument
NFSv4: Send unmapped uid/gids to the server if the idmapper fails
NFSv4: If the server sends us a numeric uid/gid then accept it
NFSv4.1: reject zero layout with zeroed stripe unit
...
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 2 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_mech.c | 2 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 18 | ||||
-rw-r--r-- | net/sunrpc/sched.c | 29 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 25 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/rpc_rdma.c | 86 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/verbs.c | 53 | ||||
-rw-r--r-- | net/sunrpc/xprtrdma/xprt_rdma.h | 1 |
8 files changed, 120 insertions, 96 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 45dbf1521b9a..f3914d0c5079 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -417,7 +417,7 @@ static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, | |||
417 | gss_msg->msg.len += len; | 417 | gss_msg->msg.len += len; |
418 | } | 418 | } |
419 | if (mech->gm_upcall_enctypes) { | 419 | if (mech->gm_upcall_enctypes) { |
420 | len = sprintf(p, mech->gm_upcall_enctypes); | 420 | len = sprintf(p, "enctypes=%s ", mech->gm_upcall_enctypes); |
421 | p += len; | 421 | p += len; |
422 | gss_msg->msg.len += len; | 422 | gss_msg->msg.len += len; |
423 | } | 423 | } |
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index f375decc024b..9022f0a6503e 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c | |||
@@ -750,7 +750,7 @@ static struct gss_api_mech gss_kerberos_mech = { | |||
750 | .gm_ops = &gss_kerberos_ops, | 750 | .gm_ops = &gss_kerberos_ops, |
751 | .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), | 751 | .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), |
752 | .gm_pfs = gss_kerberos_pfs, | 752 | .gm_pfs = gss_kerberos_pfs, |
753 | .gm_upcall_enctypes = "enctypes=18,17,16,23,3,1,2 ", | 753 | .gm_upcall_enctypes = "18,17,16,23,3,1,2", |
754 | }; | 754 | }; |
755 | 755 | ||
756 | static int __init init_kerberos_module(void) | 756 | static int __init init_kerberos_module(void) |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 57d344cf2256..e7a96e478f63 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -436,7 +436,9 @@ void rpc_killall_tasks(struct rpc_clnt *clnt) | |||
436 | if (!(rovr->tk_flags & RPC_TASK_KILLED)) { | 436 | if (!(rovr->tk_flags & RPC_TASK_KILLED)) { |
437 | rovr->tk_flags |= RPC_TASK_KILLED; | 437 | rovr->tk_flags |= RPC_TASK_KILLED; |
438 | rpc_exit(rovr, -EIO); | 438 | rpc_exit(rovr, -EIO); |
439 | rpc_wake_up_queued_task(rovr->tk_waitqueue, rovr); | 439 | if (RPC_IS_QUEUED(rovr)) |
440 | rpc_wake_up_queued_task(rovr->tk_waitqueue, | ||
441 | rovr); | ||
440 | } | 442 | } |
441 | } | 443 | } |
442 | spin_unlock(&clnt->cl_lock); | 444 | spin_unlock(&clnt->cl_lock); |
@@ -597,6 +599,14 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt) | |||
597 | } | 599 | } |
598 | } | 600 | } |
599 | 601 | ||
602 | void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt) | ||
603 | { | ||
604 | rpc_task_release_client(task); | ||
605 | rpc_task_set_client(task, clnt); | ||
606 | } | ||
607 | EXPORT_SYMBOL_GPL(rpc_task_reset_client); | ||
608 | |||
609 | |||
600 | static void | 610 | static void |
601 | rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg) | 611 | rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg) |
602 | { | 612 | { |
@@ -636,12 +646,6 @@ struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data) | |||
636 | rpc_task_set_client(task, task_setup_data->rpc_client); | 646 | rpc_task_set_client(task, task_setup_data->rpc_client); |
637 | rpc_task_set_rpc_message(task, task_setup_data->rpc_message); | 647 | rpc_task_set_rpc_message(task, task_setup_data->rpc_message); |
638 | 648 | ||
639 | if (task->tk_status != 0) { | ||
640 | int ret = task->tk_status; | ||
641 | rpc_put_task(task); | ||
642 | return ERR_PTR(ret); | ||
643 | } | ||
644 | |||
645 | if (task->tk_action == NULL) | 649 | if (task->tk_action == NULL) |
646 | rpc_call_start(task); | 650 | rpc_call_start(task); |
647 | 651 | ||
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 3fc8624fcd17..ffb687671da0 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -299,15 +299,8 @@ static void rpc_make_runnable(struct rpc_task *task) | |||
299 | if (rpc_test_and_set_running(task)) | 299 | if (rpc_test_and_set_running(task)) |
300 | return; | 300 | return; |
301 | if (RPC_IS_ASYNC(task)) { | 301 | if (RPC_IS_ASYNC(task)) { |
302 | int status; | ||
303 | |||
304 | INIT_WORK(&task->u.tk_work, rpc_async_schedule); | 302 | INIT_WORK(&task->u.tk_work, rpc_async_schedule); |
305 | status = queue_work(rpciod_workqueue, &task->u.tk_work); | 303 | queue_work(rpciod_workqueue, &task->u.tk_work); |
306 | if (status < 0) { | ||
307 | printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); | ||
308 | task->tk_status = status; | ||
309 | return; | ||
310 | } | ||
311 | } else | 304 | } else |
312 | wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED); | 305 | wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED); |
313 | } | 306 | } |
@@ -637,14 +630,12 @@ static void __rpc_execute(struct rpc_task *task) | |||
637 | save_callback = task->tk_callback; | 630 | save_callback = task->tk_callback; |
638 | task->tk_callback = NULL; | 631 | task->tk_callback = NULL; |
639 | save_callback(task); | 632 | save_callback(task); |
640 | } | 633 | } else { |
641 | 634 | /* | |
642 | /* | 635 | * Perform the next FSM step. |
643 | * Perform the next FSM step. | 636 | * tk_action may be NULL when the task has been killed |
644 | * tk_action may be NULL when the task has been killed | 637 | * by someone else. |
645 | * by someone else. | 638 | */ |
646 | */ | ||
647 | if (!RPC_IS_QUEUED(task)) { | ||
648 | if (task->tk_action == NULL) | 639 | if (task->tk_action == NULL) |
649 | break; | 640 | break; |
650 | task->tk_action(task); | 641 | task->tk_action(task); |
@@ -843,12 +834,6 @@ struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data) | |||
843 | } | 834 | } |
844 | 835 | ||
845 | rpc_init_task(task, setup_data); | 836 | rpc_init_task(task, setup_data); |
846 | if (task->tk_status < 0) { | ||
847 | int err = task->tk_status; | ||
848 | rpc_put_task(task); | ||
849 | return ERR_PTR(err); | ||
850 | } | ||
851 | |||
852 | task->tk_flags |= flags; | 837 | task->tk_flags |= flags; |
853 | dprintk("RPC: allocated task %p\n", task); | 838 | dprintk("RPC: allocated task %p\n", task); |
854 | return task; | 839 | return task; |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 856274d7e85c..9494c3767356 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -202,10 +202,9 @@ int xprt_reserve_xprt(struct rpc_task *task) | |||
202 | goto out_sleep; | 202 | goto out_sleep; |
203 | } | 203 | } |
204 | xprt->snd_task = task; | 204 | xprt->snd_task = task; |
205 | if (req) { | 205 | req->rq_bytes_sent = 0; |
206 | req->rq_bytes_sent = 0; | 206 | req->rq_ntrans++; |
207 | req->rq_ntrans++; | 207 | |
208 | } | ||
209 | return 1; | 208 | return 1; |
210 | 209 | ||
211 | out_sleep: | 210 | out_sleep: |
@@ -213,7 +212,7 @@ out_sleep: | |||
213 | task->tk_pid, xprt); | 212 | task->tk_pid, xprt); |
214 | task->tk_timeout = 0; | 213 | task->tk_timeout = 0; |
215 | task->tk_status = -EAGAIN; | 214 | task->tk_status = -EAGAIN; |
216 | if (req && req->rq_ntrans) | 215 | if (req->rq_ntrans) |
217 | rpc_sleep_on(&xprt->resend, task, NULL); | 216 | rpc_sleep_on(&xprt->resend, task, NULL); |
218 | else | 217 | else |
219 | rpc_sleep_on(&xprt->sending, task, NULL); | 218 | rpc_sleep_on(&xprt->sending, task, NULL); |
@@ -965,7 +964,7 @@ struct rpc_xprt *xprt_alloc(struct net *net, int size, int max_req) | |||
965 | xprt = kzalloc(size, GFP_KERNEL); | 964 | xprt = kzalloc(size, GFP_KERNEL); |
966 | if (xprt == NULL) | 965 | if (xprt == NULL) |
967 | goto out; | 966 | goto out; |
968 | kref_init(&xprt->kref); | 967 | atomic_set(&xprt->count, 1); |
969 | 968 | ||
970 | xprt->max_reqs = max_req; | 969 | xprt->max_reqs = max_req; |
971 | xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL); | 970 | xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL); |
@@ -1145,13 +1144,11 @@ found: | |||
1145 | 1144 | ||
1146 | /** | 1145 | /** |
1147 | * xprt_destroy - destroy an RPC transport, killing off all requests. | 1146 | * xprt_destroy - destroy an RPC transport, killing off all requests. |
1148 | * @kref: kref for the transport to destroy | 1147 | * @xprt: transport to destroy |
1149 | * | 1148 | * |
1150 | */ | 1149 | */ |
1151 | static void xprt_destroy(struct kref *kref) | 1150 | static void xprt_destroy(struct rpc_xprt *xprt) |
1152 | { | 1151 | { |
1153 | struct rpc_xprt *xprt = container_of(kref, struct rpc_xprt, kref); | ||
1154 | |||
1155 | dprintk("RPC: destroying transport %p\n", xprt); | 1152 | dprintk("RPC: destroying transport %p\n", xprt); |
1156 | xprt->shutdown = 1; | 1153 | xprt->shutdown = 1; |
1157 | del_timer_sync(&xprt->timer); | 1154 | del_timer_sync(&xprt->timer); |
@@ -1175,7 +1172,8 @@ static void xprt_destroy(struct kref *kref) | |||
1175 | */ | 1172 | */ |
1176 | void xprt_put(struct rpc_xprt *xprt) | 1173 | void xprt_put(struct rpc_xprt *xprt) |
1177 | { | 1174 | { |
1178 | kref_put(&xprt->kref, xprt_destroy); | 1175 | if (atomic_dec_and_test(&xprt->count)) |
1176 | xprt_destroy(xprt); | ||
1179 | } | 1177 | } |
1180 | 1178 | ||
1181 | /** | 1179 | /** |
@@ -1185,6 +1183,7 @@ void xprt_put(struct rpc_xprt *xprt) | |||
1185 | */ | 1183 | */ |
1186 | struct rpc_xprt *xprt_get(struct rpc_xprt *xprt) | 1184 | struct rpc_xprt *xprt_get(struct rpc_xprt *xprt) |
1187 | { | 1185 | { |
1188 | kref_get(&xprt->kref); | 1186 | if (atomic_inc_not_zero(&xprt->count)) |
1189 | return xprt; | 1187 | return xprt; |
1188 | return NULL; | ||
1190 | } | 1189 | } |
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 2ac3f6e8adff..554d0814c875 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c | |||
@@ -87,6 +87,8 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos, | |||
87 | enum rpcrdma_chunktype type, struct rpcrdma_mr_seg *seg, int nsegs) | 87 | enum rpcrdma_chunktype type, struct rpcrdma_mr_seg *seg, int nsegs) |
88 | { | 88 | { |
89 | int len, n = 0, p; | 89 | int len, n = 0, p; |
90 | int page_base; | ||
91 | struct page **ppages; | ||
90 | 92 | ||
91 | if (pos == 0 && xdrbuf->head[0].iov_len) { | 93 | if (pos == 0 && xdrbuf->head[0].iov_len) { |
92 | seg[n].mr_page = NULL; | 94 | seg[n].mr_page = NULL; |
@@ -95,34 +97,32 @@ rpcrdma_convert_iovs(struct xdr_buf *xdrbuf, unsigned int pos, | |||
95 | ++n; | 97 | ++n; |
96 | } | 98 | } |
97 | 99 | ||
98 | if (xdrbuf->page_len && (xdrbuf->pages[0] != NULL)) { | 100 | len = xdrbuf->page_len; |
99 | if (n == nsegs) | 101 | ppages = xdrbuf->pages + (xdrbuf->page_base >> PAGE_SHIFT); |
100 | return 0; | 102 | page_base = xdrbuf->page_base & ~PAGE_MASK; |
101 | seg[n].mr_page = xdrbuf->pages[0]; | 103 | p = 0; |
102 | seg[n].mr_offset = (void *)(unsigned long) xdrbuf->page_base; | 104 | while (len && n < nsegs) { |
103 | seg[n].mr_len = min_t(u32, | 105 | seg[n].mr_page = ppages[p]; |
104 | PAGE_SIZE - xdrbuf->page_base, xdrbuf->page_len); | 106 | seg[n].mr_offset = (void *)(unsigned long) page_base; |
105 | len = xdrbuf->page_len - seg[n].mr_len; | 107 | seg[n].mr_len = min_t(u32, PAGE_SIZE - page_base, len); |
108 | BUG_ON(seg[n].mr_len > PAGE_SIZE); | ||
109 | len -= seg[n].mr_len; | ||
106 | ++n; | 110 | ++n; |
107 | p = 1; | 111 | ++p; |
108 | while (len > 0) { | 112 | page_base = 0; /* page offset only applies to first page */ |
109 | if (n == nsegs) | ||
110 | return 0; | ||
111 | seg[n].mr_page = xdrbuf->pages[p]; | ||
112 | seg[n].mr_offset = NULL; | ||
113 | seg[n].mr_len = min_t(u32, PAGE_SIZE, len); | ||
114 | len -= seg[n].mr_len; | ||
115 | ++n; | ||
116 | ++p; | ||
117 | } | ||
118 | } | 113 | } |
119 | 114 | ||
115 | /* Message overflows the seg array */ | ||
116 | if (len && n == nsegs) | ||
117 | return 0; | ||
118 | |||
120 | if (xdrbuf->tail[0].iov_len) { | 119 | if (xdrbuf->tail[0].iov_len) { |
121 | /* the rpcrdma protocol allows us to omit any trailing | 120 | /* the rpcrdma protocol allows us to omit any trailing |
122 | * xdr pad bytes, saving the server an RDMA operation. */ | 121 | * xdr pad bytes, saving the server an RDMA operation. */ |
123 | if (xdrbuf->tail[0].iov_len < 4 && xprt_rdma_pad_optimize) | 122 | if (xdrbuf->tail[0].iov_len < 4 && xprt_rdma_pad_optimize) |
124 | return n; | 123 | return n; |
125 | if (n == nsegs) | 124 | if (n == nsegs) |
125 | /* Tail remains, but we're out of segments */ | ||
126 | return 0; | 126 | return 0; |
127 | seg[n].mr_page = NULL; | 127 | seg[n].mr_page = NULL; |
128 | seg[n].mr_offset = xdrbuf->tail[0].iov_base; | 128 | seg[n].mr_offset = xdrbuf->tail[0].iov_base; |
@@ -296,6 +296,8 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad) | |||
296 | int copy_len; | 296 | int copy_len; |
297 | unsigned char *srcp, *destp; | 297 | unsigned char *srcp, *destp; |
298 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt); | 298 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(rqst->rq_xprt); |
299 | int page_base; | ||
300 | struct page **ppages; | ||
299 | 301 | ||
300 | destp = rqst->rq_svec[0].iov_base; | 302 | destp = rqst->rq_svec[0].iov_base; |
301 | curlen = rqst->rq_svec[0].iov_len; | 303 | curlen = rqst->rq_svec[0].iov_len; |
@@ -324,28 +326,25 @@ rpcrdma_inline_pullup(struct rpc_rqst *rqst, int pad) | |||
324 | __func__, destp + copy_len, curlen); | 326 | __func__, destp + copy_len, curlen); |
325 | rqst->rq_svec[0].iov_len += curlen; | 327 | rqst->rq_svec[0].iov_len += curlen; |
326 | } | 328 | } |
327 | |||
328 | r_xprt->rx_stats.pullup_copy_count += copy_len; | 329 | r_xprt->rx_stats.pullup_copy_count += copy_len; |
329 | npages = PAGE_ALIGN(rqst->rq_snd_buf.page_base+copy_len) >> PAGE_SHIFT; | 330 | |
331 | page_base = rqst->rq_snd_buf.page_base; | ||
332 | ppages = rqst->rq_snd_buf.pages + (page_base >> PAGE_SHIFT); | ||
333 | page_base &= ~PAGE_MASK; | ||
334 | npages = PAGE_ALIGN(page_base+copy_len) >> PAGE_SHIFT; | ||
330 | for (i = 0; copy_len && i < npages; i++) { | 335 | for (i = 0; copy_len && i < npages; i++) { |
331 | if (i == 0) | 336 | curlen = PAGE_SIZE - page_base; |
332 | curlen = PAGE_SIZE - rqst->rq_snd_buf.page_base; | ||
333 | else | ||
334 | curlen = PAGE_SIZE; | ||
335 | if (curlen > copy_len) | 337 | if (curlen > copy_len) |
336 | curlen = copy_len; | 338 | curlen = copy_len; |
337 | dprintk("RPC: %s: page %d destp 0x%p len %d curlen %d\n", | 339 | dprintk("RPC: %s: page %d destp 0x%p len %d curlen %d\n", |
338 | __func__, i, destp, copy_len, curlen); | 340 | __func__, i, destp, copy_len, curlen); |
339 | srcp = kmap_atomic(rqst->rq_snd_buf.pages[i], | 341 | srcp = kmap_atomic(ppages[i], KM_SKB_SUNRPC_DATA); |
340 | KM_SKB_SUNRPC_DATA); | 342 | memcpy(destp, srcp+page_base, curlen); |
341 | if (i == 0) | ||
342 | memcpy(destp, srcp+rqst->rq_snd_buf.page_base, curlen); | ||
343 | else | ||
344 | memcpy(destp, srcp, curlen); | ||
345 | kunmap_atomic(srcp, KM_SKB_SUNRPC_DATA); | 343 | kunmap_atomic(srcp, KM_SKB_SUNRPC_DATA); |
346 | rqst->rq_svec[0].iov_len += curlen; | 344 | rqst->rq_svec[0].iov_len += curlen; |
347 | destp += curlen; | 345 | destp += curlen; |
348 | copy_len -= curlen; | 346 | copy_len -= curlen; |
347 | page_base = 0; | ||
349 | } | 348 | } |
350 | /* header now contains entire send message */ | 349 | /* header now contains entire send message */ |
351 | return pad; | 350 | return pad; |
@@ -606,6 +605,8 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) | |||
606 | { | 605 | { |
607 | int i, npages, curlen, olen; | 606 | int i, npages, curlen, olen; |
608 | char *destp; | 607 | char *destp; |
608 | struct page **ppages; | ||
609 | int page_base; | ||
609 | 610 | ||
610 | curlen = rqst->rq_rcv_buf.head[0].iov_len; | 611 | curlen = rqst->rq_rcv_buf.head[0].iov_len; |
611 | if (curlen > copy_len) { /* write chunk header fixup */ | 612 | if (curlen > copy_len) { /* write chunk header fixup */ |
@@ -624,32 +625,29 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) | |||
624 | olen = copy_len; | 625 | olen = copy_len; |
625 | i = 0; | 626 | i = 0; |
626 | rpcx_to_rdmax(rqst->rq_xprt)->rx_stats.fixup_copy_count += olen; | 627 | rpcx_to_rdmax(rqst->rq_xprt)->rx_stats.fixup_copy_count += olen; |
628 | page_base = rqst->rq_rcv_buf.page_base; | ||
629 | ppages = rqst->rq_rcv_buf.pages + (page_base >> PAGE_SHIFT); | ||
630 | page_base &= ~PAGE_MASK; | ||
631 | |||
627 | if (copy_len && rqst->rq_rcv_buf.page_len) { | 632 | if (copy_len && rqst->rq_rcv_buf.page_len) { |
628 | npages = PAGE_ALIGN(rqst->rq_rcv_buf.page_base + | 633 | npages = PAGE_ALIGN(page_base + |
629 | rqst->rq_rcv_buf.page_len) >> PAGE_SHIFT; | 634 | rqst->rq_rcv_buf.page_len) >> PAGE_SHIFT; |
630 | for (; i < npages; i++) { | 635 | for (; i < npages; i++) { |
631 | if (i == 0) | 636 | curlen = PAGE_SIZE - page_base; |
632 | curlen = PAGE_SIZE - rqst->rq_rcv_buf.page_base; | ||
633 | else | ||
634 | curlen = PAGE_SIZE; | ||
635 | if (curlen > copy_len) | 637 | if (curlen > copy_len) |
636 | curlen = copy_len; | 638 | curlen = copy_len; |
637 | dprintk("RPC: %s: page %d" | 639 | dprintk("RPC: %s: page %d" |
638 | " srcp 0x%p len %d curlen %d\n", | 640 | " srcp 0x%p len %d curlen %d\n", |
639 | __func__, i, srcp, copy_len, curlen); | 641 | __func__, i, srcp, copy_len, curlen); |
640 | destp = kmap_atomic(rqst->rq_rcv_buf.pages[i], | 642 | destp = kmap_atomic(ppages[i], KM_SKB_SUNRPC_DATA); |
641 | KM_SKB_SUNRPC_DATA); | 643 | memcpy(destp + page_base, srcp, curlen); |
642 | if (i == 0) | 644 | flush_dcache_page(ppages[i]); |
643 | memcpy(destp + rqst->rq_rcv_buf.page_base, | ||
644 | srcp, curlen); | ||
645 | else | ||
646 | memcpy(destp, srcp, curlen); | ||
647 | flush_dcache_page(rqst->rq_rcv_buf.pages[i]); | ||
648 | kunmap_atomic(destp, KM_SKB_SUNRPC_DATA); | 645 | kunmap_atomic(destp, KM_SKB_SUNRPC_DATA); |
649 | srcp += curlen; | 646 | srcp += curlen; |
650 | copy_len -= curlen; | 647 | copy_len -= curlen; |
651 | if (copy_len == 0) | 648 | if (copy_len == 0) |
652 | break; | 649 | break; |
650 | page_base = 0; | ||
653 | } | 651 | } |
654 | rqst->rq_rcv_buf.page_len = olen - copy_len; | 652 | rqst->rq_rcv_buf.page_len = olen - copy_len; |
655 | } else | 653 | } else |
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 5f4c7b3bc711..d4297dc43dc4 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c | |||
@@ -144,6 +144,7 @@ rpcrdma_cq_async_error_upcall(struct ib_event *event, void *context) | |||
144 | static inline | 144 | static inline |
145 | void rpcrdma_event_process(struct ib_wc *wc) | 145 | void rpcrdma_event_process(struct ib_wc *wc) |
146 | { | 146 | { |
147 | struct rpcrdma_mw *frmr; | ||
147 | struct rpcrdma_rep *rep = | 148 | struct rpcrdma_rep *rep = |
148 | (struct rpcrdma_rep *)(unsigned long) wc->wr_id; | 149 | (struct rpcrdma_rep *)(unsigned long) wc->wr_id; |
149 | 150 | ||
@@ -154,15 +155,23 @@ void rpcrdma_event_process(struct ib_wc *wc) | |||
154 | return; | 155 | return; |
155 | 156 | ||
156 | if (IB_WC_SUCCESS != wc->status) { | 157 | if (IB_WC_SUCCESS != wc->status) { |
157 | dprintk("RPC: %s: %s WC status %X, connection lost\n", | 158 | dprintk("RPC: %s: WC opcode %d status %X, connection lost\n", |
158 | __func__, (wc->opcode & IB_WC_RECV) ? "recv" : "send", | 159 | __func__, wc->opcode, wc->status); |
159 | wc->status); | ||
160 | rep->rr_len = ~0U; | 160 | rep->rr_len = ~0U; |
161 | rpcrdma_schedule_tasklet(rep); | 161 | if (wc->opcode != IB_WC_FAST_REG_MR && wc->opcode != IB_WC_LOCAL_INV) |
162 | rpcrdma_schedule_tasklet(rep); | ||
162 | return; | 163 | return; |
163 | } | 164 | } |
164 | 165 | ||
165 | switch (wc->opcode) { | 166 | switch (wc->opcode) { |
167 | case IB_WC_FAST_REG_MR: | ||
168 | frmr = (struct rpcrdma_mw *)(unsigned long)wc->wr_id; | ||
169 | frmr->r.frmr.state = FRMR_IS_VALID; | ||
170 | break; | ||
171 | case IB_WC_LOCAL_INV: | ||
172 | frmr = (struct rpcrdma_mw *)(unsigned long)wc->wr_id; | ||
173 | frmr->r.frmr.state = FRMR_IS_INVALID; | ||
174 | break; | ||
166 | case IB_WC_RECV: | 175 | case IB_WC_RECV: |
167 | rep->rr_len = wc->byte_len; | 176 | rep->rr_len = wc->byte_len; |
168 | ib_dma_sync_single_for_cpu( | 177 | ib_dma_sync_single_for_cpu( |
@@ -1450,6 +1459,12 @@ rpcrdma_map_one(struct rpcrdma_ia *ia, struct rpcrdma_mr_seg *seg, int writing) | |||
1450 | seg->mr_dma = ib_dma_map_single(ia->ri_id->device, | 1459 | seg->mr_dma = ib_dma_map_single(ia->ri_id->device, |
1451 | seg->mr_offset, | 1460 | seg->mr_offset, |
1452 | seg->mr_dmalen, seg->mr_dir); | 1461 | seg->mr_dmalen, seg->mr_dir); |
1462 | if (ib_dma_mapping_error(ia->ri_id->device, seg->mr_dma)) { | ||
1463 | dprintk("RPC: %s: mr_dma %llx mr_offset %p mr_dma_len %zu\n", | ||
1464 | __func__, | ||
1465 | (unsigned long long)seg->mr_dma, | ||
1466 | seg->mr_offset, seg->mr_dmalen); | ||
1467 | } | ||
1453 | } | 1468 | } |
1454 | 1469 | ||
1455 | static void | 1470 | static void |
@@ -1469,7 +1484,8 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
1469 | struct rpcrdma_xprt *r_xprt) | 1484 | struct rpcrdma_xprt *r_xprt) |
1470 | { | 1485 | { |
1471 | struct rpcrdma_mr_seg *seg1 = seg; | 1486 | struct rpcrdma_mr_seg *seg1 = seg; |
1472 | struct ib_send_wr frmr_wr, *bad_wr; | 1487 | struct ib_send_wr invalidate_wr, frmr_wr, *bad_wr, *post_wr; |
1488 | |||
1473 | u8 key; | 1489 | u8 key; |
1474 | int len, pageoff; | 1490 | int len, pageoff; |
1475 | int i, rc; | 1491 | int i, rc; |
@@ -1484,6 +1500,7 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
1484 | rpcrdma_map_one(ia, seg, writing); | 1500 | rpcrdma_map_one(ia, seg, writing); |
1485 | seg1->mr_chunk.rl_mw->r.frmr.fr_pgl->page_list[i] = seg->mr_dma; | 1501 | seg1->mr_chunk.rl_mw->r.frmr.fr_pgl->page_list[i] = seg->mr_dma; |
1486 | len += seg->mr_len; | 1502 | len += seg->mr_len; |
1503 | BUG_ON(seg->mr_len > PAGE_SIZE); | ||
1487 | ++seg; | 1504 | ++seg; |
1488 | ++i; | 1505 | ++i; |
1489 | /* Check for holes */ | 1506 | /* Check for holes */ |
@@ -1494,26 +1511,45 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
1494 | dprintk("RPC: %s: Using frmr %p to map %d segments\n", | 1511 | dprintk("RPC: %s: Using frmr %p to map %d segments\n", |
1495 | __func__, seg1->mr_chunk.rl_mw, i); | 1512 | __func__, seg1->mr_chunk.rl_mw, i); |
1496 | 1513 | ||
1514 | if (unlikely(seg1->mr_chunk.rl_mw->r.frmr.state == FRMR_IS_VALID)) { | ||
1515 | dprintk("RPC: %s: frmr %x left valid, posting invalidate.\n", | ||
1516 | __func__, | ||
1517 | seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey); | ||
1518 | /* Invalidate before using. */ | ||
1519 | memset(&invalidate_wr, 0, sizeof invalidate_wr); | ||
1520 | invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw; | ||
1521 | invalidate_wr.next = &frmr_wr; | ||
1522 | invalidate_wr.opcode = IB_WR_LOCAL_INV; | ||
1523 | invalidate_wr.send_flags = IB_SEND_SIGNALED; | ||
1524 | invalidate_wr.ex.invalidate_rkey = | ||
1525 | seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | ||
1526 | DECR_CQCOUNT(&r_xprt->rx_ep); | ||
1527 | post_wr = &invalidate_wr; | ||
1528 | } else | ||
1529 | post_wr = &frmr_wr; | ||
1530 | |||
1497 | /* Bump the key */ | 1531 | /* Bump the key */ |
1498 | key = (u8)(seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey & 0x000000FF); | 1532 | key = (u8)(seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey & 0x000000FF); |
1499 | ib_update_fast_reg_key(seg1->mr_chunk.rl_mw->r.frmr.fr_mr, ++key); | 1533 | ib_update_fast_reg_key(seg1->mr_chunk.rl_mw->r.frmr.fr_mr, ++key); |
1500 | 1534 | ||
1501 | /* Prepare FRMR WR */ | 1535 | /* Prepare FRMR WR */ |
1502 | memset(&frmr_wr, 0, sizeof frmr_wr); | 1536 | memset(&frmr_wr, 0, sizeof frmr_wr); |
1537 | frmr_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw; | ||
1503 | frmr_wr.opcode = IB_WR_FAST_REG_MR; | 1538 | frmr_wr.opcode = IB_WR_FAST_REG_MR; |
1504 | frmr_wr.send_flags = 0; /* unsignaled */ | 1539 | frmr_wr.send_flags = IB_SEND_SIGNALED; |
1505 | frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma; | 1540 | frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma; |
1506 | frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl; | 1541 | frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl; |
1507 | frmr_wr.wr.fast_reg.page_list_len = i; | 1542 | frmr_wr.wr.fast_reg.page_list_len = i; |
1508 | frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT; | 1543 | frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT; |
1509 | frmr_wr.wr.fast_reg.length = i << PAGE_SHIFT; | 1544 | frmr_wr.wr.fast_reg.length = i << PAGE_SHIFT; |
1545 | BUG_ON(frmr_wr.wr.fast_reg.length < len); | ||
1510 | frmr_wr.wr.fast_reg.access_flags = (writing ? | 1546 | frmr_wr.wr.fast_reg.access_flags = (writing ? |
1511 | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE : | 1547 | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE : |
1512 | IB_ACCESS_REMOTE_READ); | 1548 | IB_ACCESS_REMOTE_READ); |
1513 | frmr_wr.wr.fast_reg.rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | 1549 | frmr_wr.wr.fast_reg.rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; |
1514 | DECR_CQCOUNT(&r_xprt->rx_ep); | 1550 | DECR_CQCOUNT(&r_xprt->rx_ep); |
1515 | 1551 | ||
1516 | rc = ib_post_send(ia->ri_id->qp, &frmr_wr, &bad_wr); | 1552 | rc = ib_post_send(ia->ri_id->qp, post_wr, &bad_wr); |
1517 | 1553 | ||
1518 | if (rc) { | 1554 | if (rc) { |
1519 | dprintk("RPC: %s: failed ib_post_send for register," | 1555 | dprintk("RPC: %s: failed ib_post_send for register," |
@@ -1542,8 +1578,9 @@ rpcrdma_deregister_frmr_external(struct rpcrdma_mr_seg *seg, | |||
1542 | rpcrdma_unmap_one(ia, seg++); | 1578 | rpcrdma_unmap_one(ia, seg++); |
1543 | 1579 | ||
1544 | memset(&invalidate_wr, 0, sizeof invalidate_wr); | 1580 | memset(&invalidate_wr, 0, sizeof invalidate_wr); |
1581 | invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw; | ||
1545 | invalidate_wr.opcode = IB_WR_LOCAL_INV; | 1582 | invalidate_wr.opcode = IB_WR_LOCAL_INV; |
1546 | invalidate_wr.send_flags = 0; /* unsignaled */ | 1583 | invalidate_wr.send_flags = IB_SEND_SIGNALED; |
1547 | invalidate_wr.ex.invalidate_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | 1584 | invalidate_wr.ex.invalidate_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; |
1548 | DECR_CQCOUNT(&r_xprt->rx_ep); | 1585 | DECR_CQCOUNT(&r_xprt->rx_ep); |
1549 | 1586 | ||
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h index c7a7eba991bc..cae761a8536c 100644 --- a/net/sunrpc/xprtrdma/xprt_rdma.h +++ b/net/sunrpc/xprtrdma/xprt_rdma.h | |||
@@ -164,6 +164,7 @@ struct rpcrdma_mr_seg { /* chunk descriptors */ | |||
164 | struct { | 164 | struct { |
165 | struct ib_fast_reg_page_list *fr_pgl; | 165 | struct ib_fast_reg_page_list *fr_pgl; |
166 | struct ib_mr *fr_mr; | 166 | struct ib_mr *fr_mr; |
167 | enum { FRMR_IS_INVALID, FRMR_IS_VALID } state; | ||
167 | } frmr; | 168 | } frmr; |
168 | } r; | 169 | } r; |
169 | struct list_head mw_list; | 170 | struct list_head mw_list; |