From patchwork Tue Feb 12 12:23:33 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 2128111 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 240393FCA4 for ; Tue, 12 Feb 2013 12:25:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933206Ab3BLMYG (ORCPT ); Tue, 12 Feb 2013 07:24:06 -0500 Received: from mail-vc0-f179.google.com ([209.85.220.179]:43661 "EHLO mail-vc0-f179.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933168Ab3BLMYE (ORCPT ); Tue, 12 Feb 2013 07:24:04 -0500 Received: by mail-vc0-f179.google.com with SMTP id gb23so5348vcb.38 for ; Tue, 12 Feb 2013 04:24:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:sender:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references; bh=RN33Sfjz8LzsCIiFeWbj0i17fRqN62LE+Wnn+Cdr0do=; b=R4oWVWHh+SG77tKzeWERU+sORdBIup6ywOzAwyB6ZqqtkevCqEuISlSAw/CBzQtlA+ l5aj5jVepZ9Rlf+8X02SULrqHxtWcUWCZ7Re+n/UCQ56ql9KAEXAT2Tte6+B2t1mALIe Rv+eg8m98aJLE1xf8TkS3sOtFnPLeB5odGwfBmuW4InSFKQsrryB6IsLUVbh2fEv33aY MBNiIQHgBoL/dOp1UexU2EBmAx5TPcj2tVCpV1PrMVomFz2zhV+1JyvJ631EKbNdntTd TcrNIqvedyB5WY6KcM9VKi2s+37d3yqK2SAnhkV8FuJX04oxfEkNNOU3KumDUMRuZKIM 9n2g== X-Received: by 10.52.38.234 with SMTP id j10mr9685540vdk.0.1360671843846; Tue, 12 Feb 2013 04:24:03 -0800 (PST) Received: from yakj.usersys.redhat.com (93-34-179-137.ip50.fastwebnet.it. [93.34.179.137]) by mx.google.com with ESMTPS id a19sm64574262vdh.9.2013.02.12.04.24.01 (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Tue, 12 Feb 2013 04:24:03 -0800 (PST) From: Paolo Bonzini To: linux-kernel@vger.kernel.org Cc: Wanlong Gao , asias@redhat.com, mst@redhat.com, Rusty Russell , kvm@vger.kernel.org, virtualization@lists.linux-foundation.org Subject: [PATCH 7/9] virtio-scsi: use virtqueue_start_buf Date: Tue, 12 Feb 2013 13:23:33 +0100 Message-Id: <1360671815-2135-8-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.1.2 In-Reply-To: <1360671815-2135-1-git-send-email-pbonzini@redhat.com> References: <1360671815-2135-1-git-send-email-pbonzini@redhat.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Using the new virtio_scsi_add_sg function lets us simplify the queueing path. In particular, all data protected by the tgt_lock is just gone (multiqueue will find a new use for the lock). The speedup is relatively small (2-4%) but it is worthwhile because of the code simplification it enables. And it will be particularly useful when adding multiqueue supoprt, because it keeps the tgt_lock critical sections very slim while avoiding a proliferation of locks. Signed-off-by: Wanlong Gao Signed-off-by: Paolo Bonzini --- drivers/scsi/virtio_scsi.c | 102 +++++++++++++++++++------------------------- 1 files changed, 44 insertions(+), 58 deletions(-) diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 3449a1f..6b752f7 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -59,11 +59,8 @@ struct virtio_scsi_vq { /* Per-target queue state */ struct virtio_scsi_target_state { - /* Protects sg. Lock hierarchy is tgt_lock -> vq_lock. */ + /* Never held at the same time as vq_lock. */ spinlock_t tgt_lock; - - /* For sglist construction when adding commands to the virtqueue. */ - struct scatterlist sg[]; }; /* Driver instance state */ @@ -351,89 +348,82 @@ static void virtscsi_event_done(struct virtqueue *vq) spin_unlock_irqrestore(&vscsi->event_vq.vq_lock, flags); }; -static void virtscsi_map_sgl(struct scatterlist *sg, unsigned int *p_idx, - struct scsi_data_buffer *sdb) -{ - struct sg_table *table = &sdb->table; - struct scatterlist *sg_elem; - unsigned int idx = *p_idx; - int i; - - for_each_sg(table->sgl, sg_elem, table->nents, i) - sg[idx++] = *sg_elem; - - *p_idx = idx; -} - /** - * virtscsi_map_cmd - map a scsi_cmd to a virtqueue scatterlist + * virtscsi_add_cmd - add a virtio_scsi_cmd to a virtqueue * @vscsi : virtio_scsi state * @cmd : command structure - * @out_num : number of read-only elements - * @in_num : number of write-only elements * @req_size : size of the request buffer * @resp_size : size of the response buffer - * - * Called with tgt_lock held. + * @gfp : flags to use for memory allocations */ -static void virtscsi_map_cmd(struct virtio_scsi_target_state *tgt, - struct virtio_scsi_cmd *cmd, - unsigned *out_num, unsigned *in_num, - size_t req_size, size_t resp_size) +static int virtscsi_add_cmd(struct virtqueue *vq, + struct virtio_scsi_cmd *cmd, + size_t req_size, size_t resp_size, gfp_t gfp) { struct scsi_cmnd *sc = cmd->sc; - struct scatterlist *sg = tgt->sg; - unsigned int idx = 0; + struct scatterlist sg; + unsigned int nents, nsg; + struct sg_table *out, *in; + int ret; + + out = in = NULL; + + if (sc && sc->sc_data_direction != DMA_NONE) { + if (sc->sc_data_direction != DMA_FROM_DEVICE) + out = &scsi_out(sc)->table; + if (sc->sc_data_direction != DMA_TO_DEVICE) + in = &scsi_in(sc)->table; + } + + nsg = 2 + (out ? 1 : 0) + (in ? 1 : 0); + nents = 2 + (out ? out->nents : 0) + (in ? in->nents : 0); + ret = virtqueue_start_buf(vq, cmd, nents, nsg, gfp); + if (ret < 0) + return ret; /* Request header. */ - sg_set_buf(&sg[idx++], &cmd->req, req_size); + sg_init_one(&sg, &cmd->req, req_size); + virtqueue_add_sg(vq, &sg, 1, DMA_TO_DEVICE); /* Data-out buffer. */ - if (sc && sc->sc_data_direction != DMA_FROM_DEVICE) - virtscsi_map_sgl(sg, &idx, scsi_out(sc)); - - *out_num = idx; + if (out) + virtqueue_add_sg(vq, out->sgl, out->nents, DMA_TO_DEVICE); /* Response header. */ - sg_set_buf(&sg[idx++], &cmd->resp, resp_size); + sg_init_one(&sg, &cmd->resp, resp_size); + virtqueue_add_sg(vq, &sg, 1, DMA_FROM_DEVICE); /* Data-in buffer */ - if (sc && sc->sc_data_direction != DMA_TO_DEVICE) - virtscsi_map_sgl(sg, &idx, scsi_in(sc)); + if (in) + virtqueue_add_sg(vq, in->sgl, in->nents, DMA_FROM_DEVICE); - *in_num = idx - *out_num; + virtqueue_end_buf(vq); + return 0; } -static int virtscsi_kick_cmd(struct virtio_scsi_target_state *tgt, - struct virtio_scsi_vq *vq, +static int virtscsi_kick_cmd(struct virtio_scsi_vq *vq, struct virtio_scsi_cmd *cmd, size_t req_size, size_t resp_size, gfp_t gfp) { - unsigned int out_num, in_num; unsigned long flags; - int err; + int ret; bool needs_kick = false; - spin_lock_irqsave(&tgt->tgt_lock, flags); - virtscsi_map_cmd(tgt, cmd, &out_num, &in_num, req_size, resp_size); - - spin_lock(&vq->vq_lock); - err = virtqueue_add_buf(vq->vq, tgt->sg, out_num, in_num, cmd, gfp); - spin_unlock(&tgt->tgt_lock); - if (!err) + spin_lock_irqsave(&vq->vq_lock, flags); + ret = virtscsi_add_cmd(vq->vq, cmd, req_size, resp_size, gfp); + if (!ret) needs_kick = virtqueue_kick_prepare(vq->vq); spin_unlock_irqrestore(&vq->vq_lock, flags); if (needs_kick) virtqueue_notify(vq->vq); - return err; + return ret; } static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) { struct virtio_scsi *vscsi = shost_priv(sh); - struct virtio_scsi_target_state *tgt = vscsi->tgt[sc->device->id]; struct virtio_scsi_cmd *cmd; int ret; @@ -467,7 +457,7 @@ static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE); memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len); - if (virtscsi_kick_cmd(tgt, &vscsi->req_vq, cmd, + if (virtscsi_kick_cmd(&vscsi->req_vq, cmd, sizeof cmd->req.cmd, sizeof cmd->resp.cmd, GFP_ATOMIC) == 0) ret = 0; @@ -481,11 +471,10 @@ out: static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd) { DECLARE_COMPLETION_ONSTACK(comp); - struct virtio_scsi_target_state *tgt = vscsi->tgt[cmd->sc->device->id]; int ret = FAILED; cmd->comp = ∁ - if (virtscsi_kick_cmd(tgt, &vscsi->ctrl_vq, cmd, + if (virtscsi_kick_cmd(&vscsi->ctrl_vq, cmd, sizeof cmd->req.tmf, sizeof cmd->resp.tmf, GFP_NOIO) < 0) goto out; @@ -592,14 +581,11 @@ static struct virtio_scsi_target_state *virtscsi_alloc_tgt( gfp_t gfp_mask = GFP_KERNEL; /* We need extra sg elements at head and tail. */ - tgt = kmalloc(sizeof(*tgt) + sizeof(tgt->sg[0]) * (sg_elems + 2), - gfp_mask); - + tgt = kmalloc(sizeof(*tgt), gfp_mask); if (!tgt) return NULL; spin_lock_init(&tgt->tgt_lock); - sg_init_table(tgt->sg, sg_elems + 2); return tgt; }