|
@@ -705,14 +705,13 @@ static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count,
|
|
}
|
|
}
|
|
|
|
|
|
static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs,
|
|
static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs,
|
|
- struct sg_iovec *iov, int iov_count, int uncopy,
|
|
|
|
- int do_free_page)
|
|
|
|
|
|
+ struct sg_iovec *iov, int iov_count,
|
|
|
|
+ int to_user, int from_user, int do_free_page)
|
|
{
|
|
{
|
|
int ret = 0, i;
|
|
int ret = 0, i;
|
|
struct bio_vec *bvec;
|
|
struct bio_vec *bvec;
|
|
int iov_idx = 0;
|
|
int iov_idx = 0;
|
|
unsigned int iov_off = 0;
|
|
unsigned int iov_off = 0;
|
|
- int read = bio_data_dir(bio) == READ;
|
|
|
|
|
|
|
|
__bio_for_each_segment(bvec, bio, i, 0) {
|
|
__bio_for_each_segment(bvec, bio, i, 0) {
|
|
char *bv_addr = page_address(bvec->bv_page);
|
|
char *bv_addr = page_address(bvec->bv_page);
|
|
@@ -727,13 +726,14 @@ static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs,
|
|
iov_addr = iov[iov_idx].iov_base + iov_off;
|
|
iov_addr = iov[iov_idx].iov_base + iov_off;
|
|
|
|
|
|
if (!ret) {
|
|
if (!ret) {
|
|
- if (!read && !uncopy)
|
|
|
|
- ret = copy_from_user(bv_addr, iov_addr,
|
|
|
|
- bytes);
|
|
|
|
- if (read && uncopy)
|
|
|
|
|
|
+ if (to_user)
|
|
ret = copy_to_user(iov_addr, bv_addr,
|
|
ret = copy_to_user(iov_addr, bv_addr,
|
|
bytes);
|
|
bytes);
|
|
|
|
|
|
|
|
+ if (from_user)
|
|
|
|
+ ret = copy_from_user(bv_addr, iov_addr,
|
|
|
|
+ bytes);
|
|
|
|
+
|
|
if (ret)
|
|
if (ret)
|
|
ret = -EFAULT;
|
|
ret = -EFAULT;
|
|
}
|
|
}
|
|
@@ -770,7 +770,8 @@ int bio_uncopy_user(struct bio *bio)
|
|
|
|
|
|
if (!bio_flagged(bio, BIO_NULL_MAPPED))
|
|
if (!bio_flagged(bio, BIO_NULL_MAPPED))
|
|
ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs,
|
|
ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs,
|
|
- bmd->nr_sgvecs, 1, bmd->is_our_pages);
|
|
|
|
|
|
+ bmd->nr_sgvecs, bio_data_dir(bio) == READ,
|
|
|
|
+ 0, bmd->is_our_pages);
|
|
bio_free_map_data(bmd);
|
|
bio_free_map_data(bmd);
|
|
bio_put(bio);
|
|
bio_put(bio);
|
|
return ret;
|
|
return ret;
|
|
@@ -875,8 +876,9 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
|
|
/*
|
|
/*
|
|
* success
|
|
* success
|
|
*/
|
|
*/
|
|
- if (!write_to_vm && (!map_data || !map_data->null_mapped)) {
|
|
|
|
- ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 0);
|
|
|
|
|
|
+ if ((!write_to_vm && (!map_data || !map_data->null_mapped)) ||
|
|
|
|
+ (map_data && map_data->from_user)) {
|
|
|
|
+ ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 1, 0);
|
|
if (ret)
|
|
if (ret)
|
|
goto cleanup;
|
|
goto cleanup;
|
|
}
|
|
}
|