diff options
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r-- | fs/nfs/direct.c | 261 |
1 files changed, 178 insertions, 83 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index afcab007a22b..16844f98f50e 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -193,7 +193,7 @@ static ssize_t nfs_direct_wait(struct nfs_direct_req *dreq) | |||
193 | if (dreq->iocb) | 193 | if (dreq->iocb) |
194 | goto out; | 194 | goto out; |
195 | 195 | ||
196 | result = wait_for_completion_interruptible(&dreq->completion); | 196 | result = wait_for_completion_killable(&dreq->completion); |
197 | 197 | ||
198 | if (!result) | 198 | if (!result) |
199 | result = dreq->error; | 199 | result = dreq->error; |
@@ -263,17 +263,29 @@ static const struct rpc_call_ops nfs_read_direct_ops = { | |||
263 | * handled automatically by nfs_direct_read_result(). Otherwise, if | 263 | * handled automatically by nfs_direct_read_result(). Otherwise, if |
264 | * no requests have been sent, just return an error. | 264 | * no requests have been sent, just return an error. |
265 | */ | 265 | */ |
266 | static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos) | 266 | static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, |
267 | const struct iovec *iov, | ||
268 | loff_t pos) | ||
267 | { | 269 | { |
268 | struct nfs_open_context *ctx = dreq->ctx; | 270 | struct nfs_open_context *ctx = dreq->ctx; |
269 | struct inode *inode = ctx->path.dentry->d_inode; | 271 | struct inode *inode = ctx->path.dentry->d_inode; |
272 | unsigned long user_addr = (unsigned long)iov->iov_base; | ||
273 | size_t count = iov->iov_len; | ||
270 | size_t rsize = NFS_SERVER(inode)->rsize; | 274 | size_t rsize = NFS_SERVER(inode)->rsize; |
275 | struct rpc_task *task; | ||
276 | struct rpc_message msg = { | ||
277 | .rpc_cred = ctx->cred, | ||
278 | }; | ||
279 | struct rpc_task_setup task_setup_data = { | ||
280 | .rpc_client = NFS_CLIENT(inode), | ||
281 | .rpc_message = &msg, | ||
282 | .callback_ops = &nfs_read_direct_ops, | ||
283 | .flags = RPC_TASK_ASYNC, | ||
284 | }; | ||
271 | unsigned int pgbase; | 285 | unsigned int pgbase; |
272 | int result; | 286 | int result; |
273 | ssize_t started = 0; | 287 | ssize_t started = 0; |
274 | 288 | ||
275 | get_dreq(dreq); | ||
276 | |||
277 | do { | 289 | do { |
278 | struct nfs_read_data *data; | 290 | struct nfs_read_data *data; |
279 | size_t bytes; | 291 | size_t bytes; |
@@ -309,7 +321,7 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo | |||
309 | 321 | ||
310 | data->req = (struct nfs_page *) dreq; | 322 | data->req = (struct nfs_page *) dreq; |
311 | data->inode = inode; | 323 | data->inode = inode; |
312 | data->cred = ctx->cred; | 324 | data->cred = msg.rpc_cred; |
313 | data->args.fh = NFS_FH(inode); | 325 | data->args.fh = NFS_FH(inode); |
314 | data->args.context = ctx; | 326 | data->args.context = ctx; |
315 | data->args.offset = pos; | 327 | data->args.offset = pos; |
@@ -319,14 +331,16 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo | |||
319 | data->res.fattr = &data->fattr; | 331 | data->res.fattr = &data->fattr; |
320 | data->res.eof = 0; | 332 | data->res.eof = 0; |
321 | data->res.count = bytes; | 333 | data->res.count = bytes; |
334 | msg.rpc_argp = &data->args; | ||
335 | msg.rpc_resp = &data->res; | ||
322 | 336 | ||
323 | rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, | 337 | task_setup_data.task = &data->task; |
324 | &nfs_read_direct_ops, data); | 338 | task_setup_data.callback_data = data; |
325 | NFS_PROTO(inode)->read_setup(data); | 339 | NFS_PROTO(inode)->read_setup(data, &msg); |
326 | 340 | ||
327 | data->task.tk_cookie = (unsigned long) inode; | 341 | task = rpc_run_task(&task_setup_data); |
328 | 342 | if (!IS_ERR(task)) | |
329 | rpc_execute(&data->task); | 343 | rpc_put_task(task); |
330 | 344 | ||
331 | dprintk("NFS: %5u initiated direct read call " | 345 | dprintk("NFS: %5u initiated direct read call " |
332 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", | 346 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", |
@@ -347,20 +361,49 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo | |||
347 | count -= bytes; | 361 | count -= bytes; |
348 | } while (count != 0); | 362 | } while (count != 0); |
349 | 363 | ||
364 | if (started) | ||
365 | return started; | ||
366 | return result < 0 ? (ssize_t) result : -EFAULT; | ||
367 | } | ||
368 | |||
369 | static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, | ||
370 | const struct iovec *iov, | ||
371 | unsigned long nr_segs, | ||
372 | loff_t pos) | ||
373 | { | ||
374 | ssize_t result = -EINVAL; | ||
375 | size_t requested_bytes = 0; | ||
376 | unsigned long seg; | ||
377 | |||
378 | get_dreq(dreq); | ||
379 | |||
380 | for (seg = 0; seg < nr_segs; seg++) { | ||
381 | const struct iovec *vec = &iov[seg]; | ||
382 | result = nfs_direct_read_schedule_segment(dreq, vec, pos); | ||
383 | if (result < 0) | ||
384 | break; | ||
385 | requested_bytes += result; | ||
386 | if ((size_t)result < vec->iov_len) | ||
387 | break; | ||
388 | pos += vec->iov_len; | ||
389 | } | ||
390 | |||
350 | if (put_dreq(dreq)) | 391 | if (put_dreq(dreq)) |
351 | nfs_direct_complete(dreq); | 392 | nfs_direct_complete(dreq); |
352 | 393 | ||
353 | if (started) | 394 | if (requested_bytes != 0) |
354 | return 0; | 395 | return 0; |
355 | return result < 0 ? (ssize_t) result : -EFAULT; | 396 | |
397 | if (result < 0) | ||
398 | return result; | ||
399 | return -EIO; | ||
356 | } | 400 | } |
357 | 401 | ||
358 | static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos) | 402 | static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, |
403 | unsigned long nr_segs, loff_t pos) | ||
359 | { | 404 | { |
360 | ssize_t result = 0; | 405 | ssize_t result = 0; |
361 | sigset_t oldset; | ||
362 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 406 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
363 | struct rpc_clnt *clnt = NFS_CLIENT(inode); | ||
364 | struct nfs_direct_req *dreq; | 407 | struct nfs_direct_req *dreq; |
365 | 408 | ||
366 | dreq = nfs_direct_req_alloc(); | 409 | dreq = nfs_direct_req_alloc(); |
@@ -372,12 +415,9 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size | |||
372 | if (!is_sync_kiocb(iocb)) | 415 | if (!is_sync_kiocb(iocb)) |
373 | dreq->iocb = iocb; | 416 | dreq->iocb = iocb; |
374 | 417 | ||
375 | nfs_add_stats(inode, NFSIOS_DIRECTREADBYTES, count); | 418 | result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos); |
376 | rpc_clnt_sigmask(clnt, &oldset); | ||
377 | result = nfs_direct_read_schedule(dreq, user_addr, count, pos); | ||
378 | if (!result) | 419 | if (!result) |
379 | result = nfs_direct_wait(dreq); | 420 | result = nfs_direct_wait(dreq); |
380 | rpc_clnt_sigunmask(clnt, &oldset); | ||
381 | nfs_direct_req_release(dreq); | 421 | nfs_direct_req_release(dreq); |
382 | 422 | ||
383 | return result; | 423 | return result; |
@@ -399,6 +439,15 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
399 | struct inode *inode = dreq->inode; | 439 | struct inode *inode = dreq->inode; |
400 | struct list_head *p; | 440 | struct list_head *p; |
401 | struct nfs_write_data *data; | 441 | struct nfs_write_data *data; |
442 | struct rpc_task *task; | ||
443 | struct rpc_message msg = { | ||
444 | .rpc_cred = dreq->ctx->cred, | ||
445 | }; | ||
446 | struct rpc_task_setup task_setup_data = { | ||
447 | .rpc_client = NFS_CLIENT(inode), | ||
448 | .callback_ops = &nfs_write_direct_ops, | ||
449 | .flags = RPC_TASK_ASYNC, | ||
450 | }; | ||
402 | 451 | ||
403 | dreq->count = 0; | 452 | dreq->count = 0; |
404 | get_dreq(dreq); | 453 | get_dreq(dreq); |
@@ -408,6 +457,9 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
408 | 457 | ||
409 | get_dreq(dreq); | 458 | get_dreq(dreq); |
410 | 459 | ||
460 | /* Use stable writes */ | ||
461 | data->args.stable = NFS_FILE_SYNC; | ||
462 | |||
411 | /* | 463 | /* |
412 | * Reset data->res. | 464 | * Reset data->res. |
413 | */ | 465 | */ |
@@ -419,17 +471,18 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
419 | * Reuse data->task; data->args should not have changed | 471 | * Reuse data->task; data->args should not have changed |
420 | * since the original request was sent. | 472 | * since the original request was sent. |
421 | */ | 473 | */ |
422 | rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, | 474 | task_setup_data.task = &data->task; |
423 | &nfs_write_direct_ops, data); | 475 | task_setup_data.callback_data = data; |
424 | NFS_PROTO(inode)->write_setup(data, FLUSH_STABLE); | 476 | msg.rpc_argp = &data->args; |
425 | 477 | msg.rpc_resp = &data->res; | |
426 | data->task.tk_priority = RPC_PRIORITY_NORMAL; | 478 | NFS_PROTO(inode)->write_setup(data, &msg); |
427 | data->task.tk_cookie = (unsigned long) inode; | ||
428 | 479 | ||
429 | /* | 480 | /* |
430 | * We're called via an RPC callback, so BKL is already held. | 481 | * We're called via an RPC callback, so BKL is already held. |
431 | */ | 482 | */ |
432 | rpc_execute(&data->task); | 483 | task = rpc_run_task(&task_setup_data); |
484 | if (!IS_ERR(task)) | ||
485 | rpc_put_task(task); | ||
433 | 486 | ||
434 | dprintk("NFS: %5u rescheduled direct write call (req %s/%Ld, %u bytes @ offset %Lu)\n", | 487 | dprintk("NFS: %5u rescheduled direct write call (req %s/%Ld, %u bytes @ offset %Lu)\n", |
435 | data->task.tk_pid, | 488 | data->task.tk_pid, |
@@ -472,9 +525,23 @@ static const struct rpc_call_ops nfs_commit_direct_ops = { | |||
472 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | 525 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) |
473 | { | 526 | { |
474 | struct nfs_write_data *data = dreq->commit_data; | 527 | struct nfs_write_data *data = dreq->commit_data; |
528 | struct rpc_task *task; | ||
529 | struct rpc_message msg = { | ||
530 | .rpc_argp = &data->args, | ||
531 | .rpc_resp = &data->res, | ||
532 | .rpc_cred = dreq->ctx->cred, | ||
533 | }; | ||
534 | struct rpc_task_setup task_setup_data = { | ||
535 | .task = &data->task, | ||
536 | .rpc_client = NFS_CLIENT(dreq->inode), | ||
537 | .rpc_message = &msg, | ||
538 | .callback_ops = &nfs_commit_direct_ops, | ||
539 | .callback_data = data, | ||
540 | .flags = RPC_TASK_ASYNC, | ||
541 | }; | ||
475 | 542 | ||
476 | data->inode = dreq->inode; | 543 | data->inode = dreq->inode; |
477 | data->cred = dreq->ctx->cred; | 544 | data->cred = msg.rpc_cred; |
478 | 545 | ||
479 | data->args.fh = NFS_FH(data->inode); | 546 | data->args.fh = NFS_FH(data->inode); |
480 | data->args.offset = 0; | 547 | data->args.offset = 0; |
@@ -483,18 +550,16 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
483 | data->res.fattr = &data->fattr; | 550 | data->res.fattr = &data->fattr; |
484 | data->res.verf = &data->verf; | 551 | data->res.verf = &data->verf; |
485 | 552 | ||
486 | rpc_init_task(&data->task, NFS_CLIENT(dreq->inode), RPC_TASK_ASYNC, | 553 | NFS_PROTO(data->inode)->commit_setup(data, &msg); |
487 | &nfs_commit_direct_ops, data); | ||
488 | NFS_PROTO(data->inode)->commit_setup(data, 0); | ||
489 | 554 | ||
490 | data->task.tk_priority = RPC_PRIORITY_NORMAL; | ||
491 | data->task.tk_cookie = (unsigned long)data->inode; | ||
492 | /* Note: task.tk_ops->rpc_release will free dreq->commit_data */ | 555 | /* Note: task.tk_ops->rpc_release will free dreq->commit_data */ |
493 | dreq->commit_data = NULL; | 556 | dreq->commit_data = NULL; |
494 | 557 | ||
495 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 558 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
496 | 559 | ||
497 | rpc_execute(&data->task); | 560 | task = rpc_run_task(&task_setup_data); |
561 | if (!IS_ERR(task)) | ||
562 | rpc_put_task(task); | ||
498 | } | 563 | } |
499 | 564 | ||
500 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) | 565 | static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode) |
@@ -601,17 +666,29 @@ static const struct rpc_call_ops nfs_write_direct_ops = { | |||
601 | * handled automatically by nfs_direct_write_result(). Otherwise, if | 666 | * handled automatically by nfs_direct_write_result(). Otherwise, if |
602 | * no requests have been sent, just return an error. | 667 | * no requests have been sent, just return an error. |
603 | */ | 668 | */ |
604 | static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync) | 669 | static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, |
670 | const struct iovec *iov, | ||
671 | loff_t pos, int sync) | ||
605 | { | 672 | { |
606 | struct nfs_open_context *ctx = dreq->ctx; | 673 | struct nfs_open_context *ctx = dreq->ctx; |
607 | struct inode *inode = ctx->path.dentry->d_inode; | 674 | struct inode *inode = ctx->path.dentry->d_inode; |
675 | unsigned long user_addr = (unsigned long)iov->iov_base; | ||
676 | size_t count = iov->iov_len; | ||
677 | struct rpc_task *task; | ||
678 | struct rpc_message msg = { | ||
679 | .rpc_cred = ctx->cred, | ||
680 | }; | ||
681 | struct rpc_task_setup task_setup_data = { | ||
682 | .rpc_client = NFS_CLIENT(inode), | ||
683 | .rpc_message = &msg, | ||
684 | .callback_ops = &nfs_write_direct_ops, | ||
685 | .flags = RPC_TASK_ASYNC, | ||
686 | }; | ||
608 | size_t wsize = NFS_SERVER(inode)->wsize; | 687 | size_t wsize = NFS_SERVER(inode)->wsize; |
609 | unsigned int pgbase; | 688 | unsigned int pgbase; |
610 | int result; | 689 | int result; |
611 | ssize_t started = 0; | 690 | ssize_t started = 0; |
612 | 691 | ||
613 | get_dreq(dreq); | ||
614 | |||
615 | do { | 692 | do { |
616 | struct nfs_write_data *data; | 693 | struct nfs_write_data *data; |
617 | size_t bytes; | 694 | size_t bytes; |
@@ -649,25 +726,27 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l | |||
649 | 726 | ||
650 | data->req = (struct nfs_page *) dreq; | 727 | data->req = (struct nfs_page *) dreq; |
651 | data->inode = inode; | 728 | data->inode = inode; |
652 | data->cred = ctx->cred; | 729 | data->cred = msg.rpc_cred; |
653 | data->args.fh = NFS_FH(inode); | 730 | data->args.fh = NFS_FH(inode); |
654 | data->args.context = ctx; | 731 | data->args.context = ctx; |
655 | data->args.offset = pos; | 732 | data->args.offset = pos; |
656 | data->args.pgbase = pgbase; | 733 | data->args.pgbase = pgbase; |
657 | data->args.pages = data->pagevec; | 734 | data->args.pages = data->pagevec; |
658 | data->args.count = bytes; | 735 | data->args.count = bytes; |
736 | data->args.stable = sync; | ||
659 | data->res.fattr = &data->fattr; | 737 | data->res.fattr = &data->fattr; |
660 | data->res.count = bytes; | 738 | data->res.count = bytes; |
661 | data->res.verf = &data->verf; | 739 | data->res.verf = &data->verf; |
662 | 740 | ||
663 | rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, | 741 | task_setup_data.task = &data->task; |
664 | &nfs_write_direct_ops, data); | 742 | task_setup_data.callback_data = data; |
665 | NFS_PROTO(inode)->write_setup(data, sync); | 743 | msg.rpc_argp = &data->args; |
744 | msg.rpc_resp = &data->res; | ||
745 | NFS_PROTO(inode)->write_setup(data, &msg); | ||
666 | 746 | ||
667 | data->task.tk_priority = RPC_PRIORITY_NORMAL; | 747 | task = rpc_run_task(&task_setup_data); |
668 | data->task.tk_cookie = (unsigned long) inode; | 748 | if (!IS_ERR(task)) |
669 | 749 | rpc_put_task(task); | |
670 | rpc_execute(&data->task); | ||
671 | 750 | ||
672 | dprintk("NFS: %5u initiated direct write call " | 751 | dprintk("NFS: %5u initiated direct write call " |
673 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", | 752 | "(req %s/%Ld, %zu bytes @ offset %Lu)\n", |
@@ -689,23 +768,54 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l | |||
689 | count -= bytes; | 768 | count -= bytes; |
690 | } while (count != 0); | 769 | } while (count != 0); |
691 | 770 | ||
771 | if (started) | ||
772 | return started; | ||
773 | return result < 0 ? (ssize_t) result : -EFAULT; | ||
774 | } | ||
775 | |||
776 | static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, | ||
777 | const struct iovec *iov, | ||
778 | unsigned long nr_segs, | ||
779 | loff_t pos, int sync) | ||
780 | { | ||
781 | ssize_t result = 0; | ||
782 | size_t requested_bytes = 0; | ||
783 | unsigned long seg; | ||
784 | |||
785 | get_dreq(dreq); | ||
786 | |||
787 | for (seg = 0; seg < nr_segs; seg++) { | ||
788 | const struct iovec *vec = &iov[seg]; | ||
789 | result = nfs_direct_write_schedule_segment(dreq, vec, | ||
790 | pos, sync); | ||
791 | if (result < 0) | ||
792 | break; | ||
793 | requested_bytes += result; | ||
794 | if ((size_t)result < vec->iov_len) | ||
795 | break; | ||
796 | pos += vec->iov_len; | ||
797 | } | ||
798 | |||
692 | if (put_dreq(dreq)) | 799 | if (put_dreq(dreq)) |
693 | nfs_direct_write_complete(dreq, inode); | 800 | nfs_direct_write_complete(dreq, dreq->inode); |
694 | 801 | ||
695 | if (started) | 802 | if (requested_bytes != 0) |
696 | return 0; | 803 | return 0; |
697 | return result < 0 ? (ssize_t) result : -EFAULT; | 804 | |
805 | if (result < 0) | ||
806 | return result; | ||
807 | return -EIO; | ||
698 | } | 808 | } |
699 | 809 | ||
700 | static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos) | 810 | static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, |
811 | unsigned long nr_segs, loff_t pos, | ||
812 | size_t count) | ||
701 | { | 813 | { |
702 | ssize_t result = 0; | 814 | ssize_t result = 0; |
703 | sigset_t oldset; | ||
704 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 815 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
705 | struct rpc_clnt *clnt = NFS_CLIENT(inode); | ||
706 | struct nfs_direct_req *dreq; | 816 | struct nfs_direct_req *dreq; |
707 | size_t wsize = NFS_SERVER(inode)->wsize; | 817 | size_t wsize = NFS_SERVER(inode)->wsize; |
708 | int sync = 0; | 818 | int sync = NFS_UNSTABLE; |
709 | 819 | ||
710 | dreq = nfs_direct_req_alloc(); | 820 | dreq = nfs_direct_req_alloc(); |
711 | if (!dreq) | 821 | if (!dreq) |
@@ -713,20 +823,16 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz | |||
713 | nfs_alloc_commit_data(dreq); | 823 | nfs_alloc_commit_data(dreq); |
714 | 824 | ||
715 | if (dreq->commit_data == NULL || count < wsize) | 825 | if (dreq->commit_data == NULL || count < wsize) |
716 | sync = FLUSH_STABLE; | 826 | sync = NFS_FILE_SYNC; |
717 | 827 | ||
718 | dreq->inode = inode; | 828 | dreq->inode = inode; |
719 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); | 829 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); |
720 | if (!is_sync_kiocb(iocb)) | 830 | if (!is_sync_kiocb(iocb)) |
721 | dreq->iocb = iocb; | 831 | dreq->iocb = iocb; |
722 | 832 | ||
723 | nfs_add_stats(inode, NFSIOS_DIRECTWRITTENBYTES, count); | 833 | result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync); |
724 | |||
725 | rpc_clnt_sigmask(clnt, &oldset); | ||
726 | result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync); | ||
727 | if (!result) | 834 | if (!result) |
728 | result = nfs_direct_wait(dreq); | 835 | result = nfs_direct_wait(dreq); |
729 | rpc_clnt_sigunmask(clnt, &oldset); | ||
730 | nfs_direct_req_release(dreq); | 836 | nfs_direct_req_release(dreq); |
731 | 837 | ||
732 | return result; | 838 | return result; |
@@ -759,21 +865,16 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, | |||
759 | ssize_t retval = -EINVAL; | 865 | ssize_t retval = -EINVAL; |
760 | struct file *file = iocb->ki_filp; | 866 | struct file *file = iocb->ki_filp; |
761 | struct address_space *mapping = file->f_mapping; | 867 | struct address_space *mapping = file->f_mapping; |
762 | /* XXX: temporary */ | 868 | size_t count; |
763 | const char __user *buf = iov[0].iov_base; | ||
764 | size_t count = iov[0].iov_len; | ||
765 | 869 | ||
766 | dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n", | 870 | count = iov_length(iov, nr_segs); |
871 | nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count); | ||
872 | |||
873 | dprintk("nfs: direct read(%s/%s, %zd@%Ld)\n", | ||
767 | file->f_path.dentry->d_parent->d_name.name, | 874 | file->f_path.dentry->d_parent->d_name.name, |
768 | file->f_path.dentry->d_name.name, | 875 | file->f_path.dentry->d_name.name, |
769 | (unsigned long) count, (long long) pos); | 876 | count, (long long) pos); |
770 | |||
771 | if (nr_segs != 1) | ||
772 | goto out; | ||
773 | 877 | ||
774 | retval = -EFAULT; | ||
775 | if (!access_ok(VERIFY_WRITE, buf, count)) | ||
776 | goto out; | ||
777 | retval = 0; | 878 | retval = 0; |
778 | if (!count) | 879 | if (!count) |
779 | goto out; | 880 | goto out; |
@@ -782,7 +883,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, | |||
782 | if (retval) | 883 | if (retval) |
783 | goto out; | 884 | goto out; |
784 | 885 | ||
785 | retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos); | 886 | retval = nfs_direct_read(iocb, iov, nr_segs, pos); |
786 | if (retval > 0) | 887 | if (retval > 0) |
787 | iocb->ki_pos = pos + retval; | 888 | iocb->ki_pos = pos + retval; |
788 | 889 | ||
@@ -821,17 +922,15 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
821 | ssize_t retval = -EINVAL; | 922 | ssize_t retval = -EINVAL; |
822 | struct file *file = iocb->ki_filp; | 923 | struct file *file = iocb->ki_filp; |
823 | struct address_space *mapping = file->f_mapping; | 924 | struct address_space *mapping = file->f_mapping; |
824 | /* XXX: temporary */ | 925 | size_t count; |
825 | const char __user *buf = iov[0].iov_base; | 926 | |
826 | size_t count = iov[0].iov_len; | 927 | count = iov_length(iov, nr_segs); |
928 | nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count); | ||
827 | 929 | ||
828 | dprintk("nfs: direct write(%s/%s, %lu@%Ld)\n", | 930 | dfprintk(VFS, "nfs: direct write(%s/%s, %zd@%Ld)\n", |
829 | file->f_path.dentry->d_parent->d_name.name, | 931 | file->f_path.dentry->d_parent->d_name.name, |
830 | file->f_path.dentry->d_name.name, | 932 | file->f_path.dentry->d_name.name, |
831 | (unsigned long) count, (long long) pos); | 933 | count, (long long) pos); |
832 | |||
833 | if (nr_segs != 1) | ||
834 | goto out; | ||
835 | 934 | ||
836 | retval = generic_write_checks(file, &pos, &count, 0); | 935 | retval = generic_write_checks(file, &pos, &count, 0); |
837 | if (retval) | 936 | if (retval) |
@@ -844,15 +943,11 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
844 | if (!count) | 943 | if (!count) |
845 | goto out; | 944 | goto out; |
846 | 945 | ||
847 | retval = -EFAULT; | ||
848 | if (!access_ok(VERIFY_READ, buf, count)) | ||
849 | goto out; | ||
850 | |||
851 | retval = nfs_sync_mapping(mapping); | 946 | retval = nfs_sync_mapping(mapping); |
852 | if (retval) | 947 | if (retval) |
853 | goto out; | 948 | goto out; |
854 | 949 | ||
855 | retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos); | 950 | retval = nfs_direct_write(iocb, iov, nr_segs, pos, count); |
856 | 951 | ||
857 | if (retval > 0) | 952 | if (retval > 0) |
858 | iocb->ki_pos = pos + retval; | 953 | iocb->ki_pos = pos + retval; |