Ejemplo n.º 1
0
static void process_msg_disconnect(IVShmemState *s, uint16_t posn,
                                   Error **errp)
{
    IVSHMEM_DPRINTF("posn %d has gone away\n", posn);
    if (posn >= s->nb_peers || posn == s->vm_id) {
        error_setg(errp, "invalid peer %d", posn);
        return;
    }
    close_peer_eventfds(s, posn);
}
Ejemplo n.º 2
0
static void pci_ivshmem_exit(PCIDevice *dev)
{
    IVShmemState *s = IVSHMEM(dev);
    int i;

    fifo8_destroy(&s->incoming_fifo);

    if (s->migration_blocker) {
        migrate_del_blocker(s->migration_blocker);
        error_free(s->migration_blocker);
    }

    if (memory_region_is_mapped(&s->ivshmem)) {
        if (!s->hostmem) {
            void *addr = memory_region_get_ram_ptr(&s->ivshmem);
            int fd;

            if (munmap(addr, s->ivshmem_size) == -1) {
                error_report("Failed to munmap shared memory %s",
                             strerror(errno));
            }

            fd = qemu_get_ram_fd(memory_region_get_ram_addr(&s->ivshmem));
            if (fd != -1) {
                close(fd);
            }
        }

        vmstate_unregister_ram(&s->ivshmem, DEVICE(dev));
        memory_region_del_subregion(&s->bar, &s->ivshmem);
    }

    if (s->eventfd_chr) {
        for (i = 0; i < s->vectors; i++) {
            if (s->eventfd_chr[i]) {
                qemu_chr_free(s->eventfd_chr[i]);
            }
        }
        g_free(s->eventfd_chr);
    }

    if (s->peers) {
        for (i = 0; i < s->nb_peers; i++) {
            close_peer_eventfds(s, i);
        }
        g_free(s->peers);
    }

    if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
        msix_uninit_exclusive_bar(dev);
    }

    g_free(s->msi_vectors);
}
Ejemplo n.º 3
0
static void ivshmem_exit(PCIDevice *dev)
{
    IVShmemState *s = IVSHMEM_COMMON(dev);
    int i;

    if (s->migration_blocker) {
        migrate_del_blocker(s->migration_blocker);
        error_free(s->migration_blocker);
    }

    if (memory_region_is_mapped(s->ivshmem_bar2)) {
        if (!s->hostmem) {
            void *addr = memory_region_get_ram_ptr(s->ivshmem_bar2);
            int fd;

            if (munmap(addr, memory_region_size(s->ivshmem_bar2) == -1)) {
                error_report("Failed to munmap shared memory %s",
                             strerror(errno));
            }

            fd = memory_region_get_fd(s->ivshmem_bar2);
            close(fd);
        }

        vmstate_unregister_ram(s->ivshmem_bar2, DEVICE(dev));
    }

    if (s->peers) {
        for (i = 0; i < s->nb_peers; i++) {
            close_peer_eventfds(s, i);
        }
        g_free(s->peers);
    }

    if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
        msix_uninit_exclusive_bar(dev);
    }

    g_free(s->msi_vectors);
}
Ejemplo n.º 4
0
static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
{
    IVShmemState *s = opaque;
    int incoming_fd;
    int new_eventfd;
    int64_t incoming_posn;
    Error *err = NULL;
    Peer *peer;

    if (!fifo_update_and_get_i64(s, buf, size, &incoming_posn)) {
        return;
    }

    if (incoming_posn < -1) {
        IVSHMEM_DPRINTF("invalid incoming_posn %" PRId64 "\n", incoming_posn);
        return;
    }

    /* pick off s->server_chr->msgfd and store it, posn should accompany msg */
    incoming_fd = qemu_chr_fe_get_msgfd(s->server_chr);
    IVSHMEM_DPRINTF("posn is %" PRId64 ", fd is %d\n",
                    incoming_posn, incoming_fd);

    /* make sure we have enough space for this peer */
    if (incoming_posn >= s->nb_peers) {
        if (resize_peers(s, incoming_posn + 1) < 0) {
            error_report("failed to resize peers array");
            if (incoming_fd != -1) {
                close(incoming_fd);
            }
            return;
        }
    }

    peer = &s->peers[incoming_posn];

    if (incoming_fd == -1) {
        /* if posn is positive and unseen before then this is our posn*/
        if (incoming_posn >= 0 && s->vm_id == -1) {
            /* receive our posn */
            s->vm_id = incoming_posn;
        } else {
            /* otherwise an fd == -1 means an existing peer has gone away */
            IVSHMEM_DPRINTF("posn %" PRId64 " has gone away\n", incoming_posn);
            close_peer_eventfds(s, incoming_posn);
        }
        return;
    }

    /* if the position is -1, then it's shared memory region fd */
    if (incoming_posn == -1) {
        void * map_ptr;

        if (memory_region_is_mapped(&s->ivshmem)) {
            error_report("shm already initialized");
            close(incoming_fd);
            return;
        }

        if (check_shm_size(s, incoming_fd, &err) == -1) {
            error_report_err(err);
            close(incoming_fd);
            return;
        }

        /* mmap the region and map into the BAR2 */
        map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
                                                            incoming_fd, 0);
        if (map_ptr == MAP_FAILED) {
            error_report("Failed to mmap shared memory %s", strerror(errno));
            close(incoming_fd);
            return;
        }
        memory_region_init_ram_ptr(&s->ivshmem, OBJECT(s),
                                   "ivshmem.bar2", s->ivshmem_size, map_ptr);
        qemu_set_ram_fd(s->ivshmem.ram_addr, incoming_fd);
        vmstate_register_ram(&s->ivshmem, DEVICE(s));

        IVSHMEM_DPRINTF("guest h/w addr = %p, size = %" PRIu64 "\n",
                        map_ptr, s->ivshmem_size);

        memory_region_add_subregion(&s->bar, 0, &s->ivshmem);

        return;
    }

    /* each peer has an associated array of eventfds, and we keep
     * track of how many eventfds received so far */
    /* get a new eventfd: */
    if (peer->nb_eventfds >= s->vectors) {
        error_report("Too many eventfd received, device has %d vectors",
                     s->vectors);
        close(incoming_fd);
        return;
    }

    new_eventfd = peer->nb_eventfds++;

    /* this is an eventfd for a particular peer VM */
    IVSHMEM_DPRINTF("eventfds[%" PRId64 "][%d] = %d\n", incoming_posn,
                    new_eventfd, incoming_fd);
    event_notifier_init_fd(&peer->eventfds[new_eventfd], incoming_fd);
    fcntl_setfl(incoming_fd, O_NONBLOCK); /* msix/irqfd poll non block */

    if (incoming_posn == s->vm_id) {
        setup_interrupt(s, new_eventfd);
    }

    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
        ivshmem_add_eventfd(s, incoming_posn, new_eventfd);
    }
}