aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-02-04 14:07:43 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2014-04-01 23:19:23 -0400
commit7f25bba819a38ab7310024a9350655f374707e20 (patch)
treed93d7fcf6db340dc8078b18555d0abb4611ef488 /fs
parent6130f5315ee80a591285a25957af71621bd0f17e (diff)
cifs_iovec_read: keep iov_iter between the calls of cifs_readdata_to_iov()
... we are doing them on adjacent parts of file, so what happens is that each subsequent call works to rebuild the iov_iter to exact state it had been abandoned in by previous one. Just keep it through the entire cifs_iovec_read(). And use copy_page_to_iter() instead of doing kmap/copy_to_user/kunmap manually... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/file.c62
1 files changed, 17 insertions, 45 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index df414db74ab9..ad63e4740aff 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2727,56 +2727,27 @@ cifs_retry_async_readv(struct cifs_readdata *rdata)
2727/** 2727/**
2728 * cifs_readdata_to_iov - copy data from pages in response to an iovec 2728 * cifs_readdata_to_iov - copy data from pages in response to an iovec
2729 * @rdata: the readdata response with list of pages holding data 2729 * @rdata: the readdata response with list of pages holding data
2730 * @iov: vector in which we should copy the data 2730 * @iter: destination for our data
2731 * @nr_segs: number of segments in vector
2732 * @offset: offset into file of the first iovec
2733 * @copied: used to return the amount of data copied to the iov
2734 * 2731 *
2735 * This function copies data from a list of pages in a readdata response into 2732 * This function copies data from a list of pages in a readdata response into
2736 * an array of iovecs. It will first calculate where the data should go 2733 * an array of iovecs. It will first calculate where the data should go
2737 * based on the info in the readdata and then copy the data into that spot. 2734 * based on the info in the readdata and then copy the data into that spot.
2738 */ 2735 */
2739static ssize_t 2736static int
2740cifs_readdata_to_iov(struct cifs_readdata *rdata, const struct iovec *iov, 2737cifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter)
2741 unsigned long nr_segs, loff_t offset, ssize_t *copied)
2742{ 2738{
2743 int rc = 0; 2739 size_t remaining = rdata->bytes;
2744 struct iov_iter ii;
2745 size_t pos = rdata->offset - offset;
2746 ssize_t remaining = rdata->bytes;
2747 unsigned char *pdata;
2748 unsigned int i; 2740 unsigned int i;
2749 2741
2750 /* set up iov_iter and advance to the correct offset */
2751 iov_iter_init(&ii, iov, nr_segs, iov_length(iov, nr_segs), 0);
2752 iov_iter_advance(&ii, pos);
2753
2754 *copied = 0;
2755 for (i = 0; i < rdata->nr_pages; i++) { 2742 for (i = 0; i < rdata->nr_pages; i++) {
2756 ssize_t copy;
2757 struct page *page = rdata->pages[i]; 2743 struct page *page = rdata->pages[i];
2758 2744 size_t copy = min(remaining, PAGE_SIZE);
2759 /* copy a whole page or whatever's left */ 2745 size_t written = copy_page_to_iter(page, 0, copy, iter);
2760 copy = min_t(ssize_t, remaining, PAGE_SIZE); 2746 remaining -= written;
2761 2747 if (written < copy && iov_iter_count(iter) > 0)
2762 /* ...but limit it to whatever space is left in the iov */ 2748 break;
2763 copy = min_t(ssize_t, copy, iov_iter_count(&ii));
2764
2765 /* go while there's data to be copied and no errors */
2766 if (copy && !rc) {
2767 pdata = kmap(page);
2768 rc = memcpy_toiovecend(ii.iov, pdata, ii.iov_offset,
2769 (int)copy);
2770 kunmap(page);
2771 if (!rc) {
2772 *copied += copy;
2773 remaining -= copy;
2774 iov_iter_advance(&ii, copy);
2775 }
2776 }
2777 } 2749 }
2778 2750 return remaining ? -EFAULT : 0;
2779 return rc;
2780} 2751}
2781 2752
2782static void 2753static void
@@ -2851,6 +2822,7 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
2851 struct cifsFileInfo *open_file; 2822 struct cifsFileInfo *open_file;
2852 struct cifs_readdata *rdata, *tmp; 2823 struct cifs_readdata *rdata, *tmp;
2853 struct list_head rdata_list; 2824 struct list_head rdata_list;
2825 struct iov_iter to;
2854 pid_t pid; 2826 pid_t pid;
2855 2827
2856 if (!nr_segs) 2828 if (!nr_segs)
@@ -2860,6 +2832,8 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
2860 if (!len) 2832 if (!len)
2861 return 0; 2833 return 0;
2862 2834
2835 iov_iter_init(&to, iov, nr_segs, len, 0);
2836
2863 INIT_LIST_HEAD(&rdata_list); 2837 INIT_LIST_HEAD(&rdata_list);
2864 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); 2838 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
2865 open_file = file->private_data; 2839 open_file = file->private_data;
@@ -2917,12 +2891,11 @@ error:
2917 if (!list_empty(&rdata_list)) 2891 if (!list_empty(&rdata_list))
2918 rc = 0; 2892 rc = 0;
2919 2893
2894 len = iov_iter_count(&to);
2920 /* the loop below should proceed in the order of increasing offsets */ 2895 /* the loop below should proceed in the order of increasing offsets */
2921 list_for_each_entry_safe(rdata, tmp, &rdata_list, list) { 2896 list_for_each_entry_safe(rdata, tmp, &rdata_list, list) {
2922 again: 2897 again:
2923 if (!rc) { 2898 if (!rc) {
2924 ssize_t copied;
2925
2926 /* FIXME: freezable sleep too? */ 2899 /* FIXME: freezable sleep too? */
2927 rc = wait_for_completion_killable(&rdata->done); 2900 rc = wait_for_completion_killable(&rdata->done);
2928 if (rc) 2901 if (rc)
@@ -2935,10 +2908,7 @@ error:
2935 goto again; 2908 goto again;
2936 } 2909 }
2937 } else { 2910 } else {
2938 rc = cifs_readdata_to_iov(rdata, iov, 2911 rc = cifs_readdata_to_iov(rdata, &to);
2939 nr_segs, *poffset,
2940 &copied);
2941 total_read += copied;
2942 } 2912 }
2943 2913
2944 } 2914 }
@@ -2946,6 +2916,8 @@ error:
2946 kref_put(&rdata->refcount, cifs_uncached_readdata_release); 2916 kref_put(&rdata->refcount, cifs_uncached_readdata_release);
2947 } 2917 }
2948 2918
2919 total_read = len - iov_iter_count(&to);
2920
2949 cifs_stats_bytes_read(tcon, total_read); 2921 cifs_stats_bytes_read(tcon, total_read);
2950 *poffset += total_read; 2922 *poffset += total_read;
2951 2923