Commit 7f25bba819a38ab7310024a9350655f374707e20
1 parent
6130f5315e
Exists in
master
and in
13 other branches
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>
Showing 1 changed file with 17 additions and 45 deletions Side-by-side Diff
fs/cifs/file.c
... | ... | @@ -2727,56 +2727,27 @@ |
2727 | 2727 | /** |
2728 | 2728 | * cifs_readdata_to_iov - copy data from pages in response to an iovec |
2729 | 2729 | * @rdata: the readdata response with list of pages holding data |
2730 | - * @iov: vector in which we should copy the 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 | |
2730 | + * @iter: destination for our data | |
2734 | 2731 | * |
2735 | 2732 | * This function copies data from a list of pages in a readdata response into |
2736 | 2733 | * an array of iovecs. It will first calculate where the data should go |
2737 | 2734 | * based on the info in the readdata and then copy the data into that spot. |
2738 | 2735 | */ |
2739 | -static ssize_t | |
2740 | -cifs_readdata_to_iov(struct cifs_readdata *rdata, const struct iovec *iov, | |
2741 | - unsigned long nr_segs, loff_t offset, ssize_t *copied) | |
2736 | +static int | |
2737 | +cifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter) | |
2742 | 2738 | { |
2743 | - int rc = 0; | |
2744 | - struct iov_iter ii; | |
2745 | - size_t pos = rdata->offset - offset; | |
2746 | - ssize_t remaining = rdata->bytes; | |
2747 | - unsigned char *pdata; | |
2739 | + size_t remaining = rdata->bytes; | |
2748 | 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 | 2742 | for (i = 0; i < rdata->nr_pages; i++) { |
2756 | - ssize_t copy; | |
2757 | 2743 | struct page *page = rdata->pages[i]; |
2758 | - | |
2759 | - /* copy a whole page or whatever's left */ | |
2760 | - copy = min_t(ssize_t, remaining, PAGE_SIZE); | |
2761 | - | |
2762 | - /* ...but limit it to whatever space is left in the iov */ | |
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 | - } | |
2744 | + size_t copy = min(remaining, PAGE_SIZE); | |
2745 | + size_t written = copy_page_to_iter(page, 0, copy, iter); | |
2746 | + remaining -= written; | |
2747 | + if (written < copy && iov_iter_count(iter) > 0) | |
2748 | + break; | |
2777 | 2749 | } |
2778 | - | |
2779 | - return rc; | |
2750 | + return remaining ? -EFAULT : 0; | |
2780 | 2751 | } |
2781 | 2752 | |
2782 | 2753 | static void |
... | ... | @@ -2851,6 +2822,7 @@ |
2851 | 2822 | struct cifsFileInfo *open_file; |
2852 | 2823 | struct cifs_readdata *rdata, *tmp; |
2853 | 2824 | struct list_head rdata_list; |
2825 | + struct iov_iter to; | |
2854 | 2826 | pid_t pid; |
2855 | 2827 | |
2856 | 2828 | if (!nr_segs) |
... | ... | @@ -2860,6 +2832,8 @@ |
2860 | 2832 | if (!len) |
2861 | 2833 | return 0; |
2862 | 2834 | |
2835 | + iov_iter_init(&to, iov, nr_segs, len, 0); | |
2836 | + | |
2863 | 2837 | INIT_LIST_HEAD(&rdata_list); |
2864 | 2838 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
2865 | 2839 | open_file = file->private_data; |
2866 | 2840 | |
... | ... | @@ -2917,12 +2891,11 @@ |
2917 | 2891 | if (!list_empty(&rdata_list)) |
2918 | 2892 | rc = 0; |
2919 | 2893 | |
2894 | + len = iov_iter_count(&to); | |
2920 | 2895 | /* the loop below should proceed in the order of increasing offsets */ |
2921 | 2896 | list_for_each_entry_safe(rdata, tmp, &rdata_list, list) { |
2922 | 2897 | again: |
2923 | 2898 | if (!rc) { |
2924 | - ssize_t copied; | |
2925 | - | |
2926 | 2899 | /* FIXME: freezable sleep too? */ |
2927 | 2900 | rc = wait_for_completion_killable(&rdata->done); |
2928 | 2901 | if (rc) |
2929 | 2902 | |
... | ... | @@ -2935,16 +2908,15 @@ |
2935 | 2908 | goto again; |
2936 | 2909 | } |
2937 | 2910 | } else { |
2938 | - rc = cifs_readdata_to_iov(rdata, iov, | |
2939 | - nr_segs, *poffset, | |
2940 | - &copied); | |
2941 | - total_read += copied; | |
2911 | + rc = cifs_readdata_to_iov(rdata, &to); | |
2942 | 2912 | } |
2943 | 2913 | |
2944 | 2914 | } |
2945 | 2915 | list_del_init(&rdata->list); |
2946 | 2916 | kref_put(&rdata->refcount, cifs_uncached_readdata_release); |
2947 | 2917 | } |
2918 | + | |
2919 | + total_read = len - iov_iter_count(&to); | |
2948 | 2920 | |
2949 | 2921 | cifs_stats_bytes_read(tcon, total_read); |
2950 | 2922 | *poffset += total_read; |