vringh_test.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Simple test of virtio code, entirely in userpsace. */
  3. #define _GNU_SOURCE
  4. #include <sched.h>
  5. #include <err.h>
  6. #include <linux/kernel.h>
  7. #include <linux/err.h>
  8. #include <linux/virtio.h>
  9. #include <linux/vringh.h>
  10. #include <linux/virtio_ring.h>
  11. #include <linux/virtio_config.h>
  12. #include <linux/uaccess.h>
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #include <sys/mman.h>
  16. #include <sys/wait.h>
  17. #include <fcntl.h>
  18. #define USER_MEM (1024*1024)
  19. void *__user_addr_min, *__user_addr_max;
  20. void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end;
  21. static u64 user_addr_offset;
  22. #define RINGSIZE 256
  23. #define ALIGN 4096
  24. static bool never_notify_host(struct virtqueue *vq)
  25. {
  26. abort();
  27. }
  28. static void never_callback_guest(struct virtqueue *vq)
  29. {
  30. abort();
  31. }
  32. static bool getrange_iov(struct vringh *vrh, u64 addr, struct vringh_range *r)
  33. {
  34. if (addr < (u64)(unsigned long)__user_addr_min - user_addr_offset)
  35. return false;
  36. if (addr >= (u64)(unsigned long)__user_addr_max - user_addr_offset)
  37. return false;
  38. r->start = (u64)(unsigned long)__user_addr_min - user_addr_offset;
  39. r->end_incl = (u64)(unsigned long)__user_addr_max - 1 - user_addr_offset;
  40. r->offset = user_addr_offset;
  41. return true;
  42. }
  43. /* We return single byte ranges. */
  44. static bool getrange_slow(struct vringh *vrh, u64 addr, struct vringh_range *r)
  45. {
  46. if (addr < (u64)(unsigned long)__user_addr_min - user_addr_offset)
  47. return false;
  48. if (addr >= (u64)(unsigned long)__user_addr_max - user_addr_offset)
  49. return false;
  50. r->start = addr;
  51. r->end_incl = r->start;
  52. r->offset = user_addr_offset;
  53. return true;
  54. }
  55. struct guest_virtio_device {
  56. struct virtio_device vdev;
  57. int to_host_fd;
  58. unsigned long notifies;
  59. };
  60. static bool parallel_notify_host(struct virtqueue *vq)
  61. {
  62. int rc;
  63. struct guest_virtio_device *gvdev;
  64. gvdev = container_of(vq->vdev, struct guest_virtio_device, vdev);
  65. rc = write(gvdev->to_host_fd, "", 1);
  66. if (rc < 0)
  67. return false;
  68. gvdev->notifies++;
  69. return true;
  70. }
  71. static bool no_notify_host(struct virtqueue *vq)
  72. {
  73. return true;
  74. }
  75. #define NUM_XFERS (10000000)
  76. /* We aim for two "distant" cpus. */
  77. static void find_cpus(unsigned int *first, unsigned int *last)
  78. {
  79. unsigned int i;
  80. *first = -1U;
  81. *last = 0;
  82. for (i = 0; i < 4096; i++) {
  83. cpu_set_t set;
  84. CPU_ZERO(&set);
  85. CPU_SET(i, &set);
  86. if (sched_setaffinity(getpid(), sizeof(set), &set) == 0) {
  87. if (i < *first)
  88. *first = i;
  89. if (i > *last)
  90. *last = i;
  91. }
  92. }
  93. }
  94. /* Opencoded version for fast mode */
  95. static inline int vringh_get_head(struct vringh *vrh, u16 *head)
  96. {
  97. u16 avail_idx, i;
  98. int err;
  99. err = get_user(avail_idx, &vrh->vring.avail->idx);
  100. if (err)
  101. return err;
  102. if (vrh->last_avail_idx == avail_idx)
  103. return 0;
  104. /* Only get avail ring entries after they have been exposed by guest. */
  105. virtio_rmb(vrh->weak_barriers);
  106. i = vrh->last_avail_idx & (vrh->vring.num - 1);
  107. err = get_user(*head, &vrh->vring.avail->ring[i]);
  108. if (err)
  109. return err;
  110. vrh->last_avail_idx++;
  111. return 1;
  112. }
  113. static int parallel_test(u64 features,
  114. bool (*getrange)(struct vringh *vrh,
  115. u64 addr, struct vringh_range *r),
  116. bool fast_vringh)
  117. {
  118. void *host_map, *guest_map;
  119. int pipe_ret, fd, mapsize, to_guest[2], to_host[2];
  120. unsigned long xfers = 0, notifies = 0, receives = 0;
  121. unsigned int first_cpu, last_cpu;
  122. cpu_set_t cpu_set;
  123. char buf[128];
  124. /* Create real file to mmap. */
  125. fd = open("/tmp/vringh_test-file", O_RDWR|O_CREAT|O_TRUNC, 0600);
  126. if (fd < 0)
  127. err(1, "Opening /tmp/vringh_test-file");
  128. /* Extra room at the end for some data, and indirects */
  129. mapsize = vring_size(RINGSIZE, ALIGN)
  130. + RINGSIZE * 2 * sizeof(int)
  131. + RINGSIZE * 6 * sizeof(struct vring_desc);
  132. mapsize = (mapsize + getpagesize() - 1) & ~(getpagesize() - 1);
  133. ftruncate(fd, mapsize);
  134. /* Parent and child use separate addresses, to check our mapping logic! */
  135. host_map = mmap(NULL, mapsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  136. guest_map = mmap(NULL, mapsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  137. pipe_ret = pipe(to_guest);
  138. assert(!pipe_ret);
  139. pipe_ret = pipe(to_host);
  140. assert(!pipe_ret);
  141. CPU_ZERO(&cpu_set);
  142. find_cpus(&first_cpu, &last_cpu);
  143. printf("Using CPUS %u and %u\n", first_cpu, last_cpu);
  144. fflush(stdout);
  145. if (fork() != 0) {
  146. struct vringh vrh;
  147. int status, err, rlen = 0;
  148. char rbuf[5];
  149. /* We are the host: never access guest addresses! */
  150. munmap(guest_map, mapsize);
  151. __user_addr_min = host_map;
  152. __user_addr_max = __user_addr_min + mapsize;
  153. user_addr_offset = host_map - guest_map;
  154. assert(user_addr_offset);
  155. close(to_guest[0]);
  156. close(to_host[1]);
  157. vring_init(&vrh.vring, RINGSIZE, host_map, ALIGN);
  158. vringh_init_user(&vrh, features, RINGSIZE, true,
  159. vrh.vring.desc, vrh.vring.avail, vrh.vring.used);
  160. CPU_SET(first_cpu, &cpu_set);
  161. if (sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set))
  162. errx(1, "Could not set affinity to cpu %u", first_cpu);
  163. while (xfers < NUM_XFERS) {
  164. struct iovec host_riov[2], host_wiov[2];
  165. struct vringh_iov riov, wiov;
  166. u16 head, written;
  167. if (fast_vringh) {
  168. for (;;) {
  169. err = vringh_get_head(&vrh, &head);
  170. if (err != 0)
  171. break;
  172. err = vringh_need_notify_user(&vrh);
  173. if (err < 0)
  174. errx(1, "vringh_need_notify_user: %i",
  175. err);
  176. if (err) {
  177. write(to_guest[1], "", 1);
  178. notifies++;
  179. }
  180. }
  181. if (err != 1)
  182. errx(1, "vringh_get_head");
  183. written = 0;
  184. goto complete;
  185. } else {
  186. vringh_iov_init(&riov,
  187. host_riov,
  188. ARRAY_SIZE(host_riov));
  189. vringh_iov_init(&wiov,
  190. host_wiov,
  191. ARRAY_SIZE(host_wiov));
  192. err = vringh_getdesc_user(&vrh, &riov, &wiov,
  193. getrange, &head);
  194. }
  195. if (err == 0) {
  196. err = vringh_need_notify_user(&vrh);
  197. if (err < 0)
  198. errx(1, "vringh_need_notify_user: %i",
  199. err);
  200. if (err) {
  201. write(to_guest[1], "", 1);
  202. notifies++;
  203. }
  204. if (!vringh_notify_enable_user(&vrh))
  205. continue;
  206. /* Swallow all notifies at once. */
  207. if (read(to_host[0], buf, sizeof(buf)) < 1)
  208. break;
  209. vringh_notify_disable_user(&vrh);
  210. receives++;
  211. continue;
  212. }
  213. if (err != 1)
  214. errx(1, "vringh_getdesc_user: %i", err);
  215. /* We simply copy bytes. */
  216. if (riov.used) {
  217. rlen = vringh_iov_pull_user(&riov, rbuf,
  218. sizeof(rbuf));
  219. if (rlen != 4)
  220. errx(1, "vringh_iov_pull_user: %i",
  221. rlen);
  222. assert(riov.i == riov.used);
  223. written = 0;
  224. } else {
  225. err = vringh_iov_push_user(&wiov, rbuf, rlen);
  226. if (err != rlen)
  227. errx(1, "vringh_iov_push_user: %i",
  228. err);
  229. assert(wiov.i == wiov.used);
  230. written = err;
  231. }
  232. complete:
  233. xfers++;
  234. err = vringh_complete_user(&vrh, head, written);
  235. if (err != 0)
  236. errx(1, "vringh_complete_user: %i", err);
  237. }
  238. err = vringh_need_notify_user(&vrh);
  239. if (err < 0)
  240. errx(1, "vringh_need_notify_user: %i", err);
  241. if (err) {
  242. write(to_guest[1], "", 1);
  243. notifies++;
  244. }
  245. wait(&status);
  246. if (!WIFEXITED(status))
  247. errx(1, "Child died with signal %i?", WTERMSIG(status));
  248. if (WEXITSTATUS(status) != 0)
  249. errx(1, "Child exited %i?", WEXITSTATUS(status));
  250. printf("Host: notified %lu, pinged %lu\n", notifies, receives);
  251. return 0;
  252. } else {
  253. struct guest_virtio_device gvdev;
  254. struct virtqueue *vq;
  255. unsigned int *data;
  256. struct vring_desc *indirects;
  257. unsigned int finished = 0;
  258. /* We pass sg[]s pointing into here, but we need RINGSIZE+1 */
  259. data = guest_map + vring_size(RINGSIZE, ALIGN);
  260. indirects = (void *)data + (RINGSIZE + 1) * 2 * sizeof(int);
  261. /* We are the guest. */
  262. munmap(host_map, mapsize);
  263. close(to_guest[1]);
  264. close(to_host[0]);
  265. gvdev.vdev.features = features;
  266. INIT_LIST_HEAD(&gvdev.vdev.vqs);
  267. spin_lock_init(&gvdev.vdev.vqs_list_lock);
  268. gvdev.to_host_fd = to_host[1];
  269. gvdev.notifies = 0;
  270. CPU_SET(first_cpu, &cpu_set);
  271. if (sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set))
  272. err(1, "Could not set affinity to cpu %u", first_cpu);
  273. vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &gvdev.vdev, true,
  274. false, guest_map,
  275. fast_vringh ? no_notify_host
  276. : parallel_notify_host,
  277. never_callback_guest, "guest vq");
  278. /* Don't kfree indirects. */
  279. __kfree_ignore_start = indirects;
  280. __kfree_ignore_end = indirects + RINGSIZE * 6;
  281. while (xfers < NUM_XFERS) {
  282. struct scatterlist sg[4];
  283. unsigned int num_sg, len;
  284. int *dbuf, err;
  285. bool output = !(xfers % 2);
  286. /* Consume bufs. */
  287. while ((dbuf = virtqueue_get_buf(vq, &len)) != NULL) {
  288. if (len == 4)
  289. assert(*dbuf == finished - 1);
  290. else if (!fast_vringh)
  291. assert(*dbuf == finished);
  292. finished++;
  293. }
  294. /* Produce a buffer. */
  295. dbuf = data + (xfers % (RINGSIZE + 1));
  296. if (output)
  297. *dbuf = xfers;
  298. else
  299. *dbuf = -1;
  300. switch ((xfers / sizeof(*dbuf)) % 4) {
  301. case 0:
  302. /* Nasty three-element sg list. */
  303. sg_init_table(sg, num_sg = 3);
  304. sg_set_buf(&sg[0], (void *)dbuf, 1);
  305. sg_set_buf(&sg[1], (void *)dbuf + 1, 2);
  306. sg_set_buf(&sg[2], (void *)dbuf + 3, 1);
  307. break;
  308. case 1:
  309. sg_init_table(sg, num_sg = 2);
  310. sg_set_buf(&sg[0], (void *)dbuf, 1);
  311. sg_set_buf(&sg[1], (void *)dbuf + 1, 3);
  312. break;
  313. case 2:
  314. sg_init_table(sg, num_sg = 1);
  315. sg_set_buf(&sg[0], (void *)dbuf, 4);
  316. break;
  317. case 3:
  318. sg_init_table(sg, num_sg = 4);
  319. sg_set_buf(&sg[0], (void *)dbuf, 1);
  320. sg_set_buf(&sg[1], (void *)dbuf + 1, 1);
  321. sg_set_buf(&sg[2], (void *)dbuf + 2, 1);
  322. sg_set_buf(&sg[3], (void *)dbuf + 3, 1);
  323. break;
  324. }
  325. /* May allocate an indirect, so force it to allocate
  326. * user addr */
  327. __kmalloc_fake = indirects + (xfers % RINGSIZE) * 4;
  328. if (output)
  329. err = virtqueue_add_outbuf(vq, sg, num_sg, dbuf,
  330. GFP_KERNEL);
  331. else
  332. err = virtqueue_add_inbuf(vq, sg, num_sg,
  333. dbuf, GFP_KERNEL);
  334. if (err == -ENOSPC) {
  335. if (!virtqueue_enable_cb_delayed(vq))
  336. continue;
  337. /* Swallow all notifies at once. */
  338. if (read(to_guest[0], buf, sizeof(buf)) < 1)
  339. break;
  340. receives++;
  341. virtqueue_disable_cb(vq);
  342. continue;
  343. }
  344. if (err)
  345. errx(1, "virtqueue_add_in/outbuf: %i", err);
  346. xfers++;
  347. virtqueue_kick(vq);
  348. }
  349. /* Any extra? */
  350. while (finished != xfers) {
  351. int *dbuf;
  352. unsigned int len;
  353. /* Consume bufs. */
  354. dbuf = virtqueue_get_buf(vq, &len);
  355. if (dbuf) {
  356. if (len == 4)
  357. assert(*dbuf == finished - 1);
  358. else
  359. assert(len == 0);
  360. finished++;
  361. continue;
  362. }
  363. if (!virtqueue_enable_cb_delayed(vq))
  364. continue;
  365. if (read(to_guest[0], buf, sizeof(buf)) < 1)
  366. break;
  367. receives++;
  368. virtqueue_disable_cb(vq);
  369. }
  370. printf("Guest: notified %lu, pinged %lu\n",
  371. gvdev.notifies, receives);
  372. vring_del_virtqueue(vq);
  373. return 0;
  374. }
  375. }
  376. int main(int argc, char *argv[])
  377. {
  378. struct virtio_device vdev;
  379. struct virtqueue *vq;
  380. struct vringh vrh;
  381. struct scatterlist guest_sg[RINGSIZE], *sgs[2];
  382. struct iovec host_riov[2], host_wiov[2];
  383. struct vringh_iov riov, wiov;
  384. struct vring_used_elem used[RINGSIZE];
  385. char buf[28];
  386. u16 head;
  387. int err;
  388. unsigned i;
  389. void *ret;
  390. bool (*getrange)(struct vringh *vrh, u64 addr, struct vringh_range *r);
  391. bool fast_vringh = false, parallel = false;
  392. getrange = getrange_iov;
  393. vdev.features = 0;
  394. INIT_LIST_HEAD(&vdev.vqs);
  395. spin_lock_init(&vdev.vqs_list_lock);
  396. while (argv[1]) {
  397. if (strcmp(argv[1], "--indirect") == 0)
  398. __virtio_set_bit(&vdev, VIRTIO_RING_F_INDIRECT_DESC);
  399. else if (strcmp(argv[1], "--eventidx") == 0)
  400. __virtio_set_bit(&vdev, VIRTIO_RING_F_EVENT_IDX);
  401. else if (strcmp(argv[1], "--virtio-1") == 0)
  402. __virtio_set_bit(&vdev, VIRTIO_F_VERSION_1);
  403. else if (strcmp(argv[1], "--slow-range") == 0)
  404. getrange = getrange_slow;
  405. else if (strcmp(argv[1], "--fast-vringh") == 0)
  406. fast_vringh = true;
  407. else if (strcmp(argv[1], "--parallel") == 0)
  408. parallel = true;
  409. else
  410. errx(1, "Unknown arg %s", argv[1]);
  411. argv++;
  412. }
  413. if (parallel)
  414. return parallel_test(vdev.features, getrange, fast_vringh);
  415. if (posix_memalign(&__user_addr_min, PAGE_SIZE, USER_MEM) != 0)
  416. abort();
  417. __user_addr_max = __user_addr_min + USER_MEM;
  418. memset(__user_addr_min, 0, vring_size(RINGSIZE, ALIGN));
  419. /* Set up guest side. */
  420. vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &vdev, true, false,
  421. __user_addr_min,
  422. never_notify_host, never_callback_guest,
  423. "guest vq");
  424. /* Set up host side. */
  425. vring_init(&vrh.vring, RINGSIZE, __user_addr_min, ALIGN);
  426. vringh_init_user(&vrh, vdev.features, RINGSIZE, true,
  427. vrh.vring.desc, vrh.vring.avail, vrh.vring.used);
  428. /* No descriptor to get yet... */
  429. err = vringh_getdesc_user(&vrh, &riov, &wiov, getrange, &head);
  430. if (err != 0)
  431. errx(1, "vringh_getdesc_user: %i", err);
  432. /* Guest puts in a descriptor. */
  433. memcpy(__user_addr_max - 1, "a", 1);
  434. sg_init_table(guest_sg, 1);
  435. sg_set_buf(&guest_sg[0], __user_addr_max - 1, 1);
  436. sg_init_table(guest_sg+1, 1);
  437. sg_set_buf(&guest_sg[1], __user_addr_max - 3, 2);
  438. sgs[0] = &guest_sg[0];
  439. sgs[1] = &guest_sg[1];
  440. /* May allocate an indirect, so force it to allocate user addr */
  441. __kmalloc_fake = __user_addr_min + vring_size(RINGSIZE, ALIGN);
  442. err = virtqueue_add_sgs(vq, sgs, 1, 1, &err, GFP_KERNEL);
  443. if (err)
  444. errx(1, "virtqueue_add_sgs: %i", err);
  445. __kmalloc_fake = NULL;
  446. /* Host retrieves it. */
  447. vringh_iov_init(&riov, host_riov, ARRAY_SIZE(host_riov));
  448. vringh_iov_init(&wiov, host_wiov, ARRAY_SIZE(host_wiov));
  449. err = vringh_getdesc_user(&vrh, &riov, &wiov, getrange, &head);
  450. if (err != 1)
  451. errx(1, "vringh_getdesc_user: %i", err);
  452. assert(riov.used == 1);
  453. assert(riov.iov[0].iov_base == __user_addr_max - 1);
  454. assert(riov.iov[0].iov_len == 1);
  455. if (getrange != getrange_slow) {
  456. assert(wiov.used == 1);
  457. assert(wiov.iov[0].iov_base == __user_addr_max - 3);
  458. assert(wiov.iov[0].iov_len == 2);
  459. } else {
  460. assert(wiov.used == 2);
  461. assert(wiov.iov[0].iov_base == __user_addr_max - 3);
  462. assert(wiov.iov[0].iov_len == 1);
  463. assert(wiov.iov[1].iov_base == __user_addr_max - 2);
  464. assert(wiov.iov[1].iov_len == 1);
  465. }
  466. err = vringh_iov_pull_user(&riov, buf, 5);
  467. if (err != 1)
  468. errx(1, "vringh_iov_pull_user: %i", err);
  469. assert(buf[0] == 'a');
  470. assert(riov.i == 1);
  471. assert(vringh_iov_pull_user(&riov, buf, 5) == 0);
  472. memcpy(buf, "bcdef", 5);
  473. err = vringh_iov_push_user(&wiov, buf, 5);
  474. if (err != 2)
  475. errx(1, "vringh_iov_push_user: %i", err);
  476. assert(memcmp(__user_addr_max - 3, "bc", 2) == 0);
  477. assert(wiov.i == wiov.used);
  478. assert(vringh_iov_push_user(&wiov, buf, 5) == 0);
  479. /* Host is done. */
  480. err = vringh_complete_user(&vrh, head, err);
  481. if (err != 0)
  482. errx(1, "vringh_complete_user: %i", err);
  483. /* Guest should see used token now. */
  484. __kfree_ignore_start = __user_addr_min + vring_size(RINGSIZE, ALIGN);
  485. __kfree_ignore_end = __kfree_ignore_start + 1;
  486. ret = virtqueue_get_buf(vq, &i);
  487. if (ret != &err)
  488. errx(1, "virtqueue_get_buf: %p", ret);
  489. assert(i == 2);
  490. /* Guest puts in a huge descriptor. */
  491. sg_init_table(guest_sg, RINGSIZE);
  492. for (i = 0; i < RINGSIZE; i++) {
  493. sg_set_buf(&guest_sg[i],
  494. __user_addr_max - USER_MEM/4, USER_MEM/4);
  495. }
  496. /* Fill contents with recognisable garbage. */
  497. for (i = 0; i < USER_MEM/4; i++)
  498. ((char *)__user_addr_max - USER_MEM/4)[i] = i;
  499. /* This will allocate an indirect, so force it to allocate user addr */
  500. __kmalloc_fake = __user_addr_min + vring_size(RINGSIZE, ALIGN);
  501. err = virtqueue_add_outbuf(vq, guest_sg, RINGSIZE, &err, GFP_KERNEL);
  502. if (err)
  503. errx(1, "virtqueue_add_outbuf (large): %i", err);
  504. __kmalloc_fake = NULL;
  505. /* Host picks it up (allocates new iov). */
  506. vringh_iov_init(&riov, host_riov, ARRAY_SIZE(host_riov));
  507. vringh_iov_init(&wiov, host_wiov, ARRAY_SIZE(host_wiov));
  508. err = vringh_getdesc_user(&vrh, &riov, &wiov, getrange, &head);
  509. if (err != 1)
  510. errx(1, "vringh_getdesc_user: %i", err);
  511. assert(riov.max_num & VRINGH_IOV_ALLOCATED);
  512. assert(riov.iov != host_riov);
  513. if (getrange != getrange_slow)
  514. assert(riov.used == RINGSIZE);
  515. else
  516. assert(riov.used == RINGSIZE * USER_MEM/4);
  517. assert(!(wiov.max_num & VRINGH_IOV_ALLOCATED));
  518. assert(wiov.used == 0);
  519. /* Pull data back out (in odd chunks), should be as expected. */
  520. for (i = 0; i < RINGSIZE * USER_MEM/4; i += 3) {
  521. err = vringh_iov_pull_user(&riov, buf, 3);
  522. if (err != 3 && i + err != RINGSIZE * USER_MEM/4)
  523. errx(1, "vringh_iov_pull_user large: %i", err);
  524. assert(buf[0] == (char)i);
  525. assert(err < 2 || buf[1] == (char)(i + 1));
  526. assert(err < 3 || buf[2] == (char)(i + 2));
  527. }
  528. assert(riov.i == riov.used);
  529. vringh_iov_cleanup(&riov);
  530. vringh_iov_cleanup(&wiov);
  531. /* Complete using multi interface, just because we can. */
  532. used[0].id = head;
  533. used[0].len = 0;
  534. err = vringh_complete_multi_user(&vrh, used, 1);
  535. if (err)
  536. errx(1, "vringh_complete_multi_user(1): %i", err);
  537. /* Free up those descriptors. */
  538. ret = virtqueue_get_buf(vq, &i);
  539. if (ret != &err)
  540. errx(1, "virtqueue_get_buf: %p", ret);
  541. /* Add lots of descriptors. */
  542. sg_init_table(guest_sg, 1);
  543. sg_set_buf(&guest_sg[0], __user_addr_max - 1, 1);
  544. for (i = 0; i < RINGSIZE; i++) {
  545. err = virtqueue_add_outbuf(vq, guest_sg, 1, &err, GFP_KERNEL);
  546. if (err)
  547. errx(1, "virtqueue_add_outbuf (multiple): %i", err);
  548. }
  549. /* Now get many, and consume them all at once. */
  550. vringh_iov_init(&riov, host_riov, ARRAY_SIZE(host_riov));
  551. vringh_iov_init(&wiov, host_wiov, ARRAY_SIZE(host_wiov));
  552. for (i = 0; i < RINGSIZE; i++) {
  553. err = vringh_getdesc_user(&vrh, &riov, &wiov, getrange, &head);
  554. if (err != 1)
  555. errx(1, "vringh_getdesc_user: %i", err);
  556. used[i].id = head;
  557. used[i].len = 0;
  558. }
  559. /* Make sure it wraps around ring, to test! */
  560. assert(vrh.vring.used->idx % RINGSIZE != 0);
  561. err = vringh_complete_multi_user(&vrh, used, RINGSIZE);
  562. if (err)
  563. errx(1, "vringh_complete_multi_user: %i", err);
  564. /* Free those buffers. */
  565. for (i = 0; i < RINGSIZE; i++) {
  566. unsigned len;
  567. assert(virtqueue_get_buf(vq, &len) != NULL);
  568. }
  569. /* Test weird (but legal!) indirect. */
  570. if (__virtio_test_bit(&vdev, VIRTIO_RING_F_INDIRECT_DESC)) {
  571. char *data = __user_addr_max - USER_MEM/4;
  572. struct vring_desc *d = __user_addr_max - USER_MEM/2;
  573. struct vring vring;
  574. /* Force creation of direct, which we modify. */
  575. __virtio_clear_bit(&vdev, VIRTIO_RING_F_INDIRECT_DESC);
  576. vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &vdev, true,
  577. false, __user_addr_min,
  578. never_notify_host,
  579. never_callback_guest,
  580. "guest vq");
  581. sg_init_table(guest_sg, 4);
  582. sg_set_buf(&guest_sg[0], d, sizeof(*d)*2);
  583. sg_set_buf(&guest_sg[1], d + 2, sizeof(*d)*1);
  584. sg_set_buf(&guest_sg[2], data + 6, 4);
  585. sg_set_buf(&guest_sg[3], d + 3, sizeof(*d)*3);
  586. err = virtqueue_add_outbuf(vq, guest_sg, 4, &err, GFP_KERNEL);
  587. if (err)
  588. errx(1, "virtqueue_add_outbuf (indirect): %i", err);
  589. vring_init(&vring, RINGSIZE, __user_addr_min, ALIGN);
  590. /* They're used in order, but double-check... */
  591. assert(vring.desc[0].addr == (unsigned long)d);
  592. assert(vring.desc[1].addr == (unsigned long)(d+2));
  593. assert(vring.desc[2].addr == (unsigned long)data + 6);
  594. assert(vring.desc[3].addr == (unsigned long)(d+3));
  595. vring.desc[0].flags |= VRING_DESC_F_INDIRECT;
  596. vring.desc[1].flags |= VRING_DESC_F_INDIRECT;
  597. vring.desc[3].flags |= VRING_DESC_F_INDIRECT;
  598. /* First indirect */
  599. d[0].addr = (unsigned long)data;
  600. d[0].len = 1;
  601. d[0].flags = VRING_DESC_F_NEXT;
  602. d[0].next = 1;
  603. d[1].addr = (unsigned long)data + 1;
  604. d[1].len = 2;
  605. d[1].flags = 0;
  606. /* Second indirect */
  607. d[2].addr = (unsigned long)data + 3;
  608. d[2].len = 3;
  609. d[2].flags = 0;
  610. /* Third indirect */
  611. d[3].addr = (unsigned long)data + 10;
  612. d[3].len = 5;
  613. d[3].flags = VRING_DESC_F_NEXT;
  614. d[3].next = 1;
  615. d[4].addr = (unsigned long)data + 15;
  616. d[4].len = 6;
  617. d[4].flags = VRING_DESC_F_NEXT;
  618. d[4].next = 2;
  619. d[5].addr = (unsigned long)data + 21;
  620. d[5].len = 7;
  621. d[5].flags = 0;
  622. /* Host picks it up (allocates new iov). */
  623. vringh_iov_init(&riov, host_riov, ARRAY_SIZE(host_riov));
  624. vringh_iov_init(&wiov, host_wiov, ARRAY_SIZE(host_wiov));
  625. err = vringh_getdesc_user(&vrh, &riov, &wiov, getrange, &head);
  626. if (err != 1)
  627. errx(1, "vringh_getdesc_user: %i", err);
  628. if (head != 0)
  629. errx(1, "vringh_getdesc_user: head %i not 0", head);
  630. assert(riov.max_num & VRINGH_IOV_ALLOCATED);
  631. if (getrange != getrange_slow)
  632. assert(riov.used == 7);
  633. else
  634. assert(riov.used == 28);
  635. err = vringh_iov_pull_user(&riov, buf, 29);
  636. assert(err == 28);
  637. /* Data should be linear. */
  638. for (i = 0; i < err; i++)
  639. assert(buf[i] == i);
  640. vringh_iov_cleanup(&riov);
  641. }
  642. /* Don't leak memory... */
  643. vring_del_virtqueue(vq);
  644. free(__user_addr_min);
  645. return 0;
  646. }