Revision d28a1b6e hw/virtio-blk.c

b/hw/virtio-blk.c
35 35
    VirtQueueElement elem;
36 36
    struct virtio_blk_inhdr *in;
37 37
    struct virtio_blk_outhdr *out;
38
    size_t size;
39
    uint8_t *buffer;
38
    QEMUIOVector qiov;
40 39
    struct VirtIOBlockReq *next;
41 40
} VirtIOBlockReq;
42 41

  
......
45 44
    VirtIOBlock *s = req->dev;
46 45

  
47 46
    req->in->status = status;
48
    virtqueue_push(s->vq, &req->elem, req->size + sizeof(*req->in));
47
    virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
49 48
    virtio_notify(&s->vdev, s->vq);
50 49

  
51
    qemu_free(req->buffer);
52 50
    qemu_free(req);
53 51
}
54 52

  
......
76 74
{
77 75
    VirtIOBlockReq *req = opaque;
78 76

  
79
    /* Copy read data to the guest */
80
    if (!ret && !(req->out->type & VIRTIO_BLK_T_OUT)) {
81
        size_t offset = 0;
82
        int i;
83

  
84
        for (i = 0; i < req->elem.in_num - 1; i++) {
85
            size_t len;
86

  
87
            /* Be pretty defensive wrt malicious guests */
88
            len = MIN(req->elem.in_sg[i].iov_len,
89
                      req->size - offset);
90

  
91
            memcpy(req->elem.in_sg[i].iov_base,
92
                   req->buffer + offset,
93
                   len);
94
            offset += len;
95
        }
96
    } else if (ret && (req->out->type & VIRTIO_BLK_T_OUT)) {
77
    if (ret && (req->out->type & VIRTIO_BLK_T_OUT)) {
97 78
        if (virtio_blk_handle_write_error(req, -ret))
98 79
            return;
99 80
    }
......
122 103
    return req;
123 104
}
124 105

  
125
static int virtio_blk_handle_write(VirtIOBlockReq *req)
106
static void virtio_blk_handle_write(VirtIOBlockReq *req)
126 107
{
127
    if (!req->buffer) {
128
        size_t offset = 0;
129
        int i;
130

  
131
        for (i = 1; i < req->elem.out_num; i++)
132
            req->size += req->elem.out_sg[i].iov_len;
133

  
134
        req->buffer = qemu_memalign(512, req->size);
135
        if (req->buffer == NULL) {
136
            qemu_free(req);
137
            return -1;
138
        }
139

  
140
        /* We copy the data from the SG list to avoid splitting up the request.
141
           This helps performance a lot until we can pass full sg lists as AIO
142
           operations */
143
        for (i = 1; i < req->elem.out_num; i++) {
144
            size_t len;
145

  
146
            len = MIN(req->elem.out_sg[i].iov_len,
147
                    req->size - offset);
148
            memcpy(req->buffer + offset,
149
                    req->elem.out_sg[i].iov_base,
150
                    len);
151
            offset += len;
152
        }
153
    }
108
    bdrv_aio_writev(req->dev->bs, req->out->sector, &req->qiov,
109
                    req->qiov.size / 512, virtio_blk_rw_complete, req);
110
}
154 111

  
155
    bdrv_aio_write(req->dev->bs, req->out->sector, req->buffer, req->size / 512,
156
            virtio_blk_rw_complete, req);
157
    return 0;
112
static void virtio_blk_handle_read(VirtIOBlockReq *req)
113
{
114
    bdrv_aio_readv(req->dev->bs, req->out->sector, &req->qiov,
115
                   req->qiov.size / 512, virtio_blk_rw_complete, req);
158 116
}
159 117

  
160 118
static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
......
163 121
    VirtIOBlockReq *req;
164 122

  
165 123
    while ((req = virtio_blk_get_request(s))) {
166
        int i;
167

  
168 124
        if (req->elem.out_num < 1 || req->elem.in_num < 1) {
169 125
            fprintf(stderr, "virtio-blk missing headers\n");
170 126
            exit(1);
......
187 143
            virtio_notify(vdev, vq);
188 144
            qemu_free(req);
189 145
        } else if (req->out->type & VIRTIO_BLK_T_OUT) {
190
            if (virtio_blk_handle_write(req) < 0)
191
                break;
146
            qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
147
                                     req->elem.out_num - 1);
148
            virtio_blk_handle_write(req);
192 149
        } else {
193
            for (i = 0; i < req->elem.in_num - 1; i++)
194
                req->size += req->elem.in_sg[i].iov_len;
195

  
196
            req->buffer = qemu_memalign(512, req->size);
197
            if (req->buffer == NULL) {
198
                qemu_free(req);
199
                break;
200
            }
201

  
202
            bdrv_aio_read(s->bs, req->out->sector,
203
                          req->buffer,
204
                          req->size / 512,
205
                          virtio_blk_rw_complete,
206
                          req);
150
            qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
151
                                     req->elem.in_num - 1);
152
            virtio_blk_handle_read(req);
207 153
        }
208 154
    }
209 155
    /*

Also available in: Unified diff