diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 128 |
1 files changed, 52 insertions, 76 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 216d7e99f921..8807442c94dd 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -2579,19 +2579,32 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov, | |||
2579 | struct cifsInodeInfo *cinode = CIFS_I(inode); | 2579 | struct cifsInodeInfo *cinode = CIFS_I(inode); |
2580 | struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; | 2580 | struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; |
2581 | ssize_t rc = -EACCES; | 2581 | ssize_t rc = -EACCES; |
2582 | loff_t lock_pos = pos; | 2582 | loff_t lock_pos = iocb->ki_pos; |
2583 | 2583 | ||
2584 | if (file->f_flags & O_APPEND) | ||
2585 | lock_pos = i_size_read(inode); | ||
2586 | /* | 2584 | /* |
2587 | * We need to hold the sem to be sure nobody modifies lock list | 2585 | * We need to hold the sem to be sure nobody modifies lock list |
2588 | * with a brlock that prevents writing. | 2586 | * with a brlock that prevents writing. |
2589 | */ | 2587 | */ |
2590 | down_read(&cinode->lock_sem); | 2588 | down_read(&cinode->lock_sem); |
2589 | mutex_lock(&inode->i_mutex); | ||
2590 | if (file->f_flags & O_APPEND) | ||
2591 | lock_pos = i_size_read(inode); | ||
2591 | if (!cifs_find_lock_conflict(cfile, lock_pos, iov_length(iov, nr_segs), | 2592 | if (!cifs_find_lock_conflict(cfile, lock_pos, iov_length(iov, nr_segs), |
2592 | server->vals->exclusive_lock_type, NULL, | 2593 | server->vals->exclusive_lock_type, NULL, |
2593 | CIFS_WRITE_OP)) | 2594 | CIFS_WRITE_OP)) { |
2594 | rc = generic_file_aio_write(iocb, iov, nr_segs, pos); | 2595 | rc = __generic_file_aio_write(iocb, iov, nr_segs); |
2596 | mutex_unlock(&inode->i_mutex); | ||
2597 | |||
2598 | if (rc > 0) { | ||
2599 | ssize_t err; | ||
2600 | |||
2601 | err = generic_write_sync(file, iocb->ki_pos - rc, rc); | ||
2602 | if (rc < 0) | ||
2603 | rc = err; | ||
2604 | } | ||
2605 | } else { | ||
2606 | mutex_unlock(&inode->i_mutex); | ||
2607 | } | ||
2595 | up_read(&cinode->lock_sem); | 2608 | up_read(&cinode->lock_sem); |
2596 | return rc; | 2609 | return rc; |
2597 | } | 2610 | } |
@@ -2727,56 +2740,27 @@ cifs_retry_async_readv(struct cifs_readdata *rdata) | |||
2727 | /** | 2740 | /** |
2728 | * cifs_readdata_to_iov - copy data from pages in response to an iovec | 2741 | * cifs_readdata_to_iov - copy data from pages in response to an iovec |
2729 | * @rdata: the readdata response with list of pages holding data | 2742 | * @rdata: the readdata response with list of pages holding data |
2730 | * @iov: vector in which we should copy the data | 2743 | * @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 | * | 2744 | * |
2735 | * This function copies data from a list of pages in a readdata response into | 2745 | * 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 | 2746 | * 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. | 2747 | * based on the info in the readdata and then copy the data into that spot. |
2738 | */ | 2748 | */ |
2739 | static ssize_t | 2749 | static int |
2740 | cifs_readdata_to_iov(struct cifs_readdata *rdata, const struct iovec *iov, | 2750 | cifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter) |
2741 | unsigned long nr_segs, loff_t offset, ssize_t *copied) | ||
2742 | { | 2751 | { |
2743 | int rc = 0; | 2752 | 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; | 2753 | unsigned int i; |
2749 | 2754 | ||
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++) { | 2755 | for (i = 0; i < rdata->nr_pages; i++) { |
2756 | ssize_t copy; | ||
2757 | struct page *page = rdata->pages[i]; | 2756 | struct page *page = rdata->pages[i]; |
2758 | 2757 | size_t copy = min(remaining, PAGE_SIZE); | |
2759 | /* copy a whole page or whatever's left */ | 2758 | size_t written = copy_page_to_iter(page, 0, copy, iter); |
2760 | copy = min_t(ssize_t, remaining, PAGE_SIZE); | 2759 | remaining -= written; |
2761 | 2760 | if (written < copy && iov_iter_count(iter) > 0) | |
2762 | /* ...but limit it to whatever space is left in the iov */ | 2761 | 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 | } | 2762 | } |
2778 | 2763 | return remaining ? -EFAULT : 0; | |
2779 | return rc; | ||
2780 | } | 2764 | } |
2781 | 2765 | ||
2782 | static void | 2766 | static void |
@@ -2837,20 +2821,21 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server, | |||
2837 | return total_read > 0 ? total_read : result; | 2821 | return total_read > 0 ? total_read : result; |
2838 | } | 2822 | } |
2839 | 2823 | ||
2840 | static ssize_t | 2824 | ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, |
2841 | cifs_iovec_read(struct file *file, const struct iovec *iov, | 2825 | unsigned long nr_segs, loff_t pos) |
2842 | unsigned long nr_segs, loff_t *poffset) | ||
2843 | { | 2826 | { |
2827 | struct file *file = iocb->ki_filp; | ||
2844 | ssize_t rc; | 2828 | ssize_t rc; |
2845 | size_t len, cur_len; | 2829 | size_t len, cur_len; |
2846 | ssize_t total_read = 0; | 2830 | ssize_t total_read = 0; |
2847 | loff_t offset = *poffset; | 2831 | loff_t offset = pos; |
2848 | unsigned int npages; | 2832 | unsigned int npages; |
2849 | struct cifs_sb_info *cifs_sb; | 2833 | struct cifs_sb_info *cifs_sb; |
2850 | struct cifs_tcon *tcon; | 2834 | struct cifs_tcon *tcon; |
2851 | struct cifsFileInfo *open_file; | 2835 | struct cifsFileInfo *open_file; |
2852 | struct cifs_readdata *rdata, *tmp; | 2836 | struct cifs_readdata *rdata, *tmp; |
2853 | struct list_head rdata_list; | 2837 | struct list_head rdata_list; |
2838 | struct iov_iter to; | ||
2854 | pid_t pid; | 2839 | pid_t pid; |
2855 | 2840 | ||
2856 | if (!nr_segs) | 2841 | if (!nr_segs) |
@@ -2860,6 +2845,8 @@ cifs_iovec_read(struct file *file, const struct iovec *iov, | |||
2860 | if (!len) | 2845 | if (!len) |
2861 | return 0; | 2846 | return 0; |
2862 | 2847 | ||
2848 | iov_iter_init(&to, iov, nr_segs, len, 0); | ||
2849 | |||
2863 | INIT_LIST_HEAD(&rdata_list); | 2850 | INIT_LIST_HEAD(&rdata_list); |
2864 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 2851 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
2865 | open_file = file->private_data; | 2852 | open_file = file->private_data; |
@@ -2917,55 +2904,44 @@ error: | |||
2917 | if (!list_empty(&rdata_list)) | 2904 | if (!list_empty(&rdata_list)) |
2918 | rc = 0; | 2905 | rc = 0; |
2919 | 2906 | ||
2907 | len = iov_iter_count(&to); | ||
2920 | /* the loop below should proceed in the order of increasing offsets */ | 2908 | /* the loop below should proceed in the order of increasing offsets */ |
2921 | restart_loop: | ||
2922 | list_for_each_entry_safe(rdata, tmp, &rdata_list, list) { | 2909 | list_for_each_entry_safe(rdata, tmp, &rdata_list, list) { |
2910 | again: | ||
2923 | if (!rc) { | 2911 | if (!rc) { |
2924 | ssize_t copied; | ||
2925 | |||
2926 | /* FIXME: freezable sleep too? */ | 2912 | /* FIXME: freezable sleep too? */ |
2927 | rc = wait_for_completion_killable(&rdata->done); | 2913 | rc = wait_for_completion_killable(&rdata->done); |
2928 | if (rc) | 2914 | if (rc) |
2929 | rc = -EINTR; | 2915 | rc = -EINTR; |
2930 | else if (rdata->result) | 2916 | else if (rdata->result) { |
2931 | rc = rdata->result; | 2917 | rc = rdata->result; |
2932 | else { | 2918 | /* resend call if it's a retryable error */ |
2933 | rc = cifs_readdata_to_iov(rdata, iov, | 2919 | if (rc == -EAGAIN) { |
2934 | nr_segs, *poffset, | 2920 | rc = cifs_retry_async_readv(rdata); |
2935 | &copied); | 2921 | goto again; |
2936 | total_read += copied; | 2922 | } |
2923 | } else { | ||
2924 | rc = cifs_readdata_to_iov(rdata, &to); | ||
2937 | } | 2925 | } |
2938 | 2926 | ||
2939 | /* resend call if it's a retryable error */ | ||
2940 | if (rc == -EAGAIN) { | ||
2941 | rc = cifs_retry_async_readv(rdata); | ||
2942 | goto restart_loop; | ||
2943 | } | ||
2944 | } | 2927 | } |
2945 | list_del_init(&rdata->list); | 2928 | list_del_init(&rdata->list); |
2946 | kref_put(&rdata->refcount, cifs_uncached_readdata_release); | 2929 | kref_put(&rdata->refcount, cifs_uncached_readdata_release); |
2947 | } | 2930 | } |
2948 | 2931 | ||
2932 | total_read = len - iov_iter_count(&to); | ||
2933 | |||
2949 | cifs_stats_bytes_read(tcon, total_read); | 2934 | cifs_stats_bytes_read(tcon, total_read); |
2950 | *poffset += total_read; | ||
2951 | 2935 | ||
2952 | /* mask nodata case */ | 2936 | /* mask nodata case */ |
2953 | if (rc == -ENODATA) | 2937 | if (rc == -ENODATA) |
2954 | rc = 0; | 2938 | rc = 0; |
2955 | 2939 | ||
2956 | return total_read ? total_read : rc; | 2940 | if (total_read) { |
2957 | } | 2941 | iocb->ki_pos = pos + total_read; |
2958 | 2942 | return total_read; | |
2959 | ssize_t cifs_user_readv(struct kiocb *iocb, const struct iovec *iov, | 2943 | } |
2960 | unsigned long nr_segs, loff_t pos) | 2944 | return rc; |
2961 | { | ||
2962 | ssize_t read; | ||
2963 | |||
2964 | read = cifs_iovec_read(iocb->ki_filp, iov, nr_segs, &pos); | ||
2965 | if (read > 0) | ||
2966 | iocb->ki_pos = pos; | ||
2967 | |||
2968 | return read; | ||
2969 | } | 2945 | } |
2970 | 2946 | ||
2971 | ssize_t | 2947 | ssize_t |