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; |
