aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2012-06-13 10:56:32 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-07-20 03:58:57 -0400
commit139fe45abc2234b20fd5ecbcb7ea6d3688fed5e5 (patch)
tree4861934faa4808c0c12b5669f03d1e8df5dc1216
parentb5ee8f2802c559fccb177c0a117f5cd56c1049cc (diff)
[SCSI] virtio-scsi: split locking per vq
Keep a separate lock for each virtqueue. While not particularly important now, it prepares the code for when we will add support for multiple request queues. It is also more tidy as soon as we introduce a separate lock for the sglist. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r--drivers/scsi/virtio_scsi.c77
1 files changed, 52 insertions, 25 deletions
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index b0ad5aa6b552..0ecf95e214d3 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -43,15 +43,22 @@ struct virtio_scsi_cmd {
43 } resp; 43 } resp;
44} ____cacheline_aligned_in_smp; 44} ____cacheline_aligned_in_smp;
45 45
46struct virtio_scsi_vq {
47 /* Protects vq */
48 spinlock_t vq_lock;
49
50 struct virtqueue *vq;
51};
52
46/* Driver instance state */ 53/* Driver instance state */
47struct virtio_scsi { 54struct virtio_scsi {
48 /* Protects ctrl_vq, req_vq and sg[] */ 55 /* Protects sg[]. The lock hierarchy is sg_lock -> vq_lock. */
49 spinlock_t vq_lock; 56 spinlock_t sg_lock;
50 57
51 struct virtio_device *vdev; 58 struct virtio_device *vdev;
52 struct virtqueue *ctrl_vq; 59 struct virtio_scsi_vq ctrl_vq;
53 struct virtqueue *event_vq; 60 struct virtio_scsi_vq event_vq;
54 struct virtqueue *req_vq; 61 struct virtio_scsi_vq req_vq;
55 62
56 /* For sglist construction when adding commands to the virtqueue. */ 63 /* For sglist construction when adding commands to the virtqueue. */
57 struct scatterlist sg[]; 64 struct scatterlist sg[];
@@ -147,26 +154,25 @@ static void virtscsi_complete_cmd(void *buf)
147 154
148static void virtscsi_vq_done(struct virtqueue *vq, void (*fn)(void *buf)) 155static void virtscsi_vq_done(struct virtqueue *vq, void (*fn)(void *buf))
149{ 156{
150 struct Scsi_Host *sh = virtio_scsi_host(vq->vdev);
151 struct virtio_scsi *vscsi = shost_priv(sh);
152 void *buf; 157 void *buf;
153 unsigned long flags;
154 unsigned int len; 158 unsigned int len;
155 159
156 spin_lock_irqsave(&vscsi->vq_lock, flags);
157
158 do { 160 do {
159 virtqueue_disable_cb(vq); 161 virtqueue_disable_cb(vq);
160 while ((buf = virtqueue_get_buf(vq, &len)) != NULL) 162 while ((buf = virtqueue_get_buf(vq, &len)) != NULL)
161 fn(buf); 163 fn(buf);
162 } while (!virtqueue_enable_cb(vq)); 164 } while (!virtqueue_enable_cb(vq));
163
164 spin_unlock_irqrestore(&vscsi->vq_lock, flags);
165} 165}
166 166
167static void virtscsi_req_done(struct virtqueue *vq) 167static void virtscsi_req_done(struct virtqueue *vq)
168{ 168{
169 struct Scsi_Host *sh = virtio_scsi_host(vq->vdev);
170 struct virtio_scsi *vscsi = shost_priv(sh);
171 unsigned long flags;
172
173 spin_lock_irqsave(&vscsi->req_vq.vq_lock, flags);
169 virtscsi_vq_done(vq, virtscsi_complete_cmd); 174 virtscsi_vq_done(vq, virtscsi_complete_cmd);
175 spin_unlock_irqrestore(&vscsi->req_vq.vq_lock, flags);
170}; 176};
171 177
172static void virtscsi_complete_free(void *buf) 178static void virtscsi_complete_free(void *buf)
@@ -181,12 +187,24 @@ static void virtscsi_complete_free(void *buf)
181 187
182static void virtscsi_ctrl_done(struct virtqueue *vq) 188static void virtscsi_ctrl_done(struct virtqueue *vq)
183{ 189{
190 struct Scsi_Host *sh = virtio_scsi_host(vq->vdev);
191 struct virtio_scsi *vscsi = shost_priv(sh);
192 unsigned long flags;
193
194 spin_lock_irqsave(&vscsi->ctrl_vq.vq_lock, flags);
184 virtscsi_vq_done(vq, virtscsi_complete_free); 195 virtscsi_vq_done(vq, virtscsi_complete_free);
196 spin_unlock_irqrestore(&vscsi->ctrl_vq.vq_lock, flags);
185}; 197};
186 198
187static void virtscsi_event_done(struct virtqueue *vq) 199static void virtscsi_event_done(struct virtqueue *vq)
188{ 200{
201 struct Scsi_Host *sh = virtio_scsi_host(vq->vdev);
202 struct virtio_scsi *vscsi = shost_priv(sh);
203 unsigned long flags;
204
205 spin_lock_irqsave(&vscsi->event_vq.vq_lock, flags);
189 virtscsi_vq_done(vq, virtscsi_complete_free); 206 virtscsi_vq_done(vq, virtscsi_complete_free);
207 spin_unlock_irqrestore(&vscsi->event_vq.vq_lock, flags);
190}; 208};
191 209
192static void virtscsi_map_sgl(struct scatterlist *sg, unsigned int *p_idx, 210static void virtscsi_map_sgl(struct scatterlist *sg, unsigned int *p_idx,
@@ -250,7 +268,7 @@ static void virtscsi_map_cmd(struct virtio_scsi *vscsi,
250 *in_num = idx - *out_num; 268 *in_num = idx - *out_num;
251} 269}
252 270
253static int virtscsi_kick_cmd(struct virtio_scsi *vscsi, struct virtqueue *vq, 271static int virtscsi_kick_cmd(struct virtio_scsi *vscsi, struct virtio_scsi_vq *vq,
254 struct virtio_scsi_cmd *cmd, 272 struct virtio_scsi_cmd *cmd,
255 size_t req_size, size_t resp_size, gfp_t gfp) 273 size_t req_size, size_t resp_size, gfp_t gfp)
256{ 274{
@@ -258,17 +276,19 @@ static int virtscsi_kick_cmd(struct virtio_scsi *vscsi, struct virtqueue *vq,
258 unsigned long flags; 276 unsigned long flags;
259 int ret; 277 int ret;
260 278
261 spin_lock_irqsave(&vscsi->vq_lock, flags); 279 spin_lock_irqsave(&vscsi->sg_lock, flags);
262
263 virtscsi_map_cmd(vscsi, cmd, &out_num, &in_num, req_size, resp_size); 280 virtscsi_map_cmd(vscsi, cmd, &out_num, &in_num, req_size, resp_size);
264 281
265 ret = virtqueue_add_buf(vq, vscsi->sg, out_num, in_num, cmd, gfp); 282 spin_lock(&vq->vq_lock);
283 ret = virtqueue_add_buf(vq->vq, vscsi->sg, out_num, in_num, cmd, gfp);
266 if (ret >= 0) 284 if (ret >= 0)
267 ret = virtqueue_kick_prepare(vq); 285 ret = virtqueue_kick_prepare(vq->vq);
286
287 spin_unlock(&vq->vq_lock);
288 spin_unlock_irqrestore(&vscsi->sg_lock, flags);
268 289
269 spin_unlock_irqrestore(&vscsi->vq_lock, flags);
270 if (ret > 0) 290 if (ret > 0)
271 virtqueue_notify(vq); 291 virtqueue_notify(vq->vq);
272 return ret; 292 return ret;
273} 293}
274 294
@@ -302,7 +322,7 @@ static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc)
302 BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE); 322 BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE);
303 memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len); 323 memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len);
304 324
305 if (virtscsi_kick_cmd(vscsi, vscsi->req_vq, cmd, 325 if (virtscsi_kick_cmd(vscsi, &vscsi->req_vq, cmd,
306 sizeof cmd->req.cmd, sizeof cmd->resp.cmd, 326 sizeof cmd->req.cmd, sizeof cmd->resp.cmd,
307 GFP_ATOMIC) >= 0) 327 GFP_ATOMIC) >= 0)
308 ret = 0; 328 ret = 0;
@@ -317,7 +337,7 @@ static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
317 int ret = FAILED; 337 int ret = FAILED;
318 338
319 cmd->comp = &comp; 339 cmd->comp = &comp;
320 if (virtscsi_kick_cmd(vscsi, vscsi->ctrl_vq, cmd, 340 if (virtscsi_kick_cmd(vscsi, &vscsi->ctrl_vq, cmd,
321 sizeof cmd->req.tmf, sizeof cmd->resp.tmf, 341 sizeof cmd->req.tmf, sizeof cmd->resp.tmf,
322 GFP_NOIO) < 0) 342 GFP_NOIO) < 0)
323 goto out; 343 goto out;
@@ -410,6 +430,13 @@ static struct scsi_host_template virtscsi_host_template = {
410 &__val, sizeof(__val)); \ 430 &__val, sizeof(__val)); \
411 }) 431 })
412 432
433static void virtscsi_init_vq(struct virtio_scsi_vq *virtscsi_vq,
434 struct virtqueue *vq)
435{
436 spin_lock_init(&virtscsi_vq->vq_lock);
437 virtscsi_vq->vq = vq;
438}
439
413static int virtscsi_init(struct virtio_device *vdev, 440static int virtscsi_init(struct virtio_device *vdev,
414 struct virtio_scsi *vscsi) 441 struct virtio_scsi *vscsi)
415{ 442{
@@ -431,9 +458,9 @@ static int virtscsi_init(struct virtio_device *vdev,
431 if (err) 458 if (err)
432 return err; 459 return err;
433 460
434 vscsi->ctrl_vq = vqs[0]; 461 virtscsi_init_vq(&vscsi->ctrl_vq, vqs[0]);
435 vscsi->event_vq = vqs[1]; 462 virtscsi_init_vq(&vscsi->event_vq, vqs[1]);
436 vscsi->req_vq = vqs[2]; 463 virtscsi_init_vq(&vscsi->req_vq, vqs[2]);
437 464
438 virtscsi_config_set(vdev, cdb_size, VIRTIO_SCSI_CDB_SIZE); 465 virtscsi_config_set(vdev, cdb_size, VIRTIO_SCSI_CDB_SIZE);
439 virtscsi_config_set(vdev, sense_size, VIRTIO_SCSI_SENSE_SIZE); 466 virtscsi_config_set(vdev, sense_size, VIRTIO_SCSI_SENSE_SIZE);
@@ -466,7 +493,7 @@ static int __devinit virtscsi_probe(struct virtio_device *vdev)
466 vdev->priv = shost; 493 vdev->priv = shost;
467 494
468 /* Random initializations. */ 495 /* Random initializations. */
469 spin_lock_init(&vscsi->vq_lock); 496 spin_lock_init(&vscsi->sg_lock);
470 sg_init_table(vscsi->sg, sg_elems + 2); 497 sg_init_table(vscsi->sg, sg_elems + 2);
471 498
472 err = virtscsi_init(vdev, vscsi); 499 err = virtscsi_init(vdev, vscsi);