err = vringh_need_notify_user(&vrh); if (err < 0)
errx(1, "vringh_need_notify_user: %i", err); if (err) {
write(to_guest[1], "", 1);
notifies++;
}
wait(&status); if (!WIFEXITED(status))
errx(1, "Child died with signal %i?", WTERMSIG(status)); if (WEXITSTATUS(status) != 0)
errx(1, "Child exited %i?", WEXITSTATUS(status));
printf("Host: notified %lu, pinged %lu\n", notifies, receives); return 0;
} else { struct guest_virtio_device gvdev; struct virtqueue *vq; unsignedint *data; struct vring_desc *indirects; unsignedint finished = 0;
/* We pass sg[]s pointing into here, but we need RINGSIZE+1 */
data = guest_map + vring_size(RINGSIZE, ALIGN);
indirects = (void *)data + (RINGSIZE + 1) * 2 * sizeof(int);
/* We are the guest. */
munmap(host_map, mapsize);
/* May allocate an indirect, so force it to allocate
* user addr */
__kmalloc_fake = indirects + (xfers % RINGSIZE) * 4; if (output)
err = virtqueue_add_outbuf(vq, sg, num_sg, dbuf,
GFP_KERNEL); else
err = virtqueue_add_inbuf(vq, sg, num_sg,
dbuf, GFP_KERNEL);
if (err == -ENOSPC) { if (!virtqueue_enable_cb_delayed(vq)) continue; /* Swallow all notifies at once. */ if (read(to_guest[0], buf, sizeof(buf)) < 1) break;
receives++;
virtqueue_disable_cb(vq); continue;
}
if (err)
errx(1, "virtqueue_add_in/outbuf: %i", err);
xfers++;
virtqueue_kick(vq);
}
/* Any extra? */ while (finished != xfers) { int *dbuf; unsignedint len;
/* May allocate an indirect, so force it to allocate user addr */
__kmalloc_fake = __user_addr_min + vring_size(RINGSIZE, ALIGN);
err = virtqueue_add_sgs(vq, sgs, 1, 1, &err, GFP_KERNEL); if (err)
errx(1, "virtqueue_add_sgs: %i", err);
__kmalloc_fake = NULL;
/* Host is done. */
err = vringh_complete_user(&vrh, head, err); if (err != 0)
errx(1, "vringh_complete_user: %i", err);
/* Guest should see used token now. */
__kfree_ignore_start = __user_addr_min + vring_size(RINGSIZE, ALIGN);
__kfree_ignore_end = __kfree_ignore_start + 1;
ret = virtqueue_get_buf(vq, &i); if (ret != &err)
errx(1, "virtqueue_get_buf: %p", ret);
assert(i == 2);
/* Guest puts in a huge descriptor. */
sg_init_table(guest_sg, RINGSIZE); for (i = 0; i < RINGSIZE; i++) {
sg_set_buf(&guest_sg[i],
__user_addr_max - USER_MEM/4, USER_MEM/4);
}
/* Fill contents with recognisable garbage. */ for (i = 0; i < USER_MEM/4; i++)
((char *)__user_addr_max - USER_MEM/4)[i] = i;
/* This will allocate an indirect, so force it to allocate user addr */
__kmalloc_fake = __user_addr_min + vring_size(RINGSIZE, ALIGN);
err = virtqueue_add_outbuf(vq, guest_sg, RINGSIZE, &err, GFP_KERNEL); if (err)
errx(1, "virtqueue_add_outbuf (large): %i", err);
__kmalloc_fake = NULL;
/* Host picks it up (allocates new iov). */
vringh_iov_init(&riov, host_riov, ARRAY_SIZE(host_riov));
vringh_iov_init(&wiov, host_wiov, ARRAY_SIZE(host_wiov));
/* Pull data back out (in odd chunks), should be as expected. */ for (i = 0; i < RINGSIZE * USER_MEM/4; i += 3) {
err = vringh_iov_pull_user(&riov, buf, 3); if (err != 3 && i + err != RINGSIZE * USER_MEM/4)
errx(1, "vringh_iov_pull_user large: %i", err);
assert(buf[0] == (char)i);
assert(err < 2 || buf[1] == (char)(i + 1));
assert(err < 3 || buf[2] == (char)(i + 2));
}
assert(riov.i == riov.used);
vringh_iov_cleanup(&riov);
vringh_iov_cleanup(&wiov);
/* Complete using multi interface, just because we can. */
used[0].id = head;
used[0].len = 0;
err = vringh_complete_multi_user(&vrh, used, 1); if (err)
errx(1, "vringh_complete_multi_user(1): %i", err);
/* Free up those descriptors. */
ret = virtqueue_get_buf(vq, &i); if (ret != &err)
errx(1, "virtqueue_get_buf: %p", ret);
/* Add lots of descriptors. */
sg_init_table(guest_sg, 1);
sg_set_buf(&guest_sg[0], __user_addr_max - 1, 1); for (i = 0; i < RINGSIZE; i++) {
err = virtqueue_add_outbuf(vq, guest_sg, 1, &err, GFP_KERNEL); if (err)
errx(1, "virtqueue_add_outbuf (multiple): %i", err);
}
/* Now get many, and consume them all at once. */
vringh_iov_init(&riov, host_riov, ARRAY_SIZE(host_riov));
vringh_iov_init(&wiov, host_wiov, ARRAY_SIZE(host_wiov));
for (i = 0; i < RINGSIZE; i++) {
err = vringh_getdesc_user(&vrh, &riov, &wiov, getrange, &head); if (err != 1)
errx(1, "vringh_getdesc_user: %i", err);
used[i].id = head;
used[i].len = 0;
} /* Make sure it wraps around ring, to test! */
assert(vrh.vring.used->idx % RINGSIZE != 0);
err = vringh_complete_multi_user(&vrh, used, RINGSIZE); if (err)
errx(1, "vringh_complete_multi_user: %i", err);
/* Free those buffers. */ for (i = 0; i < RINGSIZE; i++) { unsigned len;
assert(virtqueue_get_buf(vq, &len) != NULL);
}
/* Host picks it up (allocates new iov). */
vringh_iov_init(&riov, host_riov, ARRAY_SIZE(host_riov));
vringh_iov_init(&wiov, host_wiov, ARRAY_SIZE(host_wiov));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.