aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/direct.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r--fs/nfs/direct.c68
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
541static 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) 542static 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 */
573static 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:
701ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) 660ssize_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)