[PATCH v2 07/10] kvm tools: Split io request from completion

Sasha Levin
2011-11-01T16:08:21Z

This patch splits IO request processing from completion notification.

Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
---
tools/kvm/disk/core.c | 6 +-
tools/kvm/include/kvm/disk-image.h | 4 +-
tools/kvm/include/kvm/virtio-blk.h | 1 +
tools/kvm/virtio/blk.c | 111 ++++++++++++++++++++++++------------
4 files changed, 81 insertions(+), 41 deletions(-)

diff --git a/tools/kvm/disk/core.c b/tools/kvm/disk/core.c
index c1cb52f..a5e6713 100644
--- a/tools/kvm/disk/core.c
+++ b/tools/kvm/disk/core.c
@@ -152,7 +152,7 @@ ssize_t disk_image__read(struct disk_image *disk, u64 sector, const struct iovec
}

if (disk->disk_req_cb)
- disk->disk_req_cb(param);
+ disk->disk_req_cb(param, total);

return total;
}
@@ -184,7 +184,7 @@ ssize_t disk_image__write(struct disk_image *disk, u64 sector, const struct iove
}

if (disk->disk_req_cb)
- disk->disk_req_cb(param);
+ disk->disk_req_cb(param, total);

return total;
}
@@ -200,7 +200,7 @@ ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *l
return *len;
}

-void disk_image__set_callback(struct disk_image *disk, void (*disk_req_cb)(void *param))
+void disk_image__set_callback(struct disk_image *disk, void (*disk_req_cb)(void *param, long len))
{
disk->disk_req_cb = disk_req_cb;
}
diff --git a/tools/kvm/include/kvm/disk-image.h b/tools/kvm/include/kvm/disk-image.h
index f22213f..632e54d 100644
--- a/tools/kvm/include/kvm/disk-image.h
+++ b/tools/kvm/include/kvm/disk-image.h
@@ -45,7 +45,7 @@ struct disk_image {
struct disk_image_operations *ops;
void *priv;
void *disk_req_cb_param;
- void (*disk_req_cb)(void *param);
+ void (*disk_req_cb)(void *param, long len);
};

