uint32_t data_vdi_id[MAX_DATA_OBJS];
} SheepdogInode;
+#define SD_INODE_HEADER_SIZE offsetof(SheepdogInode, data_vdi_id)
+
/*
* 64 bit FNV-1a non-zero initial basis
*/
unsigned int data_len;
uint8_t flags;
uint32_t id;
+ bool create;
QLIST_ENTRY(AIOReq) aio_siblings;
} AIOReq;
typedef struct BDRVSheepdogState {
BlockDriverState *bs;
+ AioContext *aio_context;
SheepdogInode inode;
static inline AIOReq *alloc_aio_req(BDRVSheepdogState *s, SheepdogAIOCB *acb,
uint64_t oid, unsigned int data_len,
- uint64_t offset, uint8_t flags,
+ uint64_t offset, uint8_t flags, bool create,
uint64_t base_oid, unsigned int iov_offset)
{
AIOReq *aio_req;
aio_req->data_len = data_len;
aio_req->flags = flags;
aio_req->id = s->aioreq_seq_num++;
+ aio_req->create = create;
acb->nr_pending++;
return aio_req;
sd_finish_aiocb(acb);
return;
}
- qemu_aio_wait();
+ aio_poll(s->aio_context, true);
}
}
typedef struct SheepdogReqCo {
int sockfd;
+ AioContext *aio_context;
SheepdogReq *hdr;
void *data;
unsigned int *wlen;
unsigned int *rlen = srco->rlen;
co = qemu_coroutine_self();
- qemu_aio_set_fd_handler(sockfd, NULL, restart_co_req, co);
+ aio_set_fd_handler(srco->aio_context, sockfd, NULL, restart_co_req, co);
ret = send_co_req(sockfd, hdr, data, wlen);
if (ret < 0) {
goto out;
}
- qemu_aio_set_fd_handler(sockfd, restart_co_req, NULL, co);
+ aio_set_fd_handler(srco->aio_context, sockfd, restart_co_req, NULL, co);
ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr));
if (ret != sizeof(*hdr)) {
out:
/* there is at most one request for this sockfd, so it is safe to
* set each handler to NULL. */
- qemu_aio_set_fd_handler(sockfd, NULL, NULL, NULL);
+ aio_set_fd_handler(srco->aio_context, sockfd, NULL, NULL, NULL);
srco->ret = ret;
srco->finished = true;
}
-static int do_req(int sockfd, SheepdogReq *hdr, void *data,
- unsigned int *wlen, unsigned int *rlen)
+static int do_req(int sockfd, AioContext *aio_context, SheepdogReq *hdr,
+ void *data, unsigned int *wlen, unsigned int *rlen)
{
Coroutine *co;
SheepdogReqCo srco = {
.sockfd = sockfd,
+ .aio_context = aio_context,
.hdr = hdr,
.data = data,
.wlen = wlen,
co = qemu_coroutine_create(do_co_req);
qemu_coroutine_enter(co, &srco);
while (!srco.finished) {
- qemu_aio_wait();
+ aio_poll(aio_context, true);
}
}
}
static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
- struct iovec *iov, int niov, bool create,
- enum AIOCBState aiocb_type);
+ struct iovec *iov, int niov,
+ enum AIOCBState aiocb_type);
static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req);
static int reload_inode(BDRVSheepdogState *s, uint32_t snapid, const char *tag);
static int get_sheep_fd(BDRVSheepdogState *s, Error **errp);
/* move aio_req from pending list to inflight one */
QLIST_REMOVE(aio_req, aio_siblings);
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
- add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, false,
+ add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
acb->aiocb_type);
}
}
BDRVSheepdogState *s = opaque;
AIOReq *aio_req, *next;
- qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL);
+ aio_set_fd_handler(s->aio_context, s->fd, NULL, NULL, NULL);
close(s->fd);
s->fd = -1;
}
idx = data_oid_to_idx(aio_req->oid);
- if (s->inode.data_vdi_id[idx] != s->inode.vdi_id) {
+ if (aio_req->create) {
/*
* If the object is newly created one, we need to update
* the vdi object (metadata object). min_dirty_data_idx
return fd;
}
- qemu_aio_set_fd_handler(fd, co_read_response, NULL, s);
+ aio_set_fd_handler(s->aio_context, fd, co_read_response, NULL, s);
return fd;
}
hdr.snapid = snapid;
hdr.flags = SD_FLAG_CMD_WRITE;
- ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
+ ret = do_req(fd, s->aio_context, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
if (ret) {
error_setg_errno(errp, -ret, "cannot get vdi info");
goto out;
}
static void coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
- struct iovec *iov, int niov, bool create,
- enum AIOCBState aiocb_type)
+ struct iovec *iov, int niov,
+ enum AIOCBState aiocb_type)
{
int nr_copies = s->inode.nr_copies;
SheepdogObjReq hdr;
uint64_t offset = aio_req->offset;
uint8_t flags = aio_req->flags;
uint64_t old_oid = aio_req->base_oid;
+ bool create = aio_req->create;
if (!nr_copies) {
error_report("bug");
qemu_co_mutex_lock(&s->lock);
s->co_send = qemu_coroutine_self();
- qemu_aio_set_fd_handler(s->fd, co_read_response, co_write_request, s);
+ aio_set_fd_handler(s->aio_context, s->fd,
+ co_read_response, co_write_request, s);
socket_set_cork(s->fd, 1);
/* send a header */
}
out:
socket_set_cork(s->fd, 0);
- qemu_aio_set_fd_handler(s->fd, co_read_response, NULL, s);
+ aio_set_fd_handler(s->aio_context, s->fd, co_read_response, NULL, s);
s->co_send = NULL;
qemu_co_mutex_unlock(&s->lock);
}
-static int read_write_object(int fd, char *buf, uint64_t oid, uint8_t copies,
+static int read_write_object(int fd, AioContext *aio_context, char *buf,
+ uint64_t oid, uint8_t copies,
unsigned int datalen, uint64_t offset,
bool write, bool create, uint32_t cache_flags)
{
hdr.offset = offset;
hdr.copies = copies;
- ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
+ ret = do_req(fd, aio_context, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
if (ret) {
error_report("failed to send a request to the sheep");
return ret;
}
}
-static int read_object(int fd, char *buf, uint64_t oid, uint8_t copies,
+static int read_object(int fd, AioContext *aio_context, char *buf,
+ uint64_t oid, uint8_t copies,
unsigned int datalen, uint64_t offset,
uint32_t cache_flags)
{
- return read_write_object(fd, buf, oid, copies, datalen, offset, false,
+ return read_write_object(fd, aio_context, buf, oid, copies,
+ datalen, offset, false,
false, cache_flags);
}
-static int write_object(int fd, char *buf, uint64_t oid, uint8_t copies,
+static int write_object(int fd, AioContext *aio_context, char *buf,
+ uint64_t oid, uint8_t copies,
unsigned int datalen, uint64_t offset, bool create,
uint32_t cache_flags)
{
- return read_write_object(fd, buf, oid, copies, datalen, offset, true,
+ return read_write_object(fd, aio_context, buf, oid, copies,
+ datalen, offset, true,
create, cache_flags);
}
return -EIO;
}
- inode = g_malloc(sizeof(s->inode));
+ inode = g_malloc(SD_INODE_HEADER_SIZE);
ret = find_vdi_name(s, s->name, snapid, tag, &vid, false, &local_err);
if (ret) {
goto out;
}
- ret = read_object(fd, (char *)inode, vid_to_vdi_oid(vid),
- s->inode.nr_copies, sizeof(*inode), 0, s->cache_flags);
+ ret = read_object(fd, s->aio_context, (char *)inode, vid_to_vdi_oid(vid),
+ s->inode.nr_copies, SD_INODE_HEADER_SIZE, 0,
+ s->cache_flags);
if (ret < 0) {
goto out;
}
if (inode->vdi_id != s->inode.vdi_id) {
- memcpy(&s->inode, inode, sizeof(s->inode));
+ memcpy(&s->inode, inode, SD_INODE_HEADER_SIZE);
}
out:
DPRINTF("simultaneous create to %" PRIx64 "\n", aio_req->oid);
aio_req->flags = 0;
aio_req->base_oid = 0;
+ aio_req->create = false;
QLIST_REMOVE(aio_req, aio_siblings);
QLIST_INSERT_HEAD(&s->pending_aio_head, aio_req, aio_siblings);
return true;
static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req)
{
SheepdogAIOCB *acb = aio_req->aiocb;
- bool create = false;
+
+ aio_req->create = false;
/* check whether this request becomes a CoW one */
if (acb->aiocb_type == AIOCB_WRITE_UDATA && is_data_obj(aio_req->oid)) {
aio_req->base_oid = vid_to_data_oid(s->inode.data_vdi_id[idx], idx);
aio_req->flags |= SD_FLAG_CMD_COW;
}
- create = true;
+ aio_req->create = true;
}
out:
if (is_data_obj(aio_req->oid)) {
- add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, create,
+ add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
acb->aiocb_type);
} else {
struct iovec iov;
iov.iov_base = &s->inode;
iov.iov_len = sizeof(s->inode);
- add_aio_request(s, aio_req, &iov, 1, false, AIOCB_WRITE_UDATA);
+ add_aio_request(s, aio_req, &iov, 1, AIOCB_WRITE_UDATA);
}
}
+static void sd_detach_aio_context(BlockDriverState *bs)
+{
+ BDRVSheepdogState *s = bs->opaque;
+
+ aio_set_fd_handler(s->aio_context, s->fd, NULL, NULL, NULL);
+}
+
+static void sd_attach_aio_context(BlockDriverState *bs,
+ AioContext *new_context)
+{
+ BDRVSheepdogState *s = bs->opaque;
+
+ s->aio_context = new_context;
+ aio_set_fd_handler(new_context, s->fd, co_read_response, NULL, s);
+}
+
/* TODO Convert to fine grained options */
static QemuOptsList runtime_opts = {
.name = "sheepdog",
const char *filename;
s->bs = bs;
+ s->aio_context = bdrv_get_aio_context(bs);
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, options, &local_err);
}
buf = g_malloc(SD_INODE_SIZE);
- ret = read_object(fd, buf, vid_to_vdi_oid(vid), 0, SD_INODE_SIZE, 0,
- s->cache_flags);
+ ret = read_object(fd, s->aio_context, buf, vid_to_vdi_oid(vid),
+ 0, SD_INODE_SIZE, 0, s->cache_flags);
closesocket(fd);
g_free(buf);
return 0;
out:
- qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL);
+ aio_set_fd_handler(bdrv_get_aio_context(bs), s->fd, NULL, NULL, NULL);
if (s->fd >= 0) {
closesocket(s->fd);
}
hdr.copy_policy = s->inode.copy_policy;
hdr.copies = s->inode.nr_copies;
- ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
+ ret = do_req(fd, s->aio_context, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
closesocket(fd);
return 0;
}
-static int sd_create(const char *filename, QEMUOptionParameter *options,
+static int sd_create(const char *filename, QemuOpts *opts,
Error **errp)
{
int ret = 0;
uint32_t vid = 0;
char *backing_file = NULL;
+ char *buf = NULL;
BDRVSheepdogState *s;
char tag[SD_MAX_VDI_TAG_LEN];
uint32_t snapid;
goto out;
}
- while (options && options->name) {
- if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
- s->inode.vdi_size = options->value.n;
- } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
- backing_file = options->value.s;
- } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
- if (!options->value.s || !strcmp(options->value.s, "off")) {
- prealloc = false;
- } else if (!strcmp(options->value.s, "full")) {
- prealloc = true;
- } else {
- error_setg(errp, "Invalid preallocation mode: '%s'",
- options->value.s);
- ret = -EINVAL;
- goto out;
- }
- } else if (!strcmp(options->name, BLOCK_OPT_REDUNDANCY)) {
- if (options->value.s) {
- ret = parse_redundancy(s, options->value.s);
- if (ret < 0) {
- error_setg(errp, "Invalid redundancy mode: '%s'",
- options->value.s);
- goto out;
- }
- }
+ s->inode.vdi_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
+ backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
+ buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
+ if (!buf || !strcmp(buf, "off")) {
+ prealloc = false;
+ } else if (!strcmp(buf, "full")) {
+ prealloc = true;
+ } else {
+ error_setg(errp, "Invalid preallocation mode: '%s'", buf);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ g_free(buf);
+ buf = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY);
+ if (buf) {
+ ret = parse_redundancy(s, buf);
+ if (ret < 0) {
+ error_setg(errp, "Invalid redundancy mode: '%s'", buf);
+ goto out;
}
- options++;
}
if (s->inode.vdi_size > SD_MAX_VDI_SIZE) {
bdrv_unref(bs);
}
+ s->aio_context = qemu_get_aio_context();
ret = do_sd_create(s, &vid, 0, errp);
if (ret) {
goto out;
ret = sd_prealloc(filename, errp);
}
out:
+ g_free(backing_file);
+ g_free(buf);
g_free(s);
return ret;
}
hdr.data_length = wlen;
hdr.flags = SD_FLAG_CMD_WRITE;
- ret = do_req(fd, (SheepdogReq *)&hdr, s->name, &wlen, &rlen);
+ ret = do_req(fd, s->aio_context, (SheepdogReq *)&hdr,
+ s->name, &wlen, &rlen);
closesocket(fd);
error_report("%s, %s", sd_strerror(rsp->result), s->name);
}
- qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL);
+ aio_set_fd_handler(bdrv_get_aio_context(bs), s->fd, NULL, NULL, NULL);
closesocket(s->fd);
g_free(s->host_spec);
}
/* we don't need to update entire object */
datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id);
s->inode.vdi_size = offset;
- ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
- s->inode.nr_copies, datalen, 0, false, s->cache_flags);
+ ret = write_object(fd, s->aio_context, (char *)&s->inode,
+ vid_to_vdi_oid(s->inode.vdi_id), s->inode.nr_copies,
+ datalen, 0, false, s->cache_flags);
close(fd);
if (ret < 0) {
iov.iov_base = &s->inode;
iov.iov_len = sizeof(s->inode);
aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id),
- data_len, offset, 0, 0, offset);
+ data_len, offset, 0, false, 0, offset);
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
- add_aio_request(s, aio_req, &iov, 1, false, AIOCB_WRITE_UDATA);
+ add_aio_request(s, aio_req, &iov, 1, AIOCB_WRITE_UDATA);
acb->aio_done_func = sd_finish_aiocb;
acb->aiocb_type = AIOCB_WRITE_UDATA;
return false;
}
- ret = do_req(fd, (SheepdogReq *)&hdr, s->name, &wlen, &rlen);
+ ret = do_req(fd, s->aio_context, (SheepdogReq *)&hdr,
+ s->name, &wlen, &rlen);
closesocket(fd);
if (ret) {
return false;
goto out;
}
- ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies,
- SD_INODE_SIZE, 0, s->cache_flags);
+ ret = read_object(fd, s->aio_context, buf, vid_to_vdi_oid(vid),
+ s->inode.nr_copies, SD_INODE_SIZE, 0, s->cache_flags);
closesocket(fd);
DPRINTF("new oid %" PRIx64 "\n", oid);
}
- aio_req = alloc_aio_req(s, acb, oid, len, offset, flags, old_oid, done);
+ aio_req = alloc_aio_req(s, acb, oid, len, offset, flags, create,
+ old_oid, done);
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
if (create) {
}
}
- add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov, create,
+ add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
acb->aiocb_type);
done:
offset = 0;
acb->aio_done_func = sd_finish_aiocb;
aio_req = alloc_aio_req(s, acb, vid_to_vdi_oid(s->inode.vdi_id),
- 0, 0, 0, 0, 0);
+ 0, 0, 0, false, 0, 0);
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
- add_aio_request(s, aio_req, NULL, 0, false, acb->aiocb_type);
+ add_aio_request(s, aio_req, NULL, 0, acb->aiocb_type);
qemu_coroutine_yield();
return acb->ret;
strncpy(s->inode.tag, sn_info->name, sizeof(s->inode.tag));
/* we don't need to update entire object */
datalen = SD_INODE_SIZE - sizeof(s->inode.data_vdi_id);
+ inode = g_malloc(datalen);
/* refresh inode. */
fd = connect_to_sdog(s, &local_err);
goto cleanup;
}
- ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
- s->inode.nr_copies, datalen, 0, false, s->cache_flags);
+ ret = write_object(fd, s->aio_context, (char *)&s->inode,
+ vid_to_vdi_oid(s->inode.vdi_id), s->inode.nr_copies,
+ datalen, 0, false, s->cache_flags);
if (ret < 0) {
error_report("failed to write snapshot's inode.");
goto cleanup;
goto cleanup;
}
- inode = (SheepdogInode *)g_malloc(datalen);
-
- ret = read_object(fd, (char *)inode, vid_to_vdi_oid(new_vid),
- s->inode.nr_copies, datalen, 0, s->cache_flags);
+ ret = read_object(fd, s->aio_context, (char *)inode,
+ vid_to_vdi_oid(new_vid), s->inode.nr_copies, datalen, 0,
+ s->cache_flags);
if (ret < 0) {
error_report("failed to read new inode info. %s", strerror(errno));
s->inode.name, s->inode.snap_id, s->inode.vdi_id);
cleanup:
+ g_free(inode);
closesocket(fd);
return ret;
}
req.opcode = SD_OP_READ_VDIS;
req.data_length = max;
- ret = do_req(fd, (SheepdogReq *)&req, vdi_inuse, &wlen, &rlen);
+ ret = do_req(fd, s->aio_context, (SheepdogReq *)&req,
+ vdi_inuse, &wlen, &rlen);
closesocket(fd);
if (ret) {
}
/* we don't need to read entire object */
- ret = read_object(fd, (char *)&inode, vid_to_vdi_oid(vid),
+ ret = read_object(fd, s->aio_context, (char *)&inode,
+ vid_to_vdi_oid(vid),
0, SD_INODE_SIZE - sizeof(inode.data_vdi_id), 0,
s->cache_flags);
create = (offset == 0);
if (load) {
- ret = read_object(fd, (char *)data, vmstate_oid,
+ ret = read_object(fd, s->aio_context, (char *)data, vmstate_oid,
s->inode.nr_copies, data_len, offset,
s->cache_flags);
} else {
- ret = write_object(fd, (char *)data, vmstate_oid,
+ ret = write_object(fd, s->aio_context, (char *)data, vmstate_oid,
s->inode.nr_copies, data_len, offset, create,
s->cache_flags);
}
return size;
}
-static QEMUOptionParameter sd_create_options[] = {
- {
- .name = BLOCK_OPT_SIZE,
- .type = OPT_SIZE,
- .help = "Virtual disk size"
- },
- {
- .name = BLOCK_OPT_BACKING_FILE,
- .type = OPT_STRING,
- .help = "File name of a base image"
- },
- {
- .name = BLOCK_OPT_PREALLOC,
- .type = OPT_STRING,
- .help = "Preallocation mode (allowed values: off, full)"
- },
- {
- .name = BLOCK_OPT_REDUNDANCY,
- .type = OPT_STRING,
- .help = "Redundancy of the image"
- },
- { NULL }
+static QemuOptsList sd_create_opts = {
+ .name = "sheepdog-create-opts",
+ .head = QTAILQ_HEAD_INITIALIZER(sd_create_opts.head),
+ .desc = {
+ {
+ .name = BLOCK_OPT_SIZE,
+ .type = QEMU_OPT_SIZE,
+ .help = "Virtual disk size"
+ },
+ {
+ .name = BLOCK_OPT_BACKING_FILE,
+ .type = QEMU_OPT_STRING,
+ .help = "File name of a base image"
+ },
+ {
+ .name = BLOCK_OPT_PREALLOC,
+ .type = QEMU_OPT_STRING,
+ .help = "Preallocation mode (allowed values: off, full)"
+ },
+ {
+ .name = BLOCK_OPT_REDUNDANCY,
+ .type = QEMU_OPT_STRING,
+ .help = "Redundancy of the image"
+ },
+ { /* end of list */ }
+ }
};
static BlockDriver bdrv_sheepdog = {
.bdrv_save_vmstate = sd_save_vmstate,
.bdrv_load_vmstate = sd_load_vmstate,
- .create_options = sd_create_options,
+ .bdrv_detach_aio_context = sd_detach_aio_context,
+ .bdrv_attach_aio_context = sd_attach_aio_context,
+
+ .create_opts = &sd_create_opts,
};
static BlockDriver bdrv_sheepdog_tcp = {
.bdrv_save_vmstate = sd_save_vmstate,
.bdrv_load_vmstate = sd_load_vmstate,
- .create_options = sd_create_options,
+ .bdrv_detach_aio_context = sd_detach_aio_context,
+ .bdrv_attach_aio_context = sd_attach_aio_context,
+
+ .create_opts = &sd_create_opts,
};
static BlockDriver bdrv_sheepdog_unix = {
.bdrv_save_vmstate = sd_save_vmstate,
.bdrv_load_vmstate = sd_load_vmstate,
- .create_options = sd_create_options,
+ .bdrv_detach_aio_context = sd_detach_aio_context,
+ .bdrv_attach_aio_context = sd_attach_aio_context,
+
+ .create_opts = &sd_create_opts,
};
static void bdrv_sheepdog_init(void)