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