+
+/*
+ * Copy up to size bytes between arg_buf and req based on the data direction
+ * described by the req. If an entire req's data cannot be transfered the
+ * req's is updated such that it's current index and bv offsets correctly
+ * reference any residual data which could not be copied. The return value
+ * is the number of bytes successfully copied to arg_buf.
+ */
+static int
+dmu_req_copy(void *arg_buf, int size, int *offset, struct request *req)
+{
+ struct bio_vec *bv;
+ struct req_iterator iter;
+ char *bv_buf;
+ int tocpy;
+
+ *offset = 0;
+ rq_for_each_segment(bv, req, iter) {
+
+ /* Fully consumed the passed arg_buf */
+ ASSERT3S(*offset, <=, size);
+ if (size == *offset)
+ break;
+
+ /* Skip fully consumed bv's */
+ if (bv->bv_len == 0)
+ continue;
+
+ tocpy = MIN(bv->bv_len, size - *offset);
+ ASSERT3S(tocpy, >=, 0);
+
+ bv_buf = page_address(bv->bv_page) + bv->bv_offset;
+ ASSERT3P(bv_buf, !=, NULL);
+
+ if (rq_data_dir(req) == WRITE)
+ memcpy(arg_buf + *offset, bv_buf, tocpy);
+ else
+ memcpy(bv_buf, arg_buf + *offset, tocpy);
+
+ *offset += tocpy;
+ bv->bv_offset += tocpy;
+ bv->bv_len -= tocpy;
+ }
+
+ return 0;
+}
+