diff options
author | Dongsu Park <dongsu.park@profitbricks.com> | 2015-01-18 10:16:34 -0500 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2015-02-05 11:30:44 -0500 |
commit | 9124d3fe21b0947b03f4b87bcfb7acd675d6e85b (patch) | |
tree | a3d9e26708dab191bdce78a7a794f45971698694 /block | |
parent | 37f19e57a0de3c4a3417aa13ff4d04f1e0dee4b3 (diff) |
block: rewrite and split __bio_copy_iov()
Rewrite __bio_copy_iov using the copy_page_{from,to}_iter helpers, and
split it into two simpler functions.
This commit should contain only literal replacements, without
functional changes.
Cc: Kent Overstreet <kmo@daterainc.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Dongsu Park <dongsu.park@profitbricks.com>
[hch: removed the __bio_copy_iov wrapper]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Ming Lei <tom.leiming@gmail.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block')
-rw-r--r-- | block/bio.c | 90 |
1 files changed, 56 insertions, 34 deletions
diff --git a/block/bio.c b/block/bio.c index 0723d4ce8589..f66a4eae16ee 100644 --- a/block/bio.c +++ b/block/bio.c | |||
@@ -1036,43 +1036,66 @@ static struct bio_map_data *bio_alloc_map_data(unsigned int iov_count, | |||
1036 | sizeof(struct iovec) * iov_count, gfp_mask); | 1036 | sizeof(struct iovec) * iov_count, gfp_mask); |
1037 | } | 1037 | } |
1038 | 1038 | ||
1039 | static int __bio_copy_iov(struct bio *bio, const struct iov_iter *iter, | 1039 | /** |
1040 | int to_user, int from_user) | 1040 | * bio_copy_from_iter - copy all pages from iov_iter to bio |
1041 | * @bio: The &struct bio which describes the I/O as destination | ||
1042 | * @iter: iov_iter as source | ||
1043 | * | ||
1044 | * Copy all pages from iov_iter to bio. | ||
1045 | * Returns 0 on success, or error on failure. | ||
1046 | */ | ||
1047 | static int bio_copy_from_iter(struct bio *bio, struct iov_iter iter) | ||
1041 | { | 1048 | { |
1042 | int ret = 0, i; | 1049 | int i; |
1043 | struct bio_vec *bvec; | 1050 | struct bio_vec *bvec; |
1044 | struct iov_iter iov_iter = *iter; | ||
1045 | 1051 | ||
1046 | bio_for_each_segment_all(bvec, bio, i) { | 1052 | bio_for_each_segment_all(bvec, bio, i) { |
1047 | char *bv_addr = page_address(bvec->bv_page); | 1053 | ssize_t ret; |
1048 | unsigned int bv_len = bvec->bv_len; | ||
1049 | |||
1050 | while (bv_len && iov_iter.count) { | ||
1051 | struct iovec iov = iov_iter_iovec(&iov_iter); | ||
1052 | unsigned int bytes = min_t(unsigned int, bv_len, | ||
1053 | iov.iov_len); | ||
1054 | |||
1055 | if (!ret) { | ||
1056 | if (to_user) | ||
1057 | ret = copy_to_user(iov.iov_base, | ||
1058 | bv_addr, bytes); | ||
1059 | |||
1060 | if (from_user) | ||
1061 | ret = copy_from_user(bv_addr, | ||
1062 | iov.iov_base, | ||
1063 | bytes); | ||
1064 | |||
1065 | if (ret) | ||
1066 | ret = -EFAULT; | ||
1067 | } | ||
1068 | 1054 | ||
1069 | bv_len -= bytes; | 1055 | ret = copy_page_from_iter(bvec->bv_page, |
1070 | bv_addr += bytes; | 1056 | bvec->bv_offset, |
1071 | iov_iter_advance(&iov_iter, bytes); | 1057 | bvec->bv_len, |
1072 | } | 1058 | &iter); |
1059 | |||
1060 | if (!iov_iter_count(&iter)) | ||
1061 | break; | ||
1062 | |||
1063 | if (ret < bvec->bv_len) | ||
1064 | return -EFAULT; | ||
1073 | } | 1065 | } |
1074 | 1066 | ||
1075 | return ret; | 1067 | return 0; |
1068 | } | ||
1069 | |||
1070 | /** | ||
1071 | * bio_copy_to_iter - copy all pages from bio to iov_iter | ||
1072 | * @bio: The &struct bio which describes the I/O as source | ||
1073 | * @iter: iov_iter as destination | ||
1074 | * | ||
1075 | * Copy all pages from bio to iov_iter. | ||
1076 | * Returns 0 on success, or error on failure. | ||
1077 | */ | ||
1078 | static int bio_copy_to_iter(struct bio *bio, struct iov_iter iter) | ||
1079 | { | ||
1080 | int i; | ||
1081 | struct bio_vec *bvec; | ||
1082 | |||
1083 | bio_for_each_segment_all(bvec, bio, i) { | ||
1084 | ssize_t ret; | ||
1085 | |||
1086 | ret = copy_page_to_iter(bvec->bv_page, | ||
1087 | bvec->bv_offset, | ||
1088 | bvec->bv_len, | ||
1089 | &iter); | ||
1090 | |||
1091 | if (!iov_iter_count(&iter)) | ||
1092 | break; | ||
1093 | |||
1094 | if (ret < bvec->bv_len) | ||
1095 | return -EFAULT; | ||
1096 | } | ||
1097 | |||
1098 | return 0; | ||
1076 | } | 1099 | } |
1077 | 1100 | ||
1078 | static void bio_free_pages(struct bio *bio) | 1101 | static void bio_free_pages(struct bio *bio) |
@@ -1101,9 +1124,8 @@ int bio_uncopy_user(struct bio *bio) | |||
1101 | * if we're in a workqueue, the request is orphaned, so | 1124 | * if we're in a workqueue, the request is orphaned, so |
1102 | * don't copy into a random user address space, just free. | 1125 | * don't copy into a random user address space, just free. |
1103 | */ | 1126 | */ |
1104 | if (current->mm) | 1127 | if (current->mm && bio_data_dir(bio) == READ) |
1105 | ret = __bio_copy_iov(bio, &bmd->iter, | 1128 | ret = bio_copy_to_iter(bio, bmd->iter); |
1106 | bio_data_dir(bio) == READ, 0); | ||
1107 | if (bmd->is_our_pages) | 1129 | if (bmd->is_our_pages) |
1108 | bio_free_pages(bio); | 1130 | bio_free_pages(bio); |
1109 | } | 1131 | } |
@@ -1228,7 +1250,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q, | |||
1228 | */ | 1250 | */ |
1229 | if (((iter->type & WRITE) && (!map_data || !map_data->null_mapped)) || | 1251 | if (((iter->type & WRITE) && (!map_data || !map_data->null_mapped)) || |
1230 | (map_data && map_data->from_user)) { | 1252 | (map_data && map_data->from_user)) { |
1231 | ret = __bio_copy_iov(bio, iter, 0, 1); | 1253 | ret = bio_copy_from_iter(bio, *iter); |
1232 | if (ret) | 1254 | if (ret) |
1233 | goto cleanup; | 1255 | goto cleanup; |
1234 | } | 1256 | } |