BlockStatsList *qmp_query_blockstats(bool has_query_nodes, bool query_nodes, Error **errp) { BlockStatsList *head = NULL, **p_next = &head; BlockBackend *blk = NULL; BlockDriverState *bs = NULL; /* Just to be safe if query_nodes is not always initialized */ query_nodes = has_query_nodes && query_nodes; while (next_query_bds(&blk, &bs, query_nodes)) { BlockStatsList *info = g_malloc0(sizeof(*info)); AioContext *ctx = blk ? blk_get_aio_context(blk) : bdrv_get_aio_context(bs); aio_context_acquire(ctx); info->value = bdrv_query_stats(blk, bs, !query_nodes); aio_context_release(ctx); *p_next = info; p_next = &info->next; } return head; }
static void scsi_write_complete(void * opaque, int ret) { SCSIGenericReq *r = (SCSIGenericReq *)opaque; SCSIDevice *s = r->req.dev; DPRINTF("scsi_write_complete() ret = %d\n", ret); assert(r->req.aiocb != NULL); r->req.aiocb = NULL; aio_context_acquire(blk_get_aio_context(s->conf.blk)); if (ret || r->req.io_canceled) { scsi_command_complete_noio(r, ret); goto done; } if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 && s->type == TYPE_TAPE) { s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; DPRINTF("block size %d\n", s->blocksize); } scsi_command_complete_noio(r, ret); done: aio_context_release(blk_get_aio_context(s->conf.blk)); }
static void test_acquire(void) { QemuThread thread; AcquireTestData data; /* Dummy event notifier ensures aio_poll() will block */ event_notifier_init(&data.notifier, false); set_event_notifier(ctx, &data.notifier, dummy_notifier_read); g_assert(!aio_poll(ctx, false)); /* consume aio_notify() */ qemu_mutex_init(&data.start_lock); qemu_mutex_lock(&data.start_lock); data.thread_acquired = false; qemu_thread_create(&thread, "test_acquire_thread", test_acquire_thread, &data, QEMU_THREAD_JOINABLE); /* Block in aio_poll(), let other thread kick us and acquire context */ aio_context_acquire(ctx); qemu_mutex_unlock(&data.start_lock); /* let the thread run */ g_assert(aio_poll(ctx, true)); g_assert(!data.thread_acquired); aio_context_release(ctx); qemu_thread_join(&thread); set_event_notifier(ctx, &data.notifier, NULL); event_notifier_cleanup(&data.notifier); g_assert(data.thread_acquired); }
int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn, BlockDriverState *vm_state_bs, uint64_t vm_state_size, BlockDriverState **first_bad_bs) { int err = 0; BlockDriverState *bs = NULL; while (err == 0 && (bs = bdrv_next(bs))) { AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); if (bs == vm_state_bs) { sn->vm_state_size = vm_state_size; err = bdrv_snapshot_create(bs, sn); } else if (bdrv_can_snapshot(bs)) { sn->vm_state_size = 0; err = bdrv_snapshot_create(bs, sn); } aio_context_release(ctx); } *first_bad_bs = bs; return err; }
static void *iothread_run(void *opaque) { IOThread *iothread = opaque; bool blocking; rcu_register_thread(); qemu_mutex_lock(&iothread->init_done_lock); iothread->thread_id = qemu_get_thread_id(); qemu_cond_signal(&iothread->init_done_cond); qemu_mutex_unlock(&iothread->init_done_lock); while (!iothread->stopping) { aio_context_acquire(iothread->ctx); blocking = true; while (!iothread->stopping && aio_poll(iothread->ctx, blocking)) { /* Progress was made, keep going */ blocking = false; } aio_context_release(iothread->ctx); } rcu_unregister_thread(); return NULL; }
static void blk_bh(void *opaque) { struct XenBlkDev *blkdev = opaque; aio_context_acquire(blkdev->ctx); blk_handle_requests(blkdev); aio_context_release(blkdev->ctx); }
static void xen_block_dataplane_bh(void *opaque) { XenBlockDataPlane *dataplane = opaque; aio_context_acquire(dataplane->ctx); xen_block_handle_requests(dataplane); aio_context_release(dataplane->ctx); }
/* Context: QEMU global mutex held */ void virtio_scsi_dataplane_start(VirtIOSCSI *s) { int i; int rc; BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); if (s->dataplane_started || s->dataplane_starting || s->dataplane_fenced || s->ctx != iothread_get_aio_context(vs->conf.iothread)) { return; } s->dataplane_starting = true; /* Set up guest notifier (irq) */ rc = k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, true); if (rc != 0) { fprintf(stderr, "virtio-scsi: Failed to set guest notifiers (%d), " "ensure -enable-kvm is set\n", rc); goto fail_guest_notifiers; } aio_context_acquire(s->ctx); rc = virtio_scsi_vring_init(s, vs->ctrl_vq, 0); if (rc) { goto fail_vrings; } rc = virtio_scsi_vring_init(s, vs->event_vq, 1); if (rc) { goto fail_vrings; } for (i = 0; i < vs->conf.num_queues; i++) { rc = virtio_scsi_vring_init(s, vs->cmd_vqs[i], i + 2); if (rc) { goto fail_vrings; } } s->dataplane_starting = false; s->dataplane_started = true; aio_context_release(s->ctx); return; fail_vrings: virtio_scsi_clear_aio(s); aio_context_release(s->ctx); for (i = 0; i < vs->conf.num_queues + 2; i++) { k->set_host_notifier(qbus->parent, i, false); } k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false); fail_guest_notifiers: s->dataplane_fenced = true; s->dataplane_starting = false; s->dataplane_started = true; }
BlockStatsList *qmp_query_blockstats(bool has_query_nodes, bool query_nodes, Error **errp) { BlockStatsList *head = NULL, **p_next = &head; BlockBackend *blk; BlockDriverState *bs; /* Just to be safe if query_nodes is not always initialized */ if (has_query_nodes && query_nodes) { for (bs = bdrv_next_node(NULL); bs; bs = bdrv_next_node(bs)) { BlockStatsList *info = g_malloc0(sizeof(*info)); AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); info->value = bdrv_query_bds_stats(bs, false); aio_context_release(ctx); *p_next = info; p_next = &info->next; } } else { for (blk = blk_next(NULL); blk; blk = blk_next(blk)) { BlockStatsList *info = g_malloc0(sizeof(*info)); AioContext *ctx = blk_get_aio_context(blk); BlockStats *s; aio_context_acquire(ctx); s = bdrv_query_bds_stats(blk_bs(blk), true); s->has_device = true; s->device = g_strdup(blk_name(blk)); bdrv_query_blk_stats(s->stats, blk); aio_context_release(ctx); info->value = s; *p_next = info; p_next = &info->next; } } return head; }
static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config) { VirtIOBlock *s = VIRTIO_BLK(vdev); struct virtio_blk_config blkcfg; memcpy(&blkcfg, config, sizeof(blkcfg)); aio_context_acquire(bdrv_get_aio_context(s->bs)); bdrv_set_enable_write_cache(s->bs, blkcfg.wce != 0); aio_context_release(bdrv_get_aio_context(s->bs)); }
static void scsi_command_complete(void *opaque, int ret) { SCSIGenericReq *r = (SCSIGenericReq *)opaque; SCSIDevice *s = r->req.dev; assert(r->req.aiocb != NULL); r->req.aiocb = NULL; aio_context_acquire(blk_get_aio_context(s->conf.blk)); scsi_command_complete_noio(r, ret); aio_context_release(blk_get_aio_context(s->conf.blk)); }
/* Context: QEMU global mutex held */ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtIOBlock *vblk = VIRTIO_BLK(s->vdev); int r; if (vblk->dataplane_started || s->starting) { return; } s->starting = true; s->vq = virtio_get_queue(s->vdev, 0); /* Set up guest notifier (irq) */ r = k->set_guest_notifiers(qbus->parent, 1, true); if (r != 0) { fprintf(stderr, "virtio-blk failed to set guest notifier (%d), " "ensure -enable-kvm is set\n", r); goto fail_guest_notifiers; } s->guest_notifier = virtio_queue_get_guest_notifier(s->vq); /* Set up virtqueue notify */ r = k->set_host_notifier(qbus->parent, 0, true); if (r != 0) { fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r); goto fail_host_notifier; } s->starting = false; vblk->dataplane_started = true; trace_virtio_blk_data_plane_start(s); blk_set_aio_context(s->conf->conf.blk, s->ctx); /* Kick right away to begin processing requests already in vring */ event_notifier_set(virtio_queue_get_host_notifier(s->vq)); /* Get this show started by hooking up our callbacks */ aio_context_acquire(s->ctx); virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, virtio_blk_data_plane_handle_output); aio_context_release(s->ctx); return; fail_host_notifier: k->set_guest_notifiers(qbus->parent, 1, false); fail_guest_notifiers: vblk->dataplane_disabled = true; s->starting = false; vblk->dataplane_started = true; }
static void block_job_defer_to_main_loop_bh(void *opaque) { BlockJobDeferToMainLoopData *data = opaque; AioContext *aio_context; qemu_bh_delete(data->bh); /* Prevent race with block_job_defer_to_main_loop() */ aio_context_acquire(data->aio_context); /* Fetch BDS AioContext again, in case it has changed */ aio_context = bdrv_get_aio_context(data->job->bs); aio_context_acquire(aio_context); data->fn(data->job, data->opaque); aio_context_release(aio_context); aio_context_release(data->aio_context); g_free(data); }
static void mirror_complete(BlockJob *job, Error **errp) { MirrorBlockJob *s = container_of(job, MirrorBlockJob, common); BlockDriverState *target; target = blk_bs(s->target); if (!s->synced) { error_setg(errp, "The active block job '%s' cannot be completed", job->id); return; } if (s->backing_mode == MIRROR_OPEN_BACKING_CHAIN) { int ret; assert(!target->backing); ret = bdrv_open_backing_file(target, NULL, "backing", errp); if (ret < 0) { return; } } /* block all operations on to_replace bs */ if (s->replaces) { AioContext *replace_aio_context; s->to_replace = bdrv_find_node(s->replaces); if (!s->to_replace) { error_setg(errp, "Node name '%s' not found", s->replaces); return; } replace_aio_context = bdrv_get_aio_context(s->to_replace); aio_context_acquire(replace_aio_context); /* TODO Translate this into permission system. Current definition of * GRAPH_MOD would require to request it for the parents; they might * not even be BlockDriverStates, however, so a BdrvChild can't address * them. May need redefinition of GRAPH_MOD. */ error_setg(&s->replace_blocker, "block device is in use by block-job-complete"); bdrv_op_block_all(s->to_replace, s->replace_blocker); bdrv_ref(s->to_replace); aio_context_release(replace_aio_context); } s->should_complete = true; block_job_enter(&s->common); }
BlockDriverState *bdrv_all_find_vmstate_bs(void) { bool not_found = true; BlockDriverState *bs = NULL; while (not_found && (bs = bdrv_next(bs))) { AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); not_found = !bdrv_can_snapshot(bs); aio_context_release(ctx); } return bs; }
static JobInfo *job_query_single(Job *job, Error **errp) { JobInfo *info; assert(!job_is_internal(job)); info = g_new(JobInfo, 1); *info = (JobInfo) { .id = g_strdup(job->id), .type = job_type(job), .status = job->status, .current_progress = job->progress_current, .total_progress = job->progress_total, .has_error = !!job->err, .error = job->err ? \ g_strdup(error_get_pretty(job->err)) : NULL, }; return info; } JobInfoList *qmp_query_jobs(Error **errp) { JobInfoList *head = NULL, **p_next = &head; Job *job; for (job = job_next(NULL); job; job = job_next(job)) { JobInfoList *elem; AioContext *aio_context; if (job_is_internal(job)) { continue; } elem = g_new0(JobInfoList, 1); aio_context = job->aio_context; aio_context_acquire(aio_context); elem->value = job_query_single(job, errp); aio_context_release(aio_context); if (!elem->value) { g_free(elem); qapi_free_JobInfoList(head); return NULL; } *p_next = elem; p_next = &elem->next; } return head; }
static void release_drive(Object *obj, const char *name, void *opaque) { DeviceState *dev = DEVICE(obj); Property *prop = opaque; BlockBackend **ptr = qdev_get_prop_ptr(dev, prop); if (*ptr) { AioContext *ctx = blk_get_aio_context(*ptr); aio_context_acquire(ctx); blockdev_auto_del(*ptr); blk_detach_dev(*ptr, dev); aio_context_release(ctx); } }
static void *test_acquire_thread(void *opaque) { AcquireTestData *data = opaque; /* Wait for other thread to let us start */ qemu_mutex_lock(&data->start_lock); qemu_mutex_unlock(&data->start_lock); aio_context_acquire(ctx); aio_context_release(ctx); data->thread_acquired = true; /* success, we got here */ return NULL; }
/* Get a job using its ID and acquire its AioContext */ static Job *find_job(const char *id, AioContext **aio_context, Error **errp) { Job *job; *aio_context = NULL; job = job_get(id); if (!job) { error_setg(errp, "Job not found"); return NULL; } *aio_context = job->aio_context; aio_context_acquire(*aio_context); return job; }
/* Context: QEMU global mutex held */ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtIOBlock *vblk = VIRTIO_BLK(s->vdev); unsigned i; unsigned nvqs = s->conf->num_queues; if (!vblk->dataplane_started || s->stopping) { return; } /* Better luck next time. */ if (vblk->dataplane_disabled) { vblk->dataplane_disabled = false; vblk->dataplane_started = false; return; } s->stopping = true; trace_virtio_blk_data_plane_stop(s); aio_context_acquire(s->ctx); /* Stop notifications for new requests from guest */ for (i = 0; i < nvqs; i++) { VirtQueue *vq = virtio_get_queue(s->vdev, i); virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, NULL); } /* Drain and switch bs back to the QEMU main loop */ blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context()); aio_context_release(s->ctx); for (i = 0; i < nvqs; i++) { virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); } /* Clean up guest notifier (irq) */ k->set_guest_notifiers(qbus->parent, nvqs, false); vblk->dataplane_started = false; s->stopping = false; }
int bdrv_all_goto_snapshot(const char *name, BlockDriverState **first_bad_bs) { int err = 0; BlockDriverState *bs = NULL; while (err == 0 && (bs = bdrv_next(bs))) { AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); if (bdrv_can_snapshot(bs)) { err = bdrv_snapshot_goto(bs, name); } aio_context_release(ctx); } *first_bad_bs = bs; return err; }
bool bdrv_all_can_snapshot(BlockDriverState **first_bad_bs) { bool ok = true; BlockDriverState *bs = NULL; while (ok && (bs = bdrv_next(bs))) { AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); if (bdrv_is_inserted(bs) && !bdrv_is_read_only(bs)) { ok = bdrv_can_snapshot(bs); } aio_context_release(ctx); } *first_bad_bs = bs; return ok; }
static void mirror_write_complete(void *opaque, int ret) { MirrorOp *op = opaque; MirrorBlockJob *s = op->s; aio_context_acquire(blk_get_aio_context(s->common.blk)); if (ret < 0) { BlockErrorAction action; bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset, op->bytes); action = mirror_error_action(s, false, -ret); if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) { s->ret = ret; } } mirror_iteration_done(op, ret); aio_context_release(blk_get_aio_context(s->common.blk)); }
void iothread_stop_all(void) { Object *container = object_get_objects_root(); BlockDriverState *bs; BdrvNextIterator it; for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *ctx = bdrv_get_aio_context(bs); if (ctx == qemu_get_aio_context()) { continue; } aio_context_acquire(ctx); bdrv_set_aio_context(bs, qemu_get_aio_context()); aio_context_release(ctx); } object_child_foreach(container, iothread_stop, NULL); }
static void virtio_blk_ioctl_complete(void *opaque, int status) { VirtIOBlockIoctlReq *ioctl_req = opaque; VirtIOBlockReq *req = ioctl_req->req; VirtIOBlock *s = req->dev; VirtIODevice *vdev = VIRTIO_DEVICE(s); struct virtio_scsi_inhdr *scsi; struct sg_io_hdr *hdr; scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base; if (status) { status = VIRTIO_BLK_S_UNSUPP; virtio_stl_p(vdev, &scsi->errors, 255); goto out; } hdr = &ioctl_req->hdr; /* * From SCSI-Generic-HOWTO: "Some lower level drivers (e.g. ide-scsi) * clear the masked_status field [hence status gets cleared too, see * block/scsi_ioctl.c] even when a CHECK_CONDITION or COMMAND_TERMINATED * status has occurred. However they do set DRIVER_SENSE in driver_status * field. Also a (sb_len_wr > 0) indicates there is a sense buffer. */ if (hdr->status == 0 && hdr->sb_len_wr > 0) { hdr->status = CHECK_CONDITION; } virtio_stl_p(vdev, &scsi->errors, hdr->status | (hdr->msg_status << 8) | (hdr->host_status << 16) | (hdr->driver_status << 24)); virtio_stl_p(vdev, &scsi->residual, hdr->resid); virtio_stl_p(vdev, &scsi->sense_len, hdr->sb_len_wr); virtio_stl_p(vdev, &scsi->data_len, hdr->dxfer_len); out: aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); virtio_blk_req_complete(req, status); virtio_blk_free_request(req); aio_context_release(blk_get_aio_context(s->conf.conf.blk)); g_free(ioctl_req); }
BlockStatsList *qmp_query_blockstats(Error **errp) { BlockStatsList *head = NULL, **p_next = &head; BlockDriverState *bs = NULL; while ((bs = bdrv_next(bs))) { BlockStatsList *info = g_malloc0(sizeof(*info)); AioContext *ctx = bdrv_get_aio_context(bs); aio_context_acquire(ctx); info->value = bdrv_query_stats(bs); aio_context_release(ctx); *p_next = info; p_next = &info->next; } return head; }
static void virtio_blk_flush_complete(void *opaque, int ret) { VirtIOBlockReq *req = opaque; VirtIOBlock *s = req->dev; aio_context_acquire(blk_get_aio_context(s->conf.conf.blk)); if (ret) { if (virtio_blk_handle_rw_error(req, -ret, 0)) { goto out; } } virtio_blk_req_complete(req, VIRTIO_BLK_S_OK); block_acct_done(blk_get_stats(req->dev->blk), &req->acct); virtio_blk_free_request(req); out: aio_context_release(blk_get_aio_context(s->conf.conf.blk)); }
/* Context: QEMU global mutex held */ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtIOBlock *vblk = VIRTIO_BLK(s->vdev); /* Better luck next time. */ if (s->disabled) { s->disabled = false; return; } if (!s->started || s->stopping) { return; } s->stopping = true; vblk->complete_request = s->saved_complete_request; trace_virtio_blk_data_plane_stop(s); aio_context_acquire(s->ctx); /* Stop notifications for new requests from guest */ aio_set_event_notifier(s->ctx, &s->host_notifier, true, NULL); /* Drain and switch bs back to the QEMU main loop */ blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context()); aio_context_release(s->ctx); /* Sync vring state back to virtqueue so that non-dataplane request * processing can continue when we disable the host notifier below. */ vring_teardown(&s->vring, s->vdev, 0); k->set_host_notifier(qbus->parent, 0, false); /* Clean up guest notifier (irq) */ k->set_guest_notifiers(qbus->parent, 1, false); s->started = false; s->stopping = false; }
static void *test_acquire_thread(void *opaque) { AcquireTestData *data = opaque; /* Wait for other thread to let us start */ qemu_mutex_lock(&data->start_lock); qemu_mutex_unlock(&data->start_lock); /* event_notifier_set might be called either before or after * the main thread's call to poll(). The test case's outcome * should be the same in either case. */ event_notifier_set(&data->notifier); aio_context_acquire(ctx); aio_context_release(ctx); data->thread_acquired = true; /* success, we got here */ return NULL; }
void qmp_block_set_write_threshold(const char *node_name, uint64_t threshold_bytes, Error **errp) { BlockDriverState *bs; AioContext *aio_context; bs = bdrv_find_node(node_name); if (!bs) { error_setg(errp, "Device '%s' not found", node_name); return; } aio_context = bdrv_get_aio_context(bs); aio_context_acquire(aio_context); bdrv_write_threshold_set(bs, threshold_bytes); aio_context_release(aio_context); }