diff options
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r-- | fs/nfs/direct.c | 68 |
1 files changed, 17 insertions, 51 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index dea3239cdded..9a7d45907054 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -510,6 +510,7 @@ static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, struct inode | |||
510 | data->args.count = bytes; | 510 | data->args.count = bytes; |
511 | data->res.fattr = &data->fattr; | 511 | data->res.fattr = &data->fattr; |
512 | data->res.count = bytes; | 512 | data->res.count = bytes; |
513 | data->res.verf = &data->verf; | ||
513 | 514 | ||
514 | rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, | 515 | rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, |
515 | &nfs_write_direct_ops, data); | 516 | &nfs_write_direct_ops, data); |
@@ -538,7 +539,7 @@ static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, struct inode | |||
538 | } while (count != 0); | 539 | } while (count != 0); |
539 | } | 540 | } |
540 | 541 | ||
541 | static ssize_t nfs_direct_write_seg(struct inode *inode, struct nfs_open_context *ctx, unsigned long user_addr, size_t count, loff_t file_offset, struct page **pages, int nr_pages) | 542 | static ssize_t nfs_direct_write(struct inode *inode, struct nfs_open_context *ctx, unsigned long user_addr, size_t count, loff_t file_offset, struct page **pages, int nr_pages) |
542 | { | 543 | { |
543 | ssize_t result; | 544 | ssize_t result; |
544 | sigset_t oldset; | 545 | sigset_t oldset; |
@@ -552,6 +553,8 @@ static ssize_t nfs_direct_write_seg(struct inode *inode, struct nfs_open_context | |||
552 | dreq->pages = pages; | 553 | dreq->pages = pages; |
553 | dreq->npages = nr_pages; | 554 | dreq->npages = nr_pages; |
554 | 555 | ||
556 | nfs_add_stats(inode, NFSIOS_DIRECTWRITTENBYTES, count); | ||
557 | |||
555 | nfs_begin_data_update(inode); | 558 | nfs_begin_data_update(inode); |
556 | 559 | ||
557 | rpc_clnt_sigmask(clnt, &oldset); | 560 | rpc_clnt_sigmask(clnt, &oldset); |
@@ -565,50 +568,6 @@ static ssize_t nfs_direct_write_seg(struct inode *inode, struct nfs_open_context | |||
565 | return result; | 568 | return result; |
566 | } | 569 | } |
567 | 570 | ||
568 | /* | ||
569 | * Upon return, generic_file_direct_IO invalidates any cached pages | ||
570 | * that non-direct readers might access, so they will pick up these | ||
571 | * writes immediately. | ||
572 | */ | ||
573 | static ssize_t nfs_direct_write(struct inode *inode, struct nfs_open_context *ctx, const struct iovec *iov, loff_t file_offset, unsigned long nr_segs) | ||
574 | { | ||
575 | ssize_t tot_bytes = 0; | ||
576 | unsigned long seg = 0; | ||
577 | |||
578 | while ((seg < nr_segs) && (tot_bytes >= 0)) { | ||
579 | ssize_t result; | ||
580 | int page_count; | ||
581 | struct page **pages; | ||
582 | const struct iovec *vec = &iov[seg++]; | ||
583 | unsigned long user_addr = (unsigned long) vec->iov_base; | ||
584 | size_t size = vec->iov_len; | ||
585 | |||
586 | page_count = nfs_get_user_pages(WRITE, user_addr, size, &pages); | ||
587 | if (page_count < 0) { | ||
588 | nfs_free_user_pages(pages, 0, 0); | ||
589 | if (tot_bytes > 0) | ||
590 | break; | ||
591 | return page_count; | ||
592 | } | ||
593 | |||
594 | nfs_add_stats(inode, NFSIOS_DIRECTWRITTENBYTES, size); | ||
595 | result = nfs_direct_write_seg(inode, ctx, user_addr, size, | ||
596 | file_offset, pages, page_count); | ||
597 | |||
598 | if (result <= 0) { | ||
599 | if (tot_bytes > 0) | ||
600 | break; | ||
601 | return result; | ||
602 | } | ||
603 | nfs_add_stats(inode, NFSIOS_SERVERWRITTENBYTES, result); | ||
604 | tot_bytes += result; | ||
605 | file_offset += result; | ||
606 | if (result < size) | ||
607 | break; | ||
608 | } | ||
609 | return tot_bytes; | ||
610 | } | ||
611 | |||
612 | /** | 571 | /** |
613 | * nfs_file_direct_read - file direct read operation for NFS files | 572 | * nfs_file_direct_read - file direct read operation for NFS files |
614 | * @iocb: target I/O control block | 573 | * @iocb: target I/O control block |
@@ -701,14 +660,13 @@ out: | |||
701 | ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) | 660 | ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) |
702 | { | 661 | { |
703 | ssize_t retval; | 662 | ssize_t retval; |
663 | int page_count; | ||
664 | struct page **pages; | ||
704 | struct file *file = iocb->ki_filp; | 665 | struct file *file = iocb->ki_filp; |
705 | struct nfs_open_context *ctx = | 666 | struct nfs_open_context *ctx = |
706 | (struct nfs_open_context *) file->private_data; | 667 | (struct nfs_open_context *) file->private_data; |
707 | struct address_space *mapping = file->f_mapping; | 668 | struct address_space *mapping = file->f_mapping; |
708 | struct inode *inode = mapping->host; | 669 | struct inode *inode = mapping->host; |
709 | struct iovec iov = { | ||
710 | .iov_base = (char __user *)buf, | ||
711 | }; | ||
712 | 670 | ||
713 | dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n", | 671 | dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n", |
714 | file->f_dentry->d_parent->d_name.name, | 672 | file->f_dentry->d_parent->d_name.name, |
@@ -729,17 +687,25 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t | |||
729 | retval = 0; | 687 | retval = 0; |
730 | if (!count) | 688 | if (!count) |
731 | goto out; | 689 | goto out; |
732 | iov.iov_len = count, | ||
733 | 690 | ||
734 | retval = -EFAULT; | 691 | retval = -EFAULT; |
735 | if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) | 692 | if (!access_ok(VERIFY_READ, buf, count)) |
736 | goto out; | 693 | goto out; |
737 | 694 | ||
738 | retval = nfs_sync_mapping(mapping); | 695 | retval = nfs_sync_mapping(mapping); |
739 | if (retval) | 696 | if (retval) |
740 | goto out; | 697 | goto out; |
741 | 698 | ||
742 | retval = nfs_direct_write(inode, ctx, &iov, pos, 1); | 699 | page_count = nfs_get_user_pages(WRITE, (unsigned long) buf, |
700 | count, &pages); | ||
701 | if (page_count < 0) { | ||
702 | nfs_free_user_pages(pages, 0, 0); | ||
703 | retval = page_count; | ||
704 | goto out; | ||
705 | } | ||
706 | |||
707 | retval = nfs_direct_write(inode, ctx, (unsigned long) buf, count, | ||
708 | pos, pages, page_count); | ||
743 | if (mapping->nrpages) | 709 | if (mapping->nrpages) |
744 | invalidate_inode_pages2(mapping); | 710 | invalidate_inode_pages2(mapping); |
745 | if (retval > 0) | 711 | if (retval > 0) |