struct disk_image *disk_image__open(const char *filename, bool readonly);
@@ -72,5 +72,5 @@ ssize_t raw_image__read_sector_mmap(struct disk_image *disk, u64 sector,
ssize_t raw_image__write_sector_mmap(struct disk_image *disk, u64 sector,
const struct iovec *iov, int iovcount, void *param);
int raw_image__close(struct disk_image *disk);
-void disk_image__set_callback(struct disk_image *disk, void (*disk_req_cb)(void *param));
+void disk_image__set_callback(struct disk_image *disk, void (*disk_req_cb)(void *param, long len));
#endif /* KVM__DISK_IMAGE_H */
diff --git a/tools/kvm/include/kvm/virtio-blk.h b/tools/kvm/include/kvm/virtio-blk.h
index 8c4fb91..63731a9 100644
--- a/tools/kvm/include/kvm/virtio-blk.h
+++ b/tools/kvm/include/kvm/virtio-blk.h
@@ -8,5 +8,6 @@ struct kvm;
void virtio_blk__init(struct kvm *kvm, struct disk_image *disk);
void virtio_blk__init_all(struct kvm *kvm);
void virtio_blk__delete_all(struct kvm *kvm);
+void virtio_blk_complete(void *param, long len);

#endif /* KVM__BLK_VIRTIO_H */
diff --git a/tools/kvm/virtio/blk.c b/tools/kvm/virtio/blk.c
index 9db293e..be53111 100644
--- a/tools/kvm/virtio/blk.c
+++ b/tools/kvm/virtio/blk.c
@@ -29,17 +29,21 @@
*/
#define DISK_SEG_MAX (VIRTIO_BLK_QUEUE_SIZE - 2)

-struct blk_dev_job {
+struct blk_dev_req {
+ struct list_head list;
struct virt_queue *vq;
struct blk_dev *bdev;
struct iovec iov[VIRTIO_BLK_QUEUE_SIZE];
u16 out, in, head;
- struct thread_pool__job job_id;
+ struct kvm *kvm;
};

struct blk_dev {
pthread_mutex_t mutex;
+ pthread_mutex_t req_mutex;
+
struct list_head list;
+ struct list_head req_list;

struct virtio_pci vpci;
struct virtio_blk_config blk_config;
@@ -47,41 +51,78 @@ struct blk_dev {
u32 features;

struct virt_queue vqs[NUM_VIRT_QUEUES];
- struct blk_dev_job jobs[VIRTIO_BLK_QUEUE_SIZE];
- u16 job_idx;
+ struct blk_dev_req reqs[VIRTIO_BLK_QUEUE_SIZE];
};

static LIST_HEAD(bdevs);
static int compat_id;

-static void virtio_blk_do_io_request(struct kvm *kvm, void *param)
+static struct blk_dev_req *virtio_blk_req_pop(struct blk_dev *bdev)
+{
+ struct blk_dev_req *req = NULL;
+
+ mutex_lock(&bdev->req_mutex);
+ if (!list_empty(&bdev->req_list)) {
+ req = list_first_entry(&bdev->req_list, struct blk_dev_req, list);
+ list_del_init(&req->list);
+ }
+ mutex_unlock(&bdev->req_mutex);
+
+ return req;
+}
+
+static void virtio_blk_req_push(struct blk_dev *bdev, struct blk_dev_req *req)
+{
+ mutex_lock(&bdev->req_mutex);
+ list_add(&req->list, &bdev->req_list);
+ mutex_unlock(&bdev->req_mutex);
+}
+
+void virtio_blk_complete(void *param, long len)
{
- struct virtio_blk_outhdr *req;
+ struct blk_dev_req *req = param;
+ struct blk_dev *bdev = req->bdev;
+ int queueid = req->vq - bdev->vqs;
u8 *status;
+
+ /* status */
+ status = req->iov[req->out + req->in - 1].iov_base;
+ *status = (len < 0) ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK;
+
+ mutex_lock(&bdev->mutex);
+ virt_queue__set_used_elem(req->vq, req->head, len);
+ mutex_unlock(&bdev->mutex);
+
+ virtio_pci__signal_vq(req->kvm, &bdev->vpci, queueid);
+
+ virtio_blk_req_push(req->bdev, req);
+}
+
+static void virtio_blk_do_io_request(struct kvm *kvm, struct blk_dev_req *req)
+{
+ struct virtio_blk_outhdr *req_hdr;
ssize_t block_cnt;
- struct blk_dev_job *job;
struct blk_dev *bdev;
struct virt_queue *queue;
struct iovec *iov;
u16 out, in, head;

block_cnt = -1;
- job = param;
- bdev = job->bdev;
- queue = job->vq;
- iov = job->iov;
- out = job->out;
- in = job->in;
- head = job->head;
- req = iov[0].iov_base;
-
- switch (req->type) {
+ bdev = req->bdev;
+ queue = req->vq;
+ iov = req->iov;
+ out = req->out;
+ in = req->in;
+ head = req->head;
+ req_hdr = iov[0].iov_base;
+
+ switch (req_hdr->type) {
case VIRTIO_BLK_T_IN:
- block_cnt = disk_image__read(bdev->disk, req->sector, iov + 1,
+ block_cnt = disk_image__read(bdev->disk, req_hdr->sector, iov + 1,
in + out - 2, NULL);
break;
case VIRTIO_BLK_T_OUT:
- block_cnt = disk_image__write(bdev->disk, req->sector, iov + 1,
+ block_cnt = disk_image__write(bdev->disk, req_hdr->sector, iov + 1,
in + out - 2, NULL);
break;
case VIRTIO_BLK_T_FLUSH:
@@ -92,35 +133,27 @@ static void virtio_blk_do_io_request(struct kvm *kvm, void *param)
disk_image__get_serial(bdev->disk, (iov + 1)->iov_base, &block_cnt);
break;
default:
- pr_warning("request type %d", req->type);
+ pr_warning("request type %d", req_hdr->type);
block_cnt = -1;
break;
}

- /* status */
- status = iov[out + in - 1].iov_base;
- *status = (block_cnt < 0) ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK;
-
- mutex_lock(&bdev->mutex);
- virt_queue__set_used_elem(queue, head, block_cnt);
- mutex_unlock(&bdev->mutex);
-
- virtio_pci__signal_vq(kvm, &bdev->vpci, queue - bdev->vqs);
+ virtio_blk_complete(req, block_cnt);
}

static void virtio_blk_do_io(struct kvm *kvm, struct virt_queue *vq, struct blk_dev *bdev)
{
while (virt_queue__available(vq)) {
- struct blk_dev_job *job = &bdev->jobs[bdev->job_idx++ % VIRTIO_BLK_QUEUE_SIZE];
+ struct blk_dev_req *req = virtio_blk_req_pop(bdev);

- *job = (struct blk_dev_job) {
- .vq = vq,
- .bdev = bdev,
+ *req = (struct blk_dev_req) {
+ .vq = vq,
+ .bdev = bdev,
+ .kvm = kvm,
};
- job->head = virt_queue__get_iov(vq, job->iov, &job->out, &job->in, kvm);
+ req->head = virt_queue__get_iov(vq, req->iov, &req->out, &req->in, kvm);

- thread_pool__init_job(&job->job_id, kvm, virtio_blk_do_io_request, job);
- thread_pool__do_job(&job->job_id);
+ virtio_blk_do_io_request(kvm, req);
}
}

@@ -191,6 +224,7 @@ static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
void virtio_blk__init(struct kvm *kvm, struct disk_image *disk)
{
struct blk_dev *bdev;
+ size_t i;

if (!disk)
return;
@@ -201,6 +235,7 @@ void virtio_blk__init(struct kvm *kvm, struct disk_image *disk)

*bdev = (struct blk_dev) {
.mutex = PTHREAD_MUTEX_INITIALIZER,
+ .req_mutex = PTHREAD_MUTEX_INITIALIZER,
.disk = disk,
.blk_config = (struct virtio_blk_config) {
.capacity = disk->size / SECTOR_SIZE,
@@ -222,6 +257,10 @@ void virtio_blk__init(struct kvm *kvm, struct disk_image *disk)

list_add_tail(&bdev->list, &bdevs);

+ INIT_LIST_HEAD(&bdev->req_list);
+ for (i = 0; i < ARRAY_SIZE(bdev->reqs); i++)
+ list_add(&bdev->reqs[i].list, &bdev->req_list);
+
if (compat_id != -1)
compat_id = compat__add_message("virtio-blk device was not detected",
"While you have requested a virtio-blk device, "
--
1.7.7.1