qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at master 416 lines 12 kB view raw
1#include "qemu/osdep.h" 2#include "qemu-common.h" 3#include "qemu/iov.h" 4#include "qemu/sockets.h" 5 6/* create a randomly-sized iovec with random vectors */ 7static void iov_random(struct iovec **iovp, unsigned *iov_cntp) 8{ 9 unsigned niov = g_test_rand_int_range(3,8); 10 struct iovec *iov = g_malloc(niov * sizeof(*iov)); 11 unsigned i; 12 for (i = 0; i < niov; ++i) { 13 iov[i].iov_len = g_test_rand_int_range(5,20); 14 iov[i].iov_base = g_malloc(iov[i].iov_len); 15 } 16 *iovp = iov; 17 *iov_cntp = niov; 18} 19 20static void iov_free(struct iovec *iov, unsigned niov) 21{ 22 unsigned i; 23 for (i = 0; i < niov; ++i) { 24 g_free(iov[i].iov_base); 25 } 26 g_free(iov); 27} 28 29static void test_iov_bytes(struct iovec *iov, unsigned niov, 30 size_t offset, size_t bytes) 31{ 32 unsigned i; 33 size_t j, o; 34 unsigned char *b; 35 o = 0; 36 37 /* we walk over all elements, */ 38 for (i = 0; i < niov; ++i) { 39 b = iov[i].iov_base; 40 /* over each char of each element, */ 41 for (j = 0; j < iov[i].iov_len; ++j) { 42 /* counting each of them and 43 * verifying that the ones within [offset,offset+bytes) 44 * range are equal to the position number (o) */ 45 if (o >= offset && o < offset + bytes) { 46 g_assert(b[j] == (o & 255)); 47 } else { 48 g_assert(b[j] == 0xff); 49 } 50 ++o; 51 } 52 } 53} 54 55static void test_to_from_buf_1(void) 56{ 57 unsigned niov; 58 struct iovec *iov; 59 size_t sz; 60 unsigned char *ibuf, *obuf; 61 unsigned i, j, n; 62 63 iov_random(&iov, &niov); 64 65 sz = iov_size(iov, niov); 66 67 ibuf = g_malloc(sz + 8) + 4; 68 memcpy(ibuf-4, "aaaa", 4); memcpy(ibuf + sz, "bbbb", 4); 69 obuf = g_malloc(sz + 8) + 4; 70 memcpy(obuf-4, "xxxx", 4); memcpy(obuf + sz, "yyyy", 4); 71 72 /* fill in ibuf with 0123456... */ 73 for (i = 0; i < sz; ++i) { 74 ibuf[i] = i & 255; 75 } 76 77 for (i = 0; i <= sz; ++i) { 78 79 /* Test from/to buf for offset(i) in [0..sz] up to the end of buffer. 80 * For last iteration with offset == sz, the procedure should 81 * skip whole vector and process exactly 0 bytes */ 82 83 /* first set bytes [i..sz) to some "random" value */ 84 n = iov_memset(iov, niov, 0, 0xff, sz); 85 g_assert(n == sz); 86 87 /* next copy bytes [i..sz) from ibuf to iovec */ 88 n = iov_from_buf(iov, niov, i, ibuf + i, sz - i); 89 g_assert(n == sz - i); 90 91 /* clear part of obuf */ 92 memset(obuf + i, 0, sz - i); 93 /* and set this part of obuf to values from iovec */ 94 n = iov_to_buf(iov, niov, i, obuf + i, sz - i); 95 g_assert(n == sz - i); 96 97 /* now compare resulting buffers */ 98 g_assert(memcmp(ibuf, obuf, sz) == 0); 99 100 /* test just one char */ 101 n = iov_to_buf(iov, niov, i, obuf + i, 1); 102 g_assert(n == (i < sz)); 103 if (n) { 104 g_assert(obuf[i] == (i & 255)); 105 } 106 107 for (j = i; j <= sz; ++j) { 108 /* now test num of bytes cap up to byte no. j, 109 * with j in [i..sz]. */ 110 111 /* clear iovec */ 112 n = iov_memset(iov, niov, 0, 0xff, sz); 113 g_assert(n == sz); 114 115 /* copy bytes [i..j) from ibuf to iovec */ 116 n = iov_from_buf(iov, niov, i, ibuf + i, j - i); 117 g_assert(n == j - i); 118 119 /* clear part of obuf */ 120 memset(obuf + i, 0, j - i); 121 122 /* copy bytes [i..j) from iovec to obuf */ 123 n = iov_to_buf(iov, niov, i, obuf + i, j - i); 124 g_assert(n == j - i); 125 126 /* verify result */ 127 g_assert(memcmp(ibuf, obuf, sz) == 0); 128 129 /* now actually check if the iovec contains the right data */ 130 test_iov_bytes(iov, niov, i, j - i); 131 } 132 } 133 g_assert(!memcmp(ibuf-4, "aaaa", 4) && !memcmp(ibuf+sz, "bbbb", 4)); 134 g_free(ibuf-4); 135 g_assert(!memcmp(obuf-4, "xxxx", 4) && !memcmp(obuf+sz, "yyyy", 4)); 136 g_free(obuf-4); 137 iov_free(iov, niov); 138} 139 140static void test_to_from_buf(void) 141{ 142 int x; 143 for (x = 0; x < 4; ++x) { 144 test_to_from_buf_1(); 145 } 146} 147 148static void test_io(void) 149{ 150#ifndef _WIN32 151/* socketpair(PF_UNIX) which does not exist on windows */ 152 153 int sv[2]; 154 int r; 155 unsigned i, j, k, s, t; 156 fd_set fds; 157 unsigned niov; 158 struct iovec *iov, *siov; 159 unsigned char *buf; 160 size_t sz; 161 162 iov_random(&iov, &niov); 163 sz = iov_size(iov, niov); 164 buf = g_malloc(sz); 165 for (i = 0; i < sz; ++i) { 166 buf[i] = i & 255; 167 } 168 iov_from_buf(iov, niov, 0, buf, sz); 169 170 siov = g_memdup(iov, sizeof(*iov) * niov); 171 172 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) { 173 perror("socketpair"); 174 exit(1); 175 } 176 177 FD_ZERO(&fds); 178 179 t = 0; 180 if (fork() == 0) { 181 /* writer */ 182 183 close(sv[0]); 184 FD_SET(sv[1], &fds); 185 fcntl(sv[1], F_SETFL, O_RDWR|O_NONBLOCK); 186 r = g_test_rand_int_range(sz / 2, sz); 187 setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &r, sizeof(r)); 188 189 for (i = 0; i <= sz; ++i) { 190 for (j = i; j <= sz; ++j) { 191 k = i; 192 do { 193 s = g_test_rand_int_range(0, j - k + 1); 194 r = iov_send(sv[1], iov, niov, k, s); 195 g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0); 196 if (r >= 0) { 197 k += r; 198 t += r; 199 usleep(g_test_rand_int_range(0, 30)); 200 } else if (errno == EAGAIN) { 201 select(sv[1]+1, NULL, &fds, NULL, NULL); 202 continue; 203 } else { 204 perror("send"); 205 exit(1); 206 } 207 } while(k < j); 208 } 209 } 210 iov_free(iov, niov); 211 g_free(buf); 212 g_free(siov); 213 exit(0); 214 215 } else { 216 /* reader & verifier */ 217 218 close(sv[1]); 219 FD_SET(sv[0], &fds); 220 fcntl(sv[0], F_SETFL, O_RDWR|O_NONBLOCK); 221 r = g_test_rand_int_range(sz / 2, sz); 222 setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &r, sizeof(r)); 223 usleep(500000); 224 225 for (i = 0; i <= sz; ++i) { 226 for (j = i; j <= sz; ++j) { 227 k = i; 228 iov_memset(iov, niov, 0, 0xff, sz); 229 do { 230 s = g_test_rand_int_range(0, j - k + 1); 231 r = iov_recv(sv[0], iov, niov, k, s); 232 g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0); 233 if (r > 0) { 234 k += r; 235 t += r; 236 } else if (!r) { 237 if (s) { 238 break; 239 } 240 } else if (errno == EAGAIN) { 241 select(sv[0]+1, &fds, NULL, NULL, NULL); 242 continue; 243 } else { 244 perror("recv"); 245 exit(1); 246 } 247 } while(k < j); 248 test_iov_bytes(iov, niov, i, j - i); 249 } 250 } 251 252 iov_free(iov, niov); 253 g_free(buf); 254 g_free(siov); 255 } 256#endif 257} 258 259static void test_discard_front(void) 260{ 261 struct iovec *iov; 262 struct iovec *iov_tmp; 263 unsigned int iov_cnt; 264 unsigned int iov_cnt_tmp; 265 void *old_base; 266 size_t size; 267 size_t ret; 268 269 /* Discard zero bytes */ 270 iov_random(&iov, &iov_cnt); 271 iov_tmp = iov; 272 iov_cnt_tmp = iov_cnt; 273 ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, 0); 274 g_assert(ret == 0); 275 g_assert(iov_tmp == iov); 276 g_assert(iov_cnt_tmp == iov_cnt); 277 iov_free(iov, iov_cnt); 278 279 /* Discard more bytes than vector size */ 280 iov_random(&iov, &iov_cnt); 281 iov_tmp = iov; 282 iov_cnt_tmp = iov_cnt; 283 size = iov_size(iov, iov_cnt); 284 ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size + 1); 285 g_assert(ret == size); 286 g_assert(iov_cnt_tmp == 0); 287 iov_free(iov, iov_cnt); 288 289 /* Discard entire vector */ 290 iov_random(&iov, &iov_cnt); 291 iov_tmp = iov; 292 iov_cnt_tmp = iov_cnt; 293 size = iov_size(iov, iov_cnt); 294 ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size); 295 g_assert(ret == size); 296 g_assert(iov_cnt_tmp == 0); 297 iov_free(iov, iov_cnt); 298 299 /* Discard within first element */ 300 iov_random(&iov, &iov_cnt); 301 iov_tmp = iov; 302 iov_cnt_tmp = iov_cnt; 303 old_base = iov->iov_base; 304 size = g_test_rand_int_range(1, iov->iov_len); 305 ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size); 306 g_assert(ret == size); 307 g_assert(iov_tmp == iov); 308 g_assert(iov_cnt_tmp == iov_cnt); 309 g_assert(iov_tmp->iov_base == old_base + size); 310 iov_tmp->iov_base = old_base; /* undo before g_free() */ 311 iov_free(iov, iov_cnt); 312 313 /* Discard entire first element */ 314 iov_random(&iov, &iov_cnt); 315 iov_tmp = iov; 316 iov_cnt_tmp = iov_cnt; 317 ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, iov->iov_len); 318 g_assert(ret == iov->iov_len); 319 g_assert(iov_tmp == iov + 1); 320 g_assert(iov_cnt_tmp == iov_cnt - 1); 321 iov_free(iov, iov_cnt); 322 323 /* Discard within second element */ 324 iov_random(&iov, &iov_cnt); 325 iov_tmp = iov; 326 iov_cnt_tmp = iov_cnt; 327 old_base = iov[1].iov_base; 328 size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len); 329 ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size); 330 g_assert(ret == size); 331 g_assert(iov_tmp == iov + 1); 332 g_assert(iov_cnt_tmp == iov_cnt - 1); 333 g_assert(iov_tmp->iov_base == old_base + (size - iov->iov_len)); 334 iov_tmp->iov_base = old_base; /* undo before g_free() */ 335 iov_free(iov, iov_cnt); 336} 337 338static void test_discard_back(void) 339{ 340 struct iovec *iov; 341 unsigned int iov_cnt; 342 unsigned int iov_cnt_tmp; 343 void *old_base; 344 size_t size; 345 size_t ret; 346 347 /* Discard zero bytes */ 348 iov_random(&iov, &iov_cnt); 349 iov_cnt_tmp = iov_cnt; 350 ret = iov_discard_back(iov, &iov_cnt_tmp, 0); 351 g_assert(ret == 0); 352 g_assert(iov_cnt_tmp == iov_cnt); 353 iov_free(iov, iov_cnt); 354 355 /* Discard more bytes than vector size */ 356 iov_random(&iov, &iov_cnt); 357 iov_cnt_tmp = iov_cnt; 358 size = iov_size(iov, iov_cnt); 359 ret = iov_discard_back(iov, &iov_cnt_tmp, size + 1); 360 g_assert(ret == size); 361 g_assert(iov_cnt_tmp == 0); 362 iov_free(iov, iov_cnt); 363 364 /* Discard entire vector */ 365 iov_random(&iov, &iov_cnt); 366 iov_cnt_tmp = iov_cnt; 367 size = iov_size(iov, iov_cnt); 368 ret = iov_discard_back(iov, &iov_cnt_tmp, size); 369 g_assert(ret == size); 370 g_assert(iov_cnt_tmp == 0); 371 iov_free(iov, iov_cnt); 372 373 /* Discard within last element */ 374 iov_random(&iov, &iov_cnt); 375 iov_cnt_tmp = iov_cnt; 376 old_base = iov[iov_cnt - 1].iov_base; 377 size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len); 378 ret = iov_discard_back(iov, &iov_cnt_tmp, size); 379 g_assert(ret == size); 380 g_assert(iov_cnt_tmp == iov_cnt); 381 g_assert(iov[iov_cnt - 1].iov_base == old_base); 382 iov_free(iov, iov_cnt); 383 384 /* Discard entire last element */ 385 iov_random(&iov, &iov_cnt); 386 iov_cnt_tmp = iov_cnt; 387 old_base = iov[iov_cnt - 1].iov_base; 388 size = iov[iov_cnt - 1].iov_len; 389 ret = iov_discard_back(iov, &iov_cnt_tmp, size); 390 g_assert(ret == size); 391 g_assert(iov_cnt_tmp == iov_cnt - 1); 392 iov_free(iov, iov_cnt); 393 394 /* Discard within second-to-last element */ 395 iov_random(&iov, &iov_cnt); 396 iov_cnt_tmp = iov_cnt; 397 old_base = iov[iov_cnt - 2].iov_base; 398 size = iov[iov_cnt - 1].iov_len + 399 g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len); 400 ret = iov_discard_back(iov, &iov_cnt_tmp, size); 401 g_assert(ret == size); 402 g_assert(iov_cnt_tmp == iov_cnt - 1); 403 g_assert(iov[iov_cnt - 2].iov_base == old_base); 404 iov_free(iov, iov_cnt); 405} 406 407int main(int argc, char **argv) 408{ 409 g_test_init(&argc, &argv, NULL); 410 g_test_rand_int(); 411 g_test_add_func("/basic/iov/from-to-buf", test_to_from_buf); 412 g_test_add_func("/basic/iov/io", test_io); 413 g_test_add_func("/basic/iov/discard-front", test_discard_front); 414 g_test_add_func("/basic/iov/discard-back", test_discard_back); 415 return g_test_run(); 416}