diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-02-04 14:07:43 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-04-01 23:19:23 -0400 |
commit | 7f25bba819a38ab7310024a9350655f374707e20 (patch) | |
tree | d93d7fcf6db340dc8078b18555d0abb4611ef488 /fs/cifs | |
parent | 6130f5315ee80a591285a25957af71621bd0f17e (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/cifs')
-rw-r--r-- | fs/cifs/file.c | 62 |
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 | */ |
2739 | static ssize_t | 2736 | static int |
2740 | cifs_readdata_to_iov(struct cifs_readdata *rdata, const struct iovec *iov, | 2737 | cifs_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 | ||
2782 | static void | 2753 | static 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 | ||