From patchwork Tue Jun 17 06:32:09 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fam Zheng X-Patchwork-Id: 360347 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 36E19140099 for ; Tue, 17 Jun 2014 16:34:23 +1000 (EST) Received: from localhost ([::1]:47641 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WwmyL-00088b-30 for incoming@patchwork.ozlabs.org; Tue, 17 Jun 2014 02:34:21 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40783) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WwmwT-0004Vi-0E for qemu-devel@nongnu.org; Tue, 17 Jun 2014 02:32:31 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WwmwL-0006Yd-Er for qemu-devel@nongnu.org; Tue, 17 Jun 2014 02:32:24 -0400 Received: from mx1.redhat.com ([209.132.183.28]:30299) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WwmwL-0006YV-76 for qemu-devel@nongnu.org; Tue, 17 Jun 2014 02:32:17 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s5H6WG3R012627 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 17 Jun 2014 02:32:16 -0400 Received: from T430.redhat.com (vpn1-113-251.nay.redhat.com [10.66.113.251]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s5H6VpAM024106; Tue, 17 Jun 2014 02:32:13 -0400 From: Fam Zheng To: qemu-devel@nongnu.org Date: Tue, 17 Jun 2014 14:32:09 +0800 Message-Id: <1402986730-25642-7-git-send-email-famz@redhat.com> In-Reply-To: <1402986730-25642-1-git-send-email-famz@redhat.com> References: <1402986730-25642-1-git-send-email-famz@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: Kevin Wolf , Paolo Bonzini , Stefan Hajnoczi Subject: [Qemu-devel] [PATCH v2 6/7] virtio-blk: Unify {non-, }dataplane's request handlings X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This drops request handling code from dataplane, and uses code from hw/block/virtio-blk.c. It starts to use multiwrite as non-dataplane does. Dataplane sets VirtIOBlock.complete_request to vring version, and calls into non-dataplane's process handling. In complete_request_early, qiov.size is added to vring push length, because it's also called in rw completion now. Signed-off-by: Fam Zheng --- hw/block/dataplane/virtio-blk.c | 183 +++++----------------------------------- 1 file changed, 19 insertions(+), 164 deletions(-) diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 29e7ec3..b6afa55 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -47,6 +47,8 @@ struct VirtIOBlockDataPlane { /* Operation blocker on BDS */ Error *blocker; + void (*saved_complete_request)(struct VirtIOBlockReq *req, + unsigned char status); }; /* Raise an interrupt to signal guest, if necessary */ @@ -59,179 +61,27 @@ static void notify_guest(VirtIOBlockDataPlane *s) event_notifier_set(s->guest_notifier); } -static void complete_rdwr(void *opaque, int ret) -{ - VirtIOBlockReq *req = opaque; - struct virtio_blk_inhdr hdr; - int len; - - if (likely(ret == 0)) { - hdr.status = VIRTIO_BLK_S_OK; - len = req->qiov.size; - } else { - hdr.status = VIRTIO_BLK_S_IOERR; - len = 0; - } - - trace_virtio_blk_data_plane_complete_request(req->dev->dataplane, - req->elem->index, ret); - - stb_p(&req->in->status, hdr.status); - - /* According to the virtio specification len should be the number of bytes - * written to, but for virtio-blk it seems to be the number of bytes - * transferred plus the status bytes. - */ - vring_push(&req->dev->dataplane->vring, req->elem, len + sizeof(hdr)); - notify_guest(req->dev->dataplane); - g_slice_free(VirtIOBlockReq, req); -} - static void complete_request_early(VirtIOBlockReq *req, unsigned char status) { stb_p(&req->in->status, status); - vring_push(&req->dev->dataplane->vring, req->elem, sizeof(*req->in)); + vring_push(&req->dev->dataplane->vring, req->elem, + req->qiov.size + sizeof(*req->in)); notify_guest(req->dev->dataplane); g_slice_free(VirtIOBlockReq, req); } -/* Get disk serial number */ -static void do_get_id_cmd(VirtIOBlockReq *req, - struct iovec *iov, unsigned int iov_cnt) -{ - char id[VIRTIO_BLK_ID_BYTES]; - - /* Serial number not NUL-terminated when longer than buffer */ - strncpy(id, req->dev->blk.serial ? req->dev->blk.serial : "", sizeof(id)); - iov_from_buf(iov, iov_cnt, 0, id, sizeof(id)); - complete_request_early(req, VIRTIO_BLK_S_OK); -} - - -static void do_rdwr_cmd(bool read, VirtIOBlockReq *req, - struct iovec *iov, unsigned iov_cnt) -{ - QEMUIOVector *qiov; - int nb_sectors; - int64_t sector_num; - - qemu_iovec_init_external(&req->qiov, iov, iov_cnt); - - qiov = &req->qiov; - - sector_num = req->out.sector * 512 / BDRV_SECTOR_SIZE; - nb_sectors = qiov->size / BDRV_SECTOR_SIZE; - - if (read) { - bdrv_aio_readv(req->dev->blk.conf.bs, - sector_num, qiov, nb_sectors, - complete_rdwr, req); - } else { - bdrv_aio_writev(req->dev->blk.conf.bs, - sector_num, qiov, nb_sectors, - complete_rdwr, req); - } -} - -static void complete_flush(void *opaque, int ret) -{ - VirtIOBlockReq *req = opaque; - unsigned char status; - - if (ret == 0) { - status = VIRTIO_BLK_S_OK; - } else { - status = VIRTIO_BLK_S_IOERR; - } - - complete_request_early(req, status); -} - -static void do_flush_cmd(VirtIOBlockReq *req) -{ - - bdrv_aio_flush(req->dev->blk.conf.bs, complete_flush, req); -} - -static void do_scsi_cmd(VirtIOBlockReq *req) -{ - int status; - - status = virtio_blk_handle_scsi_req(req->dev, req->elem); - complete_request_early(req, status); -} - -static int process_request(VirtIOBlockDataPlane *s, VirtQueueElement *elem) -{ - struct iovec *iov = elem->out_sg; - struct iovec *in_iov = elem->in_sg; - unsigned out_num = elem->out_num; - unsigned in_num = elem->in_num; - VirtIOBlockReq *req; - - req = g_slice_new(VirtIOBlockReq); - req->dev = VIRTIO_BLK(s->vdev); - req->elem = elem; - /* Copy in outhdr */ - if (unlikely(iov_to_buf(iov, out_num, 0, &req->out, - sizeof(req->out)) != sizeof(req->out))) { - error_report("virtio-blk request outhdr too short"); - g_slice_free(VirtIOBlockReq, req); - return -EFAULT; - } - iov_discard_front(&iov, &out_num, sizeof(req->out)); - - /* We are likely safe with the iov_len check, because inhdr is only 1 byte, - * but checking here in case the header gets bigger in the future. */ - if (in_num < 1 || in_iov[in_num - 1].iov_len < sizeof(*req->in)) { - error_report("virtio-blk request inhdr too short"); - return -EFAULT; - } - - /* Grab inhdr for later */ - req->in = (void *)in_iov[in_num - 1].iov_base - + in_iov[in_num - 1].iov_len - sizeof(*req->in); - iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr)); - - /* TODO Linux sets the barrier bit even when not advertised! */ - req->out.type &= ~VIRTIO_BLK_T_BARRIER; - - switch (req->out.type) { - case VIRTIO_BLK_T_IN: - do_rdwr_cmd(true, req, in_iov, in_num); - return 0; - - case VIRTIO_BLK_T_OUT: - do_rdwr_cmd(false, req, iov, out_num); - return 0; - - case VIRTIO_BLK_T_SCSI_CMD: - do_scsi_cmd(req); - return 0; - - case VIRTIO_BLK_T_FLUSH: - do_flush_cmd(req); - return 0; - - case VIRTIO_BLK_T_GET_ID: - do_get_id_cmd(req, in_iov, in_num); - return 0; - - default: - error_report("virtio-blk unsupported request type %#x", req->out.type); - g_slice_free(VirtIOBlockReq, req); - return -EFAULT; - } -} - static void handle_notify(EventNotifier *e) { VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane, host_notifier); VirtQueueElement *elem; + VirtIOBlockReq *req; int ret; + MultiReqBuffer mrb = { + .num_writes = 0, + }; event_notifier_test_and_clear(&s->host_notifier); for (;;) { @@ -248,14 +98,14 @@ static void handle_notify(EventNotifier *e) trace_virtio_blk_data_plane_process_request(s, elem->out_num, elem->in_num, elem->index); - if (process_request(s, elem) < 0) { - vring_set_broken(&s->vring); - vring_free_element(elem); - ret = -EFAULT; - break; - } + req = g_slice_new(VirtIOBlockReq); + req->dev = VIRTIO_BLK(s->vdev); + req->elem = elem; + virtio_blk_handle_request(req, &mrb); } + virtio_submit_multiwrite(s->blk->conf.bs, &mrb); + if (likely(ret == -EAGAIN)) { /* vring emptied */ /* Re-enable guest->host notifies and stop processing the vring. * But if the guest has snuck in more descriptors, keep processing. @@ -275,6 +125,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, Error **errp) { VirtIOBlockDataPlane *s; + VirtIOBlock *vblk = VIRTIO_BLK(vdev); Error *local_err = NULL; *dataplane = NULL; @@ -317,6 +168,8 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, bdrv_op_block_all(blk->conf.bs, s->blocker); *dataplane = s; + s->saved_complete_request = vblk->complete_request; + vblk->complete_request = complete_request_early; } /* Context: QEMU global mutex held */ @@ -391,10 +244,12 @@ 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); 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);