#include "qemu-error.h"
#include "qemu_socket.h"
#include "block_int.h"
+#include "bitops.h"
#define SD_PROTO_VER 0x01
return hval;
}
-static inline int is_data_obj_writeable(SheepdogInode *inode, unsigned int idx)
+static inline int is_data_obj_writable(SheepdogInode *inode, unsigned int idx)
{
return inode->vdi_id == inode->data_vdi_id[idx];
}
static int sd_schedule_bh(QEMUBHFunc *cb, SheepdogAIOCB *acb)
{
if (acb->bh) {
- error_report("bug: %d %d\n", acb->aiocb_type, acb->aiocb_type);
+ error_report("bug: %d %d", acb->aiocb_type, acb->aiocb_type);
return -EIO;
}
acb->bh = qemu_bh_new(cb, acb);
- if (!acb->bh) {
- error_report("oom: %d %d\n", acb->aiocb_type, acb->aiocb_type);
- return -EIO;
- }
-
qemu_bh_schedule(acb->bh);
-
return 0;
}
ret = getaddrinfo(addr, port, &hints, &res0);
if (ret) {
- error_report("unable to get address info %s, %s\n",
+ error_report("unable to get address info %s, %s",
addr, strerror(errno));
return -1;
}
goto success;
}
fd = -1;
- error_report("failed connect to %s:%s\n", addr, port);
+ error_report("failed connect to %s:%s", addr, port);
success:
freeaddrinfo(res0);
return fd;
if (errno == EINTR || errno == EAGAIN) {
goto again;
}
- error_report("failed to recv a rsp, %s\n", strerror(errno));
+ error_report("failed to recv a rsp, %s", strerror(errno));
return 1;
}
ret = do_writev(sockfd, iov, sizeof(*hdr) + *wlen, 0);
if (ret) {
- error_report("failed to send a req, %s\n", strerror(errno));
+ error_report("failed to send a req, %s", strerror(errno));
ret = -1;
}
ret = do_read(sockfd, hdr, sizeof(*hdr));
if (ret) {
- error_report("failed to get a rsp, %s\n", strerror(errno));
+ error_report("failed to get a rsp, %s", strerror(errno));
ret = -1;
goto out;
}
if (*rlen) {
ret = do_read(sockfd, data, *rlen);
if (ret) {
- error_report("failed to get the data, %s\n", strerror(errno));
+ error_report("failed to get the data, %s", strerror(errno));
ret = -1;
goto out;
}
ret = add_aio_request(s, aio_req, acb->qiov->iov,
acb->qiov->niov, 0, acb->aiocb_type);
if (ret < 0) {
- error_report("add_aio_request is failed\n");
+ error_report("add_aio_request is failed");
free_aio_req(s, aio_req);
if (QLIST_EMPTY(&acb->aioreq_head)) {
sd_finish_aiocb(acb);
/* read a header */
ret = do_read(fd, &rsp, sizeof(rsp));
if (ret) {
- error_report("failed to get the header, %s\n", strerror(errno));
+ error_report("failed to get the header, %s", strerror(errno));
return;
}
}
}
if (!aio_req) {
- error_report("cannot find aio_req %x\n", rsp.id);
+ error_report("cannot find aio_req %x", rsp.id);
return;
}
ret = do_readv(fd, acb->qiov->iov, rsp.data_length,
aio_req->iov_offset);
if (ret) {
- error_report("failed to get the data, %s\n", strerror(errno));
+ error_report("failed to get the data, %s", strerror(errno));
return;
}
break;
if (rsp.result != SD_RES_SUCCESS) {
acb->ret = -EIO;
- error_report("%s\n", sd_strerror(rsp.result));
+ error_report("%s", sd_strerror(rsp.result));
}
rest = free_aio_req(s, aio_req);
fd = connect_to_sdog(s->addr, s->port);
if (fd < 0) {
- error_report("%s\n", strerror(errno));
+ error_report("%s", strerror(errno));
return -1;
}
ret = set_nodelay(fd);
if (ret) {
- error_report("%s\n", strerror(errno));
+ error_report("%s", strerror(errno));
closesocket(fd);
return -1;
}
}
if (rsp->result != SD_RES_SUCCESS) {
- error_report("cannot get vdi info, %s, %s %d %s\n",
+ error_report("cannot get vdi info, %s, %s %d %s",
sd_strerror(rsp->result), filename, snapid, tag);
ret = -1;
goto out;
uint64_t old_oid = aio_req->base_oid;
if (!nr_copies) {
- error_report("bug\n");
+ error_report("bug");
}
memset(&hdr, 0, sizeof(hdr));
/* send a header */
ret = do_write(s->fd, &hdr, sizeof(hdr));
if (ret) {
- error_report("failed to send a req, %s\n", strerror(errno));
+ error_report("failed to send a req, %s", strerror(errno));
return -EIO;
}
if (wlen) {
ret = do_writev(s->fd, iov, wlen, aio_req->iov_offset);
if (ret) {
- error_report("failed to send a data, %s\n", strerror(errno));
+ error_report("failed to send a data, %s", strerror(errno));
return -EIO;
}
}
ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
if (ret) {
- error_report("failed to send a request to the sheep\n");
+ error_report("failed to send a request to the sheep");
return -1;
}
case SD_RES_SUCCESS:
return 0;
default:
- error_report("%s\n", sd_strerror(rsp->result));
+ error_report("%s", sd_strerror(rsp->result));
return -1;
}
}
fd = connect_to_sdog(s->addr, s->port);
if (fd < 0) {
- error_report("failed to connect\n");
+ error_report("failed to connect");
goto out;
}
}
if (rsp->result != SD_RES_SUCCESS) {
- error_report("%s, %s\n", sd_strerror(rsp->result), filename);
+ error_report("%s, %s", sd_strerror(rsp->result), filename);
return -EIO;
}
return 0;
}
+static int sd_prealloc(const char *filename)
+{
+ BlockDriverState *bs = NULL;
+ uint32_t idx, max_idx;
+ int64_t vdi_size;
+ void *buf = qemu_mallocz(SD_DATA_OBJ_SIZE);
+ int ret;
+
+ ret = bdrv_file_open(&bs, filename, BDRV_O_RDWR);
+ if (ret < 0) {
+ goto out;
+ }
+
+ vdi_size = bdrv_getlength(bs);
+ if (vdi_size < 0) {
+ ret = vdi_size;
+ goto out;
+ }
+ max_idx = DIV_ROUND_UP(vdi_size, SD_DATA_OBJ_SIZE);
+
+ for (idx = 0; idx < max_idx; idx++) {
+ /*
+ * The created image can be a cloned image, so we need to read
+ * a data from the source image.
+ */
+ ret = bdrv_pread(bs, idx * SD_DATA_OBJ_SIZE, buf, SD_DATA_OBJ_SIZE);
+ if (ret < 0) {
+ goto out;
+ }
+ ret = bdrv_pwrite(bs, idx * SD_DATA_OBJ_SIZE, buf, SD_DATA_OBJ_SIZE);
+ if (ret < 0) {
+ goto out;
+ }
+ }
+out:
+ if (bs) {
+ bdrv_delete(bs);
+ }
+ qemu_free(buf);
+
+ return ret;
+}
+
static int sd_create(const char *filename, QEMUOptionParameter *options)
{
int ret;
- uint32_t vid = 0;
+ uint32_t vid = 0, base_vid = 0;
int64_t vdi_size = 0;
char *backing_file = NULL;
+ BDRVSheepdogState s;
+ char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
+ uint32_t snapid;
+ int prealloc = 0;
+ const char *vdiname;
- strstart(filename, "sheepdog:", (const char **)&filename);
+ strstart(filename, "sheepdog:", &vdiname);
+
+ memset(&s, 0, sizeof(s));
+ memset(vdi, 0, sizeof(vdi));
+ memset(tag, 0, sizeof(tag));
+ if (parse_vdiname(&s, vdiname, vdi, &snapid, tag) < 0) {
+ error_report("invalid filename");
+ return -EINVAL;
+ }
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
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 = 0;
+ } else if (!strcmp(options->value.s, "full")) {
+ prealloc = 1;
+ } else {
+ error_report("Invalid preallocation mode: '%s'",
+ options->value.s);
+ return -EINVAL;
+ }
}
options++;
}
if (vdi_size > SD_MAX_VDI_SIZE) {
- error_report("too big image size\n");
+ error_report("too big image size");
return -EINVAL;
}
/* Currently, only Sheepdog backing image is supported. */
drv = bdrv_find_protocol(backing_file);
if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
- error_report("backing_file must be a sheepdog image\n");
+ error_report("backing_file must be a sheepdog image");
return -EINVAL;
}
s = bs->opaque;
if (!is_snapshot(&s->inode)) {
- error_report("cannot clone from a non snapshot vdi\n");
+ error_report("cannot clone from a non snapshot vdi");
bdrv_delete(bs);
return -EINVAL;
}
- vid = s->inode.vdi_id;
+ base_vid = s->inode.vdi_id;
bdrv_delete(bs);
}
- return do_sd_create((char *)filename, vdi_size, vid, NULL, 0, NULL, NULL);
+ ret = do_sd_create(vdi, vdi_size, base_vid, &vid, 0, s.addr, s.port);
+ if (!prealloc || ret) {
+ return ret;
+ }
+
+ return sd_prealloc(filename);
}
static void sd_close(BlockDriverState *bs)
if (!ret && rsp->result != SD_RES_SUCCESS &&
rsp->result != SD_RES_VDI_NOT_LOCKED) {
- error_report("%s, %s\n", sd_strerror(rsp->result), s->name);
+ error_report("%s, %s", sd_strerror(rsp->result), s->name);
}
qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL);
unsigned int datalen;
if (offset < s->inode.vdi_size) {
- error_report("shrinking is not supported\n");
+ error_report("shrinking is not supported");
return -EINVAL;
} else if (offset > SD_MAX_VDI_SIZE) {
- error_report("too big image size\n");
+ error_report("too big image size");
return -EINVAL;
}
close(fd);
if (ret < 0) {
- error_report("failed to update an inode.\n");
+ error_report("failed to update an inode.");
return -EIO;
}
fd = connect_to_sdog(s->addr, s->port);
if (fd < 0) {
- error_report("failed to connect\n");
+ error_report("failed to connect");
goto out;
}
create = 1;
} else if (acb->aiocb_type == AIOCB_WRITE_UDATA
- && !is_data_obj_writeable(inode, idx)) {
+ && !is_data_obj_writable(inode, idx)) {
/* Copy-On-Write */
create = 1;
old_oid = oid;
ret = add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
create, acb->aiocb_type);
if (ret < 0) {
- error_report("add_aio_request is failed\n");
+ error_report("add_aio_request is failed");
free_aio_req(s, aio_req);
acb->ret = -EIO;
goto out;
if (s->is_snapshot) {
error_report("You can't create a snapshot of a snapshot VDI, "
- "%s (%" PRIu32 ").\n", s->name, s->inode.vdi_id);
+ "%s (%" PRIu32 ").", s->name, s->inode.vdi_id);
return -EINVAL;
}
ret = write_object(fd, (char *)&s->inode, vid_to_vdi_oid(s->inode.vdi_id),
s->inode.nr_copies, datalen, 0, 0);
if (ret < 0) {
- error_report("failed to write snapshot's inode.\n");
+ error_report("failed to write snapshot's inode.");
ret = -EIO;
goto cleanup;
}
ret = do_sd_create(s->name, s->inode.vdi_size, s->inode.vdi_id, &new_vid, 1,
s->addr, s->port);
if (ret < 0) {
- error_report("failed to create inode for snapshot. %s\n",
+ error_report("failed to create inode for snapshot. %s",
strerror(errno));
ret = -EIO;
goto cleanup;
s->inode.nr_copies, datalen, 0);
if (ret < 0) {
- error_report("failed to read new inode info. %s\n", strerror(errno));
+ error_report("failed to read new inode info. %s", strerror(errno));
ret = -EIO;
goto cleanup;
}
ret = find_vdi_name(s, vdi, snapid, tag, &vid, 1);
if (ret) {
- error_report("Failed to find_vdi_name\n");
+ error_report("Failed to find_vdi_name");
ret = -ENOENT;
goto out;
}
fd = connect_to_sdog(s->addr, s->port);
if (fd < 0) {
- error_report("failed to connect\n");
+ error_report("failed to connect");
goto out;
}
memcpy(&s->inode, buf, sizeof(s->inode));
if (!s->inode.vm_state_size) {
- error_report("Invalid snapshot\n");
+ error_report("Invalid snapshot");
ret = -ENOENT;
goto out;
}
qemu_free(buf);
qemu_free(old_s);
- error_report("failed to open. recover old bdrv_sd_state.\n");
+ error_report("failed to open. recover old bdrv_sd_state.");
return ret;
}
return 0;
}
-#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
-#define BITS_PER_BYTE 8
-#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
-#define DECLARE_BITMAP(name,bits) \
- unsigned long name[BITS_TO_LONGS(bits)]
-
-#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long))
-
-static inline int test_bit(unsigned int nr, const unsigned long *addr)
-{
- return ((1UL << (nr % BITS_PER_LONG)) &
- (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
-}
-
static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
{
BDRVSheepdogState *s = bs->opaque;
fd = connect_to_sdog(s->addr, s->port);
if (fd < 0) {
- error_report("failed to connect\n");
+ error_report("failed to connect");
goto out;
}
}
if (ret < 0) {
- error_report("failed to save vmstate %s\n", strerror(errno));
+ error_report("failed to save vmstate %s", strerror(errno));
ret = -EIO;
goto cleanup;
}
.type = OPT_STRING,
.help = "File name of a base image"
},
+ {
+ .name = BLOCK_OPT_PREALLOC,
+ .type = OPT_STRING,
+ .help = "Preallocation mode (allowed values: off, full)"
+ },
{ NULL }
};