diff options
Diffstat (limited to 'fs/bio.c')
-rw-r--r-- | fs/bio.c | 22 |
1 files changed, 12 insertions, 10 deletions
@@ -705,14 +705,13 @@ static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count, | |||
705 | } | 705 | } |
706 | 706 | ||
707 | static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs, | 707 | static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs, |
708 | struct sg_iovec *iov, int iov_count, int uncopy, | 708 | struct sg_iovec *iov, int iov_count, |
709 | int do_free_page) | 709 | int to_user, int from_user, int do_free_page) |
710 | { | 710 | { |
711 | int ret = 0, i; | 711 | int ret = 0, i; |
712 | struct bio_vec *bvec; | 712 | struct bio_vec *bvec; |
713 | int iov_idx = 0; | 713 | int iov_idx = 0; |
714 | unsigned int iov_off = 0; | 714 | unsigned int iov_off = 0; |
715 | int read = bio_data_dir(bio) == READ; | ||
716 | 715 | ||
717 | __bio_for_each_segment(bvec, bio, i, 0) { | 716 | __bio_for_each_segment(bvec, bio, i, 0) { |
718 | char *bv_addr = page_address(bvec->bv_page); | 717 | char *bv_addr = page_address(bvec->bv_page); |
@@ -727,13 +726,14 @@ static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs, | |||
727 | iov_addr = iov[iov_idx].iov_base + iov_off; | 726 | iov_addr = iov[iov_idx].iov_base + iov_off; |
728 | 727 | ||
729 | if (!ret) { | 728 | if (!ret) { |
730 | if (!read && !uncopy) | 729 | if (to_user) |
731 | ret = copy_from_user(bv_addr, iov_addr, | ||
732 | bytes); | ||
733 | if (read && uncopy) | ||
734 | ret = copy_to_user(iov_addr, bv_addr, | 730 | ret = copy_to_user(iov_addr, bv_addr, |
735 | bytes); | 731 | bytes); |
736 | 732 | ||
733 | if (from_user) | ||
734 | ret = copy_from_user(bv_addr, iov_addr, | ||
735 | bytes); | ||
736 | |||
737 | if (ret) | 737 | if (ret) |
738 | ret = -EFAULT; | 738 | ret = -EFAULT; |
739 | } | 739 | } |
@@ -770,7 +770,8 @@ int bio_uncopy_user(struct bio *bio) | |||
770 | 770 | ||
771 | if (!bio_flagged(bio, BIO_NULL_MAPPED)) | 771 | if (!bio_flagged(bio, BIO_NULL_MAPPED)) |
772 | ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs, | 772 | ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs, |
773 | bmd->nr_sgvecs, 1, bmd->is_our_pages); | 773 | bmd->nr_sgvecs, bio_data_dir(bio) == READ, |
774 | 0, bmd->is_our_pages); | ||
774 | bio_free_map_data(bmd); | 775 | bio_free_map_data(bmd); |
775 | bio_put(bio); | 776 | bio_put(bio); |
776 | return ret; | 777 | return ret; |
@@ -875,8 +876,9 @@ struct bio *bio_copy_user_iov(struct request_queue *q, | |||
875 | /* | 876 | /* |
876 | * success | 877 | * success |
877 | */ | 878 | */ |
878 | if (!write_to_vm && (!map_data || !map_data->null_mapped)) { | 879 | if ((!write_to_vm && (!map_data || !map_data->null_mapped)) || |
879 | ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 0); | 880 | (map_data && map_data->from_user)) { |
881 | ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 1, 0); | ||
880 | if (ret) | 882 | if (ret) |
881 | goto cleanup; | 883 | goto cleanup; |
882 | } | 884 | } |