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 iter->siov = siov; 36 iter->siovcnt = siovcnt; 37 38 iter->diov = diov; 39 iter->diovcnt = diovcnt; 40 41 iter->sidx = 0; 42 iter->didx = 0; 43 iter->siov_len = siov[0].iov_len; 44 iter->siov_base = siov[0].iov_base; 45 iter->diov_len = diov[0].iov_len; 46 iter->diov_base = diov[0].iov_base; 47 48 return spdk_ioviter_next(iter, src, dst); 49 } 50 51 size_t 52 spdk_ioviter_next(struct spdk_ioviter *iter, void **src, void **dst) 53 { 54 size_t len = 0; 55 56 if (iter->sidx == iter->siovcnt || 57 iter->didx == iter->diovcnt || 58 iter->siov_len == 0 || 59 iter->diov_len == 0) { 60 return 0; 61 } 62 63 *src = iter->siov_base; 64 *dst = iter->diov_base; 65 len = spdk_min(iter->siov_len, iter->diov_len); 66 67 if (iter->siov_len == iter->diov_len) { 68 /* Advance both iovs to the next element */ 69 iter->sidx++; 70 if (iter->sidx == iter->siovcnt) { 71 return len; 72 } 73 74 iter->didx++; 75 if (iter->didx == iter->diovcnt) { 76 return len; 77 } 78 79 iter->siov_len = iter->siov[iter->sidx].iov_len; 80 iter->siov_base = iter->siov[iter->sidx].iov_base; 81 iter->diov_len = iter->diov[iter->didx].iov_len; 82 iter->diov_base = iter->diov[iter->didx].iov_base; 83 } else if (iter->siov_len < iter->diov_len) { 84 /* Advance only the source to the next element */ 85 iter->sidx++; 86 if (iter->sidx == iter->siovcnt) { 87 return len; 88 } 89 90 iter->diov_base += iter->siov_len; 91 iter->diov_len -= iter->siov_len; 92 iter->siov_len = iter->siov[iter->sidx].iov_len; 93 iter->siov_base = iter->siov[iter->sidx].iov_base; 94 } else { 95 /* Advance only the destination to the next element */ 96 iter->didx++; 97 if (iter->didx == iter->diovcnt) { 98 return len; 99 } 100 101 iter->siov_base += iter->diov_len; 102 iter->siov_len -= iter->diov_len; 103 iter->diov_len = iter->diov[iter->didx].iov_len; 104 iter->diov_base = iter->diov[iter->didx].iov_base; 105 } 106 107 return len; 108 } 109 110 size_t 111 spdk_iovcpy(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_t diovcnt) 112 { 113 struct spdk_ioviter iter; 114 size_t len, total_sz; 115 void *src, *dst; 116 117 total_sz = 0; 118 for (len = spdk_ioviter_first(&iter, siov, siovcnt, diov, diovcnt, &src, &dst); 119 len != 0; 120 len = spdk_ioviter_next(&iter, &src, &dst)) { 121 memcpy(dst, src, len); 122 total_sz += len; 123 } 124 125 return total_sz; 126 } 127 128 size_t 129 spdk_iovmove(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_t diovcnt) 130 { 131 struct spdk_ioviter iter; 132 size_t len, total_sz; 133 void *src, *dst; 134 135 total_sz = 0; 136 for (len = spdk_ioviter_first(&iter, siov, siovcnt, diov, diovcnt, &src, &dst); 137 len != 0; 138 len = spdk_ioviter_next(&iter, &src, &dst)) { 139 memmove(dst, src, len); 140 total_sz += len; 141 } 142 143 return total_sz; 144 } 145 146 void 147 spdk_iov_xfer_init(struct spdk_iov_xfer *ix, struct iovec *iovs, int iovcnt) 148 { 149 ix->iovs = iovs; 150 ix->iovcnt = iovcnt; 151 ix->cur_iov_idx = 0; 152 ix->cur_iov_offset = 0; 153 } 154 155 static size_t 156 iov_xfer(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len, bool to_buf) 157 { 158 size_t len, iov_remain_len, copied_len = 0; 159 struct iovec *iov; 160 161 if (buf_len == 0) { 162 return 0; 163 } 164 165 while (ix->cur_iov_idx < ix->iovcnt) { 166 iov = &ix->iovs[ix->cur_iov_idx]; 167 iov_remain_len = iov->iov_len - ix->cur_iov_offset; 168 if (iov_remain_len == 0) { 169 ix->cur_iov_idx++; 170 ix->cur_iov_offset = 0; 171 continue; 172 } 173 174 len = spdk_min(iov_remain_len, buf_len - copied_len); 175 176 if (to_buf) { 177 memcpy((char *)buf + copied_len, 178 iov->iov_base + ix->cur_iov_offset, len); 179 } else { 180 memcpy((char *)iov->iov_base + ix->cur_iov_offset, 181 (const char *)buf + copied_len, len); 182 } 183 copied_len += len; 184 ix->cur_iov_offset += len; 185 186 if (buf_len == copied_len) { 187 return copied_len; 188 } 189 } 190 191 return copied_len; 192 } 193 194 size_t 195 spdk_iov_xfer_from_buf(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len) 196 { 197 return iov_xfer(ix, buf, buf_len, false); 198 } 199 200 size_t 201 spdk_iov_xfer_to_buf(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len) 202 { 203 return iov_xfer(ix, buf, buf_len, true); 204 } 205 206 void 207 spdk_copy_iovs_to_buf(void *buf, size_t buf_len, struct iovec *iovs, int iovcnt) 208 { 209 struct spdk_iov_xfer ix; 210 211 spdk_iov_xfer_init(&ix, iovs, iovcnt); 212 spdk_iov_xfer_to_buf(&ix, buf, buf_len); 213 } 214 215 void 216 spdk_copy_buf_to_iovs(struct iovec *iovs, int iovcnt, void *buf, size_t buf_len) 217 { 218 struct spdk_iov_xfer ix; 219 220 spdk_iov_xfer_init(&ix, iovs, iovcnt); 221 spdk_iov_xfer_from_buf(&ix, buf, buf_len); 222 } 223