aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/virtio_blk.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2013-03-20 01:14:27 -0400
committerRusty Russell <rusty@rustcorp.com.au>2013-03-20 01:14:54 -0400
commit8f39db9d3709afe944710f124111ec87467d25c7 (patch)
tree7ce3ac8d3b9d6fc47e9fc0a0edeb5c2e094242f0 /drivers/block/virtio_blk.c
parent5ee21a52c05b5670ceeaa502c15cf306e379f714 (diff)
virtio-blk: use virtqueue_add_sgs on bio path
(This is a respin of Paolo Bonzini's patch, but it calls virtqueue_add_sgs() instead of his multi-part API). Move the creation of the request header and response footer to __virtblk_add_req. vbr->sg only contains the data scatterlist, the header/footer are added separately using virtqueue_add_sgs(). With this change, virtio-blk (with use_bio) is not relying anymore on the virtio functions ignoring the end markers in a scatterlist. The next patch will do the same for the other path. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Reviewed-by: Asias He <asias@redhat.com>
Diffstat (limited to 'drivers/block/virtio_blk.c')
-rw-r--r--drivers/block/virtio_blk.c58
1 files changed, 29 insertions, 29 deletions
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index b271650032fa..cfbe39d35277 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -62,6 +62,7 @@ struct virtblk_req
62 struct virtio_blk *vblk; 62 struct virtio_blk *vblk;
63 int flags; 63 int flags;
64 u8 status; 64 u8 status;
65 int nents;
65 struct scatterlist sg[]; 66 struct scatterlist sg[];
66}; 67};
67 68
@@ -100,24 +101,36 @@ static inline struct virtblk_req *virtblk_alloc_req(struct virtio_blk *vblk,
100 return vbr; 101 return vbr;
101} 102}
102 103
103static inline int __virtblk_add_req(struct virtqueue *vq, 104static int __virtblk_add_req(struct virtqueue *vq,
104 struct virtblk_req *vbr, 105 struct virtblk_req *vbr)
105 unsigned long out,
106 unsigned long in)
107{ 106{
108 return virtqueue_add_buf(vq, vbr->sg, out, in, vbr, GFP_ATOMIC); 107 struct scatterlist hdr, status, *sgs[3];
108 unsigned int num_out = 0, num_in = 0;
109
110 sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr));
111 sgs[num_out++] = &hdr;
112
113 if (vbr->nents) {
114 if (vbr->out_hdr.type & VIRTIO_BLK_T_OUT)
115 sgs[num_out++] = vbr->sg;
116 else
117 sgs[num_out + num_in++] = vbr->sg;
118 }
119
120 sg_init_one(&status, &vbr->status, sizeof(vbr->status));
121 sgs[num_out + num_in++] = &status;
122
123 return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
109} 124}
110 125
111static void virtblk_add_req(struct virtblk_req *vbr, 126static void virtblk_add_req(struct virtblk_req *vbr)
112 unsigned int out, unsigned int in)
113{ 127{
114 struct virtio_blk *vblk = vbr->vblk; 128 struct virtio_blk *vblk = vbr->vblk;
115 DEFINE_WAIT(wait); 129 DEFINE_WAIT(wait);
116 int ret; 130 int ret;
117 131
118 spin_lock_irq(vblk->disk->queue->queue_lock); 132 spin_lock_irq(vblk->disk->queue->queue_lock);
119 while (unlikely((ret = __virtblk_add_req(vblk->vq, vbr, 133 while (unlikely((ret = __virtblk_add_req(vblk->vq, vbr)) < 0)) {
120 out, in)) < 0)) {
121 prepare_to_wait_exclusive(&vblk->queue_wait, &wait, 134 prepare_to_wait_exclusive(&vblk->queue_wait, &wait,
122 TASK_UNINTERRUPTIBLE); 135 TASK_UNINTERRUPTIBLE);
123 136
@@ -134,22 +147,18 @@ static void virtblk_add_req(struct virtblk_req *vbr,
134 147
135static void virtblk_bio_send_flush(struct virtblk_req *vbr) 148static void virtblk_bio_send_flush(struct virtblk_req *vbr)
136{ 149{
137 unsigned int out = 0, in = 0;
138
139 vbr->flags |= VBLK_IS_FLUSH; 150 vbr->flags |= VBLK_IS_FLUSH;
140 vbr->out_hdr.type = VIRTIO_BLK_T_FLUSH; 151 vbr->out_hdr.type = VIRTIO_BLK_T_FLUSH;
141 vbr->out_hdr.sector = 0; 152 vbr->out_hdr.sector = 0;
142 vbr->out_hdr.ioprio = 0; 153 vbr->out_hdr.ioprio = 0;
143 sg_set_buf(&vbr->sg[out++], &vbr->out_hdr, sizeof(vbr->out_hdr)); 154 vbr->nents = 0;
144 sg_set_buf(&vbr->sg[out + in++], &vbr->status, sizeof(vbr->status));
145 155
146 virtblk_add_req(vbr, out, in); 156 virtblk_add_req(vbr);
147} 157}
148 158
149static void virtblk_bio_send_data(struct virtblk_req *vbr) 159static void virtblk_bio_send_data(struct virtblk_req *vbr)
150{ 160{
151 struct virtio_blk *vblk = vbr->vblk; 161 struct virtio_blk *vblk = vbr->vblk;
152 unsigned int num, out = 0, in = 0;
153 struct bio *bio = vbr->bio; 162 struct bio *bio = vbr->bio;
154 163
155 vbr->flags &= ~VBLK_IS_FLUSH; 164 vbr->flags &= ~VBLK_IS_FLUSH;
@@ -157,24 +166,15 @@ static void virtblk_bio_send_data(struct virtblk_req *vbr)
157 vbr->out_hdr.sector = bio->bi_sector; 166 vbr->out_hdr.sector = bio->bi_sector;
158 vbr->out_hdr.ioprio = bio_prio(bio); 167 vbr->out_hdr.ioprio = bio_prio(bio);
159 168
160 sg_set_buf(&vbr->sg[out++], &vbr->out_hdr, sizeof(vbr->out_hdr)); 169 vbr->nents = blk_bio_map_sg(vblk->disk->queue, bio, vbr->sg);
161 170 if (vbr->nents) {
162 num = blk_bio_map_sg(vblk->disk->queue, bio, vbr->sg + out); 171 if (bio->bi_rw & REQ_WRITE)
163
164 sg_set_buf(&vbr->sg[num + out + in++], &vbr->status,
165 sizeof(vbr->status));
166
167 if (num) {
168 if (bio->bi_rw & REQ_WRITE) {
169 vbr->out_hdr.type |= VIRTIO_BLK_T_OUT; 172 vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
170 out += num; 173 else
171 } else {
172 vbr->out_hdr.type |= VIRTIO_BLK_T_IN; 174 vbr->out_hdr.type |= VIRTIO_BLK_T_IN;
173 in += num;
174 }
175 } 175 }
176 176
177 virtblk_add_req(vbr, out, in); 177 virtblk_add_req(vbr);
178} 178}
179 179
180static void virtblk_bio_send_data_work(struct work_struct *work) 180static void virtblk_bio_send_data_work(struct work_struct *work)