/* The other side of virtio pushes buffers into our avail ring, and pulls them *offourusedring.Wedothereverse.Wetakebuffersofftheavailring, *andputthemontotheusedring.
*/
if (!vq->vring_addr) { /* there is no vring - return an error */ return ERR_CHANNEL_CLOSED;
}
/* the idx counter is free running, so check that it's no more *thantheringsizeawayfromlasttimewechecked...this
* should *never* happen, but we should be careful. */
uint16_t avail_cnt;
__builtin_sub_overflow(vq->vring.avail->idx, vq->last_avail_idx,
&avail_cnt); if (unlikely(avail_cnt > (uint16_t)vq->vring.num)) { /* such state is not recoverable */
panic("vq %u: new avail idx out of range (old %u new %u)\n", vq->id,
vq->last_avail_idx, vq->vring.avail->idx);
}
if (vq->last_avail_idx == vq->vring.avail->idx) {
event_unsignal(&vq->avail_event);
vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
smp_mb(); if (vq->last_avail_idx == vq->vring.avail->idx) { /* no buffers left */ return ERR_NOT_ENOUGH_BUFFER;
}
vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
event_signal(&vq->avail_event, false);
}
smp_rmb();
if (unlikely(next_idx >= vq->vring.num)) { /* index of the first descriptor in chain is out of range. vringisinnonrecoverablestate:wecannotevenreturn
an error to the other side */
panic("vq %u: head out of range %u (max %u)\n", vq->id, next_idx,
vq->vring.num);
}
if (unlikely(next_idx >= vq->vring.num)) { /* Descriptor chain is in invalid state. *Abortmessagehandling,returnanerrortothe *othersideandletitdealwithit.
*/
LTRACEF("vq %p: head out of range %u (max %u)\n", vq, next_idx,
vq->vring.num); return ERR_NOT_VALID;
}
if (iovlist->used < iovlist->cnt) { /* .iov_base will be set when we map this iov */
iovlist->iovs[iovlist->used].iov_len = desc->len;
iovlist->shared_mem_id[iovlist->used] =
(ext_mem_obj_id_t)desc->addr;
assert(iovlist->shared_mem_id[iovlist->used] == desc->addr);
iovlist->used++;
iovlist->len += desc->len;
} else { return ERR_TOO_BIG;
}
/* go to the next entry in the descriptor chain */
next_idx = desc->next;
} while (desc->flags & VRING_DESC_F_NEXT);
return NO_ERROR;
}
int vqueue_get_avail_buf(struct vqueue* vq, struct vqueue_buf* iovbuf) {
spin_lock_saved_state_t state;
spin_lock_save(&vq->slock, &state, VQ_LOCK_FLAGS); int ret = _vqueue_get_avail_buf_locked(vq, iovbuf);
spin_unlock_restore(&vq->slock, state, VQ_LOCK_FLAGS); return ret;
}
for (i = 0; i < vqiovs->used; i++) { /* see if it's already been mapped */
mutex_acquire(&mapped_list->lock);
obj = vqueue_mem_lookup(&mapped_list->list, vqiovs->shared_mem_id[i]);
mutex_release(&mapped_list->lock);
if (obj && obj->client_id == client_id &&
vqiovs->iovs[i].iov_len <= obj->size) {
LTRACEF("iov restored %s id= %lu (base= %p, size= %lu)\n",
mapped_list->in_direction ? "IN" : "OUT",
(unsignedlong)vqiovs->shared_mem_id[i], obj->iov_base,
(unsignedlong)obj->size);
vqiovs->iovs[i].iov_base = obj->iov_base; continue; /* use the previously mapped */
} elseif (obj) { /* otherwise, we need to drop old mapping and remap */
TRACEF("iov needs remapped for id= %lu\n",
(unsignedlong)vqiovs->shared_mem_id[i]);
mutex_acquire(&mapped_list->lock);
vqueue_mem_delete(&mapped_list->list, obj);
mutex_release(&mapped_list->lock);
free(obj);
}
/* allocate since it may be reused instead of unmapped after use */
obj = calloc(1, sizeof(struct vqueue_mem_obj)); if (unlikely(!obj)) {
TRACEF("calloc failure for vqueue_mem_obj for iov\n");
ret = ERR_NO_MEMORY; goto err;
}
mutex_acquire(&mapped_list->lock); if (unlikely(!vqueue_mem_insert(&mapped_list->list, obj)))
panic("Unhandled duplicate entry in ext_mem for iov\n");
mutex_release(&mapped_list->lock);
for (uint i = 0; i < vqiovs->used; i++) { /* base is expected to be set */
DEBUG_ASSERT(vqiovs->iovs[i].iov_base);
vmm_free_region(vmm_get_kernel_aspace(),
(vaddr_t)vqiovs->iovs[i].iov_base);
vqiovs->iovs[i].iov_base = NULL;
/* remove from list since it has been unmapped */
mutex_acquire(&mapped_list->lock);
obj = vqueue_mem_lookup(&mapped_list->list, vqiovs->shared_mem_id[i]); if (obj) {
LTRACEF("iov removed %s id= %lu (base= %p, size= %lu)\n",
mapped_list->in_direction ? "IN" : "OUT",
(unsignedlong)vqiovs->shared_mem_id[i],
vqiovs->iovs[i].iov_base,
(unsignedlong)vqiovs->iovs[i].iov_len);
vqueue_mem_delete(&mapped_list->list, obj);
free(obj);
} else {
TRACEF("iov mapping not found for id= %lu (base= %p, size= %lu)\n",
(unsignedlong)vqiovs->shared_mem_id[i],
vqiovs->iovs[i].iov_base,
(unsignedlong)vqiovs->iovs[i].iov_len);
}
mutex_release(&mapped_list->lock);
}
}
/* determine which list this entry is in */ for (int i = 0; i < list_cnt; i++) {
mapped = mapped_list[i];
obj = vqueue_mem_lookup(&mapped->list, id); if (obj) break;
mapped = NULL;
}
if (mapped) { /* fake a vqueue_iovs struct to use common interface */
memset(&fake_vqiovs, 0, sizeof(fake_vqiovs));
fake_vqiovs.iovs = fake_iovs;
fake_vqiovs.shared_mem_id = fake_shared_mem_id;
fake_vqiovs.used = 1;
fake_vqiovs.cnt = 1;
fake_vqiovs.iovs[0].iov_base = obj->iov_base;
fake_vqiovs.iovs[0].iov_len = obj->size;
fake_vqiovs.shared_mem_id[0] = id;
if (!vq->vring_addr) { /* there is no vring - return an error */ return ERR_CHANNEL_CLOSED;
}
if (buf->head >= vq->vring.num) { /* this would probable mean corrupted vring */
LTRACEF("vq %p: head (%u) out of range (%u)\n", vq, buf->head,
vq->vring.num); return ERR_NOT_VALID;
}
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.