diff options
Diffstat (limited to 'fs/nfs/direct.c')
-rw-r--r-- | fs/nfs/direct.c | 57 |
1 files changed, 26 insertions, 31 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 079228817603..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; |
@@ -718,9 +718,7 @@ out: | |||
718 | ssize_t | 718 | ssize_t |
719 | 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) |
720 | { | 720 | { |
721 | ssize_t retval = -EINVAL; | 721 | ssize_t retval; |
722 | loff_t *ppos = &iocb->ki_pos; | ||
723 | unsigned long limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | ||
724 | struct file *file = iocb->ki_filp; | 722 | struct file *file = iocb->ki_filp; |
725 | struct nfs_open_context *ctx = | 723 | struct nfs_open_context *ctx = |
726 | (struct nfs_open_context *) file->private_data; | 724 | (struct nfs_open_context *) file->private_data; |
@@ -728,35 +726,32 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, | |||
728 | struct inode *inode = mapping->host; | 726 | struct inode *inode = mapping->host; |
729 | struct iovec iov = { | 727 | struct iovec iov = { |
730 | .iov_base = (char __user *)buf, | 728 | .iov_base = (char __user *)buf, |
731 | .iov_len = count, | ||
732 | }; | 729 | }; |
733 | 730 | ||
734 | dfprintk(VFS, "nfs: direct write(%s/%s(%ld), %lu@%lu)\n", | 731 | dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n", |
735 | file->f_dentry->d_parent->d_name.name, | 732 | file->f_dentry->d_parent->d_name.name, |
736 | file->f_dentry->d_name.name, inode->i_ino, | 733 | file->f_dentry->d_name.name, |
737 | (unsigned long) count, (unsigned long) pos); | 734 | (unsigned long) count, (long long) pos); |
738 | 735 | ||
736 | retval = -EINVAL; | ||
739 | if (!is_sync_kiocb(iocb)) | 737 | if (!is_sync_kiocb(iocb)) |
740 | goto out; | 738 | goto out; |
741 | if (count < 0) | 739 | |
742 | goto out; | 740 | retval = generic_write_checks(file, &pos, &count, 0); |
743 | if (pos < 0) | 741 | if (retval) |
744 | goto out; | 742 | goto out; |
745 | retval = -EFAULT; | 743 | |
746 | if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) | 744 | retval = -EINVAL; |
745 | if ((ssize_t) count < 0) | ||
747 | goto out; | 746 | goto out; |
748 | retval = -EFBIG; | ||
749 | if (limit != RLIM_INFINITY) { | ||
750 | if (pos >= limit) { | ||
751 | send_sig(SIGXFSZ, current, 0); | ||
752 | goto out; | ||
753 | } | ||
754 | if (count > limit - (unsigned long) pos) | ||
755 | count = limit - (unsigned long) pos; | ||
756 | } | ||
757 | retval = 0; | 747 | retval = 0; |
758 | if (!count) | 748 | if (!count) |
759 | goto out; | 749 | goto out; |
750 | iov.iov_len = count, | ||
751 | |||
752 | retval = -EFAULT; | ||
753 | if (!access_ok(VERIFY_READ, iov.iov_base, iov.iov_len)) | ||
754 | goto out; | ||
760 | 755 | ||
761 | retval = nfs_sync_mapping(mapping); | 756 | retval = nfs_sync_mapping(mapping); |
762 | if (retval) | 757 | if (retval) |
@@ -766,7 +761,7 @@ nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, | |||
766 | if (mapping->nrpages) | 761 | if (mapping->nrpages) |
767 | invalidate_inode_pages2(mapping); | 762 | invalidate_inode_pages2(mapping); |
768 | if (retval > 0) | 763 | if (retval > 0) |
769 | *ppos = pos + retval; | 764 | iocb->ki_pos = pos + retval; |
770 | 765 | ||
771 | out: | 766 | out: |
772 | return retval; | 767 | return retval; |