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