open-cas-linux/modules/cas_cache/utils/utils_data.c
Robert Baldyga 94e8ca09e0 Initial commit
Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
2019-03-29 08:45:50 +01:00

131 lines
2.9 KiB
C

/*
* Copyright(c) 2012-2019 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#include "cas_cache.h"
/**
* This function locates index of IO vec from given vecs array where byte at
* offset is located. When found it returns its index and byte offset within
* this vec.
* @param vecs IO vector array to be searched
* @param vec_num number of items in IO vector array
* @param offset byte offset to be found
* @param offset_in_vec byte offset within found IO vec
* @return vec index if it lies within specified buffer, otherwise -1
*/
static int get_starting_vec(struct bio_vec *vecs, uint64_t vecs_num,
uint64_t offset, uint64_t *offset_in_vec)
{
int i;
for (i = 0; i < vecs_num; i++) {
if (vecs[i].bv_len > offset) {
if (offset_in_vec != NULL)
*offset_in_vec = offset;
return i;
}
offset -= vecs[i].bv_len;
}
return -1;
}
uint64_t cas_data_cpy(struct bio_vec *dst, uint64_t dst_num,
struct bio_vec *src, uint64_t src_num,
uint64_t to, uint64_t from, uint64_t bytes)
{
uint64_t i, j, dst_len, src_len, to_copy;
uint64_t dst_off, src_off;
uint64_t written = 0;
int ret;
void *dst_p, *src_p;
struct bio_vec *curr_dst, *curr_src;
/* Locate vec idx and offset in dst vec array */
ret = get_starting_vec(dst, dst_num, to, &to);
if (ret < 0) {
CAS_PRINT_RL(KERN_INFO "llu dst buffer too small "
"to_offset=%llu bytes=%llu", to, bytes);
return 0;
}
j = ret;
/* Locate vec idx and offset in src vec array */
ret = get_starting_vec(src, src_num, from, &from);
if (ret < 0) {
CAS_PRINT_RL(KERN_INFO "llu src buffer too small "
"from_offset=%llu bytes=%llu", from, bytes);
return 0;
}
i = ret;
curr_dst = &dst[j];
curr_src = &src[i];
dst_off = curr_dst->bv_offset + to;
dst_len = curr_dst->bv_len - to;
src_off = curr_src->bv_offset + from;
src_len = curr_src->bv_len - from;
while (written < bytes) {
dst_p = page_address(curr_dst->bv_page) + dst_off;
src_p = page_address(curr_src->bv_page) + src_off;
to_copy = src_len > dst_len ? dst_len : src_len;
/* Prevent from copying too much*/
if ((written + to_copy) > bytes)
to_copy = bytes - written;
memcpy(dst_p, src_p, to_copy);
written += to_copy;
if (written == bytes)
break;
/* Setup new len and offset. */
dst_off += to_copy;
dst_len -= to_copy;
src_off += to_copy;
src_len -= to_copy;
/* Go to next src buffer */
if (src_len == 0) {
i++;
/* Setup new len and offset. */
if (i < src_num) {
curr_src = &src[i];
src_off = curr_src->bv_offset;
src_len = curr_src->bv_len;
} else {
break;
}
}
/* Go to next dst buffer */
if (dst_len == 0) {
j++;
if (j < dst_num) {
curr_dst = &dst[j];
dst_off = curr_dst->bv_offset;
dst_len = curr_dst->bv_len;
} else {
break;
}
}
}
if (written != bytes) {
CAS_PRINT_RL(KERN_INFO "Written bytes not equal requested bytes "
"(written=%llu; requested=%llu)", written, bytes);
}
return written;
}