diff options
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r-- | fs/nfs/direct.c | 81 |
1 files changed, 32 insertions, 49 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index b497c71384e8..10ae377e68ff 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -122,9 +122,10 @@ nfs_free_user_pages(struct page **pages, int npages, int do_dirty) | |||
122 | { | 122 | { |
123 | int i; | 123 | int i; |
124 | for (i = 0; i < npages; i++) { | 124 | for (i = 0; i < npages; i++) { |
125 | if (do_dirty) | 125 | struct page *page = pages[i]; |
126 | set_page_dirty_lock(pages[i]); | 126 | if (do_dirty && !PageCompound(page)) |
127 | page_cache_release(pages[i]); | 127 | set_page_dirty_lock(page); |
128 | page_cache_release(page); | ||
128 | } | 129 | } |
129 | kfree(pages); | 130 | kfree(pages); |
130 | } | 131 | } |
@@ -154,6 +155,7 @@ static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, unsigned int | |||
154 | struct list_head *list; | 155 | struct list_head *list; |
155 | struct nfs_direct_req *dreq; | 156 | struct nfs_direct_req *dreq; |
156 | unsigned int reads = 0; | 157 | unsigned int reads = 0; |
158 | unsigned int rpages = (rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
157 | 159 | ||
158 | dreq = kmem_cache_alloc(nfs_direct_cachep, SLAB_KERNEL); | 160 | dreq = kmem_cache_alloc(nfs_direct_cachep, SLAB_KERNEL); |
159 | if (!dreq) | 161 | if (!dreq) |
@@ -167,7 +169,7 @@ static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, unsigned int | |||
167 | 169 | ||
168 | list = &dreq->list; | 170 | list = &dreq->list; |
169 | for(;;) { | 171 | for(;;) { |
170 | struct nfs_read_data *data = nfs_readdata_alloc(); | 172 | struct nfs_read_data *data = nfs_readdata_alloc(rpages); |
171 | 173 | ||
172 | if (unlikely(!data)) { | 174 | if (unlikely(!data)) { |
173 | while (!list_empty(list)) { | 175 | while (!list_empty(list)) { |
@@ -268,8 +270,6 @@ static void nfs_direct_read_schedule(struct nfs_direct_req *dreq, | |||
268 | NFS_PROTO(inode)->read_setup(data); | 270 | NFS_PROTO(inode)->read_setup(data); |
269 | 271 | ||
270 | data->task.tk_cookie = (unsigned long) inode; | 272 | data->task.tk_cookie = (unsigned long) inode; |
271 | data->task.tk_calldata = data; | ||
272 | data->task.tk_release = nfs_readdata_release; | ||
273 | data->complete = nfs_direct_read_result; | 273 | data->complete = nfs_direct_read_result; |
274 | 274 | ||
275 | lock_kernel(); | 275 | lock_kernel(); |
@@ -433,7 +433,7 @@ static ssize_t nfs_direct_write_seg(struct inode *inode, | |||
433 | struct nfs_writeverf first_verf; | 433 | struct nfs_writeverf first_verf; |
434 | struct nfs_write_data *wdata; | 434 | struct nfs_write_data *wdata; |
435 | 435 | ||
436 | wdata = nfs_writedata_alloc(); | 436 | wdata = nfs_writedata_alloc(NFS_SERVER(inode)->wpages); |
437 | if (!wdata) | 437 | if (!wdata) |
438 | return -ENOMEM; | 438 | return -ENOMEM; |
439 | 439 | ||
@@ -662,10 +662,10 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t | |||
662 | .iov_len = count, | 662 | .iov_len = count, |
663 | }; | 663 | }; |
664 | 664 | ||
665 | dprintk("nfs: direct read(%s/%s, %lu@%lu)\n", | 665 | dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n", |
666 | file->f_dentry->d_parent->d_name.name, | 666 | file->f_dentry->d_parent->d_name.name, |
667 | file->f_dentry->d_name.name, | 667 | file->f_dentry->d_name.name, |
668 | (unsigned long) count, (unsigned long) pos); | 668 | (unsigned long) count, (long long) pos); |
669 | 669 | ||
670 | if (!is_sync_kiocb(iocb)) | 670 | if (!is_sync_kiocb(iocb)) |
671 | goto out; | 671 | goto out; |
@@ -678,15 +678,9 @@ nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t | |||
678 | if (!count) | 678 | if (!count) |
679 | goto out; | 679 | goto out; |
680 | 680 | ||
681 | if (mapping->nrpages) { | 681 | retval = nfs_sync_mapping(mapping); |
682 | retval = filemap_fdatawrite(mapping); | 682 | if (retval) |
683 | if (retval == 0) | 683 | goto out; |
684 | retval = nfs_wb_all(inode); | ||
685 | if (retval == 0) | ||
686 | retval = filemap_fdatawait(mapping); | ||
687 | if (retval) | ||
688 | goto out; | ||
689 | } | ||
690 | 684 | ||
691 | retval = nfs_direct_read(inode, ctx, &iov, pos, 1); | 685 | retval = nfs_direct_read(inode, ctx, &iov, pos, 1); |
692 | if (retval > 0) | 686 | if (retval > 0) |
@@ -724,9 +718,7 @@ out: | |||
724 | ssize_t | 718 | ssize_t |
725 | nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) | 719 | nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) |
726 | { | 720 | { |
727 | ssize_t retval = -EINVAL; | 721 | ssize_t retval; |
728 | loff_t *ppos = &iocb->ki_pos; | ||
729 | unsigned long limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | ||
730 | struct file *file = iocb->ki_filp; | 722 | struct file *file = iocb->ki_filp; |
731 | struct nfs_open_context *ctx = | 723 | struct nfs_open_context *ctx = |
732 | (struct nfs_open_context *) file->private_data; | 724 | (struct nfs_open_context *) file->private_data; |
@@ -734,51 +726,42 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, | |||
734 | struct inode *inode = mapping->host; | 726 | struct inode *inode = mapping->host; |
735 | struct iovec iov = { | 727 | struct iovec iov = { |
736 | .iov_base = (char __user *)buf, | 728 | .iov_base = (char __user *)buf, |
737 | .iov_len = count, | ||
738 | }; | 729 | }; |
739 | 730 | ||
740 | dfprintk(VFS, "nfs: direct write(%s/%s(%ld), %lu@%lu)\n", | 731 | dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n", |
741 | file->f_dentry->d_parent->d_name.name, | 732 | file->f_dentry->d_parent->d_name.name, |
742 | file->f_dentry->d_name.name, inode->i_ino, | 733 | file->f_dentry->d_name.name, |
743 | (unsigned long) count, (unsigned long) pos); | 734 | (unsigned long) count, (long long) pos); |
744 | 735 | ||
736 | retval = -EINVAL; | ||
745 | if (!is_sync_kiocb(iocb)) | 737 | if (!is_sync_kiocb(iocb)) |
746 | goto out; | 738 | goto out; |
747 | if (count < 0) | 739 | |
748 | goto out; | 740 | retval = generic_write_checks(file, &pos, &count, 0); |
749 | if (pos < 0) | 741 | if (retval) |
750 | goto out; | 742 | goto out; |
751 | retval = -EFAULT; | 743 | |
752 | if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) | 744 | retval = -EINVAL; |
745 | if ((ssize_t) count < 0) | ||
753 | goto out; | 746 | goto out; |
754 | retval = -EFBIG; | ||
755 | if (limit != RLIM_INFINITY) { | ||
756 | if (pos >= limit) { | ||
757 | send_sig(SIGXFSZ, current, 0); | ||
758 | goto out; | ||
759 | } | ||
760 | if (count > limit - (unsigned long) pos) | ||
761 | count = limit - (unsigned long) pos; | ||
762 | } | ||
763 | retval = 0; | 747 | retval = 0; |
764 | if (!count) | 748 | if (!count) |
765 | goto out; | 749 | goto out; |
750 | iov.iov_len = count, | ||
766 | 751 | ||
767 | if (mapping->nrpages) { | 752 | retval = -EFAULT; |
768 | retval = filemap_fdatawrite(mapping); | 753 | if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) |
769 | if (retval == 0) | 754 | goto out; |
770 | retval = nfs_wb_all(inode); | 755 | |
771 | if (retval == 0) | 756 | retval = nfs_sync_mapping(mapping); |
772 | retval = filemap_fdatawait(mapping); | 757 | if (retval) |
773 | if (retval) | 758 | goto out; |
774 | goto out; | ||
775 | } | ||
776 | 759 | ||
777 | retval = nfs_direct_write(inode, ctx, &iov, pos, 1); | 760 | retval = nfs_direct_write(inode, ctx, &iov, pos, 1); |
778 | if (mapping->nrpages) | 761 | if (mapping->nrpages) |
779 | invalidate_inode_pages2(mapping); | 762 | invalidate_inode_pages2(mapping); |
780 | if (retval > 0) | 763 | if (retval > 0) |
781 | *ppos = pos + retval; | 764 | iocb->ki_pos = pos + retval; |
782 | 765 | ||
783 | out: | 766 | out: |
784 | return retval; | 767 | return retval; |