1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2019 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/util.h" 7 #include "spdk/log.h" 8 9 void 10 spdk_iov_memset(struct iovec *iovs, int iovcnt, int c) 11 { 12 int iov_idx = 0; 13 struct iovec *iov; 14 15 while (iov_idx < iovcnt) { 16 iov = &iovs[iov_idx]; 17 memset(iov->iov_base, c, iov->iov_len); 18 iov_idx++; 19 } 20 } 21 22 size_t 23 spdk_ioviter_first(struct spdk_ioviter *iter, 24 struct iovec *siov, size_t siovcnt, 25 struct iovec *diov, size_t diovcnt, 26 void **src, void **dst) 27 { 28 struct iovec *iovs[2]; 29 size_t iovcnts[2]; 30 void *out[2]; 31 size_t len; 32 33 iovs[0] = siov; 34 iovcnts[0] = siovcnt; 35 36 iovs[1] = diov; 37 iovcnts[1] = diovcnt; 38 39 len = spdk_ioviter_firstv(iter, 2, iovs, iovcnts, out); 40 41 if (len > 0) { 42 *src = out[0]; 43 *dst = out[1]; 44 } 45 46 return len; 47 } 48 49 size_t 50 spdk_ioviter_firstv(struct spdk_ioviter *iter, 51 uint32_t count, 52 struct iovec **iov, 53 size_t *iovcnt, 54 void **out) 55 { 56 struct spdk_single_ioviter *it; 57 uint32_t i; 58 59 iter->count = count; 60 61 for (i = 0; i < count; i++) { 62 it = &iter->iters[i]; 63 it->iov = iov[i]; 64 it->iovcnt = iovcnt[i]; 65 it->idx = 0; 66 it->iov_len = iov[i][0].iov_len; 67 it->iov_base = iov[i][0].iov_base; 68 } 69 70 return spdk_ioviter_nextv(iter, out); 71 } 72 73 size_t 74 spdk_ioviter_next(struct spdk_ioviter *iter, void **src, void **dst) 75 { 76 void *out[2]; 77 size_t len; 78 79 len = spdk_ioviter_nextv(iter, out); 80 81 if (len > 0) { 82 *src = out[0]; 83 *dst = out[1]; 84 } 85 86 return len; 87 } 88 89 size_t 90 spdk_ioviter_nextv(struct spdk_ioviter *iter, void **out) 91 { 92 struct spdk_single_ioviter *it; 93 size_t len; 94 uint32_t i; 95 96 /* Figure out the minimum size of each iovec's next segment */ 97 len = UINT32_MAX; 98 for (i = 0; i < iter->count; i++) { 99 it = &iter->iters[i]; 100 if (it->idx == it->iovcnt || it->iov_len == 0) { 101 /* This element has 0 bytes remaining, so we're done. */ 102 return 0; 103 } 104 105 len = spdk_min(len, it->iov_len); 106 } 107 108 for (i = 0; i < iter->count; i++) { 109 it = &iter->iters[i]; 110 111 out[i] = it->iov_base; 112 113 if (it->iov_len == len) { 114 /* Advance to next element */ 115 it->idx++; 116 if (it->idx != it->iovcnt) { 117 /* Set up for next element */ 118 it->iov_len = it->iov[it->idx].iov_len; 119 it->iov_base = it->iov[it->idx].iov_base; 120 } 121 } else { 122 /* Partial buffer */ 123 it->iov_base += len; 124 it->iov_len -= len; 125 } 126 } 127 128 return len; 129 } 130 131 size_t 132 spdk_iovcpy(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_t diovcnt) 133 { 134 struct spdk_ioviter iter; 135 size_t len, total_sz; 136 void *src, *dst; 137 138 total_sz = 0; 139 for (len = spdk_ioviter_first(&iter, siov, siovcnt, diov, diovcnt, &src, &dst); 140 len != 0; 141 len = spdk_ioviter_next(&iter, &src, &dst)) { 142 memcpy(dst, src, len); 143 total_sz += len; 144 } 145 146 return total_sz; 147 } 148 149 size_t 150 spdk_iovmove(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_t diovcnt) 151 { 152 struct spdk_ioviter iter; 153 size_t len, total_sz; 154 void *src, *dst; 155 156 total_sz = 0; 157 for (len = spdk_ioviter_first(&iter, siov, siovcnt, diov, diovcnt, &src, &dst); 158 len != 0; 159 len = spdk_ioviter_next(&iter, &src, &dst)) { 160 memmove(dst, src, len); 161 total_sz += len; 162 } 163 164 return total_sz; 165 } 166 167 void 168 spdk_iov_xfer_init(struct spdk_iov_xfer *ix, struct iovec *iovs, int iovcnt) 169 { 170 ix->iovs = iovs; 171 ix->iovcnt = iovcnt; 172 ix->cur_iov_idx = 0; 173 ix->cur_iov_offset = 0; 174 } 175 176 static size_t 177 iov_xfer(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len, bool to_buf) 178 { 179 size_t len, iov_remain_len, copied_len = 0; 180 struct iovec *iov; 181 182 if (buf_len == 0) { 183 return 0; 184 } 185 186 while (ix->cur_iov_idx < ix->iovcnt) { 187 iov = &ix->iovs[ix->cur_iov_idx]; 188 iov_remain_len = iov->iov_len - ix->cur_iov_offset; 189 if (iov_remain_len == 0) { 190 ix->cur_iov_idx++; 191 ix->cur_iov_offset = 0; 192 continue; 193 } 194 195 len = spdk_min(iov_remain_len, buf_len - copied_len); 196 197 if (to_buf) { 198 memcpy((char *)buf + copied_len, 199 (char *)iov->iov_base + ix->cur_iov_offset, len); 200 } else { 201 memcpy((char *)iov->iov_base + ix->cur_iov_offset, 202 (const char *)buf + copied_len, len); 203 } 204 copied_len += len; 205 ix->cur_iov_offset += len; 206 207 if (buf_len == copied_len) { 208 return copied_len; 209 } 210 } 211 212 return copied_len; 213 } 214 215 size_t 216 spdk_iov_xfer_from_buf(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len) 217 { 218 return iov_xfer(ix, buf, buf_len, false); 219 } 220 221 size_t 222 spdk_iov_xfer_to_buf(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len) 223 { 224 return iov_xfer(ix, buf, buf_len, true); 225 } 226 227 void 228 spdk_copy_iovs_to_buf(void *buf, size_t buf_len, struct iovec *iovs, int iovcnt) 229 { 230 struct spdk_iov_xfer ix; 231 232 spdk_iov_xfer_init(&ix, iovs, iovcnt); 233 spdk_iov_xfer_to_buf(&ix, buf, buf_len); 234 } 235 236 void 237 spdk_copy_buf_to_iovs(struct iovec *iovs, int iovcnt, void *buf, size_t buf_len) 238 { 239 struct spdk_iov_xfer ix; 240 241 spdk_iov_xfer_init(&ix, iovs, iovcnt); 242 spdk_iov_xfer_from_buf(&ix, buf, buf_len); 243 } 244