|
@@ -829,6 +829,76 @@ void bio_advance(struct bio *bio, unsigned bytes)
|
|
|
}
|
|
|
EXPORT_SYMBOL(bio_advance);
|
|
|
|
|
|
+/**
|
|
|
+ * bio_copy_data - copy contents of data buffers from one chain of bios to
|
|
|
+ * another
|
|
|
+ * @src: source bio list
|
|
|
+ * @dst: destination bio list
|
|
|
+ *
|
|
|
+ * If @src and @dst are single bios, bi_next must be NULL - otherwise, treats
|
|
|
+ * @src and @dst as linked lists of bios.
|
|
|
+ *
|
|
|
+ * Stops when it reaches the end of either @src or @dst - that is, copies
|
|
|
+ * min(src->bi_size, dst->bi_size) bytes (or the equivalent for lists of bios).
|
|
|
+ */
|
|
|
+void bio_copy_data(struct bio *dst, struct bio *src)
|
|
|
+{
|
|
|
+ struct bio_vec *src_bv, *dst_bv;
|
|
|
+ unsigned src_offset, dst_offset, bytes;
|
|
|
+ void *src_p, *dst_p;
|
|
|
+
|
|
|
+ src_bv = bio_iovec(src);
|
|
|
+ dst_bv = bio_iovec(dst);
|
|
|
+
|
|
|
+ src_offset = src_bv->bv_offset;
|
|
|
+ dst_offset = dst_bv->bv_offset;
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+ if (src_offset == src_bv->bv_offset + src_bv->bv_len) {
|
|
|
+ src_bv++;
|
|
|
+ if (src_bv == bio_iovec_idx(src, src->bi_vcnt)) {
|
|
|
+ src = src->bi_next;
|
|
|
+ if (!src)
|
|
|
+ break;
|
|
|
+
|
|
|
+ src_bv = bio_iovec(src);
|
|
|
+ }
|
|
|
+
|
|
|
+ src_offset = src_bv->bv_offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dst_offset == dst_bv->bv_offset + dst_bv->bv_len) {
|
|
|
+ dst_bv++;
|
|
|
+ if (dst_bv == bio_iovec_idx(dst, dst->bi_vcnt)) {
|
|
|
+ dst = dst->bi_next;
|
|
|
+ if (!dst)
|
|
|
+ break;
|
|
|
+
|
|
|
+ dst_bv = bio_iovec(dst);
|
|
|
+ }
|
|
|
+
|
|
|
+ dst_offset = dst_bv->bv_offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ bytes = min(dst_bv->bv_offset + dst_bv->bv_len - dst_offset,
|
|
|
+ src_bv->bv_offset + src_bv->bv_len - src_offset);
|
|
|
+
|
|
|
+ src_p = kmap_atomic(src_bv->bv_page);
|
|
|
+ dst_p = kmap_atomic(dst_bv->bv_page);
|
|
|
+
|
|
|
+ memcpy(dst_p + dst_bv->bv_offset,
|
|
|
+ src_p + src_bv->bv_offset,
|
|
|
+ bytes);
|
|
|
+
|
|
|
+ kunmap_atomic(dst_p);
|
|
|
+ kunmap_atomic(src_p);
|
|
|
+
|
|
|
+ src_offset += bytes;
|
|
|
+ dst_offset += bytes;
|
|
|
+ }
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(bio_copy_data);
|
|
|
+
|
|
|
struct bio_map_data {
|
|
|
struct bio_vec *iovecs;
|
|
|
struct sg_iovec *sgvecs;
|