aboutsummaryrefslogtreecommitdiffstats
path: root/fs/bio.c
diff options
context:
space:
mode:
authorKent Overstreet <koverstreet@google.com>2012-09-10 16:57:51 -0400
committerKent Overstreet <koverstreet@google.com>2013-03-23 17:15:37 -0400
commit16ac3d63e74f3d6e34e42d6e523b6a61de0020f0 (patch)
tree08bfffad2ccf0b67d704588ff14f9e5227ed0e7d /fs/bio.c
parentb783863f68c26c5411c50002f98a047a40b94e8e (diff)
block: Add bio_copy_data()
This gets open coded quite a bit and it's tricky to get right, so make a generic version and convert some existing users over to it instead. Signed-off-by: Kent Overstreet <koverstreet@google.com> CC: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'fs/bio.c')
-rw-r--r--fs/bio.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/fs/bio.c b/fs/bio.c
index 4ce24ee5dcd0..e437f9aae67d 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -829,6 +829,76 @@ void bio_advance(struct bio *bio, unsigned bytes)
829} 829}
830EXPORT_SYMBOL(bio_advance); 830EXPORT_SYMBOL(bio_advance);
831 831
832/**
833 * bio_copy_data - copy contents of data buffers from one chain of bios to
834 * another
835 * @src: source bio list
836 * @dst: destination bio list
837 *
838 * If @src and @dst are single bios, bi_next must be NULL - otherwise, treats
839 * @src and @dst as linked lists of bios.
840 *
841 * Stops when it reaches the end of either @src or @dst - that is, copies
842 * min(src->bi_size, dst->bi_size) bytes (or the equivalent for lists of bios).
843 */
844void bio_copy_data(struct bio *dst, struct bio *src)
845{
846 struct bio_vec *src_bv, *dst_bv;
847 unsigned src_offset, dst_offset, bytes;
848 void *src_p, *dst_p;
849
850 src_bv = bio_iovec(src);
851 dst_bv = bio_iovec(dst);
852
853 src_offset = src_bv->bv_offset;
854 dst_offset = dst_bv->bv_offset;
855
856 while (1) {
857 if (src_offset == src_bv->bv_offset + src_bv->bv_len) {
858 src_bv++;
859 if (src_bv == bio_iovec_idx(src, src->bi_vcnt)) {
860 src = src->bi_next;
861 if (!src)
862 break;
863
864 src_bv = bio_iovec(src);
865 }
866
867 src_offset = src_bv->bv_offset;
868 }
869
870 if (dst_offset == dst_bv->bv_offset + dst_bv->bv_len) {
871 dst_bv++;
872 if (dst_bv == bio_iovec_idx(dst, dst->bi_vcnt)) {
873 dst = dst->bi_next;
874 if (!dst)
875 break;
876
877 dst_bv = bio_iovec(dst);
878 }
879
880 dst_offset = dst_bv->bv_offset;
881 }
882
883 bytes = min(dst_bv->bv_offset + dst_bv->bv_len - dst_offset,
884 src_bv->bv_offset + src_bv->bv_len - src_offset);
885
886 src_p = kmap_atomic(src_bv->bv_page);
887 dst_p = kmap_atomic(dst_bv->bv_page);
888
889 memcpy(dst_p + dst_bv->bv_offset,
890 src_p + src_bv->bv_offset,
891 bytes);
892
893 kunmap_atomic(dst_p);
894 kunmap_atomic(src_p);
895
896 src_offset += bytes;
897 dst_offset += bytes;
898 }
899}
900EXPORT_SYMBOL(bio_copy_data);
901
832struct bio_map_data { 902struct bio_map_data {
833 struct bio_vec *iovecs; 903 struct bio_vec *iovecs;
834 struct sg_iovec *sgvecs; 904 struct sg_iovec *sgvecs;