summaryrefslogtreecommitdiff
path: root/block/sheepdog.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-03-12 10:08:09 +0000
committerPeter Maydell <peter.maydell@linaro.org>2018-03-12 10:08:09 +0000
commit12c06d6f967a63515399b9e1f6a40f5ce871a8b7 (patch)
treed5c2f32efcb3b9622c042c94250d0fc3fdb56167 /block/sheepdog.c
parent20f59d120053a26521fa0177ea07f947bc8bfff0 (diff)
parenta1be5921e35dcf84ce9e3c9a5c3029cea530a60b (diff)
downloadqemu-12c06d6f967a63515399b9e1f6a40f5ce871a8b7.zip
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches # gpg: Signature made Fri 09 Mar 2018 15:09:20 GMT # gpg: using RSA key 7F09B272C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: (56 commits) qemu-iotests: fix 203 migration completion race iotests: Tweak 030 in order to trigger a race condition with parallel jobs iotests: Skip test for ENOMEM error iotests: Mark all tests executable iotests: Test creating overlay when guest running qemu-iotests: Test ssh image creation over QMP qemu-iotests: Test qcow2 over file image creation with QMP block: Fail bdrv_truncate() with negative size file-posix: Fix no-op bdrv_truncate() with falloc preallocation ssh: Support .bdrv_co_create ssh: Pass BlockdevOptionsSsh to connect_to_ssh() ssh: QAPIfy host-key-check option ssh: Use QAPI BlockdevOptionsSsh object sheepdog: Support .bdrv_co_create sheepdog: QAPIfy "redundancy" create option nfs: Support .bdrv_co_create nfs: Use QAPI options in nfs_client_open() rbd: Use qemu_rbd_connect() in qemu_rbd_do_create() rbd: Assign s->snap/image_name in qemu_rbd_open() rbd: Support .bdrv_co_create ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'block/sheepdog.c')
-rw-r--r--block/sheepdog.c321
1 files changed, 228 insertions, 93 deletions
diff --git a/block/sheepdog.c b/block/sheepdog.c
index d8c10b7cac..8680b2926f 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -15,8 +15,10 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qapi/qapi-visit-sockets.h"
+#include "qapi/qapi-visit-block-core.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qobject-input-visitor.h"
+#include "qapi/qobject-output-visitor.h"
#include "qemu/uri.h"
#include "qemu/error-report.h"
#include "qemu/option.h"
@@ -533,23 +535,6 @@ static void sd_aio_setup(SheepdogAIOCB *acb, BDRVSheepdogState *s,
qemu_co_mutex_unlock(&s->queue_lock);
}
-static SocketAddress *sd_socket_address(const char *path,
- const char *host, const char *port)
-{
- SocketAddress *addr = g_new0(SocketAddress, 1);
-
- if (path) {
- addr->type = SOCKET_ADDRESS_TYPE_UNIX;
- addr->u.q_unix.path = g_strdup(path);
- } else {
- addr->type = SOCKET_ADDRESS_TYPE_INET;
- addr->u.inet.host = g_strdup(host ?: SD_DEFAULT_ADDR);
- addr->u.inet.port = g_strdup(port ?: stringify(SD_DEFAULT_PORT));
- }
-
- return addr;
-}
-
static SocketAddress *sd_server_config(QDict *options, Error **errp)
{
QDict *server = NULL;
@@ -1882,6 +1867,86 @@ out_with_err_set:
return ret;
}
+static int sd_create_prealloc(BlockdevOptionsSheepdog *location, int64_t size,
+ Error **errp)
+{
+ BlockDriverState *bs;
+ Visitor *v;
+ QObject *obj = NULL;
+ QDict *qdict;
+ Error *local_err = NULL;
+ int ret;
+
+ v = qobject_output_visitor_new(&obj);
+ visit_type_BlockdevOptionsSheepdog(v, NULL, &location, &local_err);
+ visit_free(v);
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ qobject_decref(obj);
+ return -EINVAL;
+ }
+
+ qdict = qobject_to_qdict(obj);
+ qdict_flatten(qdict);
+
+ qdict_put_str(qdict, "driver", "sheepdog");
+
+ bs = bdrv_open(NULL, NULL, qdict, BDRV_O_PROTOCOL | BDRV_O_RDWR, errp);
+ if (bs == NULL) {
+ ret = -EIO;
+ goto fail;
+ }
+
+ ret = sd_prealloc(bs, 0, size, errp);
+fail:
+ bdrv_unref(bs);
+ QDECREF(qdict);
+ return ret;
+}
+
+static int parse_redundancy(BDRVSheepdogState *s, SheepdogRedundancy *opt)
+{
+ struct SheepdogInode *inode = &s->inode;
+
+ switch (opt->type) {
+ case SHEEPDOG_REDUNDANCY_TYPE_FULL:
+ if (opt->u.full.copies > SD_MAX_COPIES || opt->u.full.copies < 1) {
+ return -EINVAL;
+ }
+ inode->copy_policy = 0;
+ inode->nr_copies = opt->u.full.copies;
+ return 0;
+
+ case SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED:
+ {
+ int64_t copy = opt->u.erasure_coded.data_strips;
+ int64_t parity = opt->u.erasure_coded.parity_strips;
+
+ if (copy != 2 && copy != 4 && copy != 8 && copy != 16) {
+ return -EINVAL;
+ }
+
+ if (parity >= SD_EC_MAX_STRIP || parity < 1) {
+ return -EINVAL;
+ }
+
+ /*
+ * 4 bits for parity and 4 bits for data.
+ * We have to compress upper data bits because it can't represent 16
+ */
+ inode->copy_policy = ((copy / 2) << 4) + parity;
+ inode->nr_copies = copy + parity;
+ return 0;
+ }
+
+ default:
+ g_assert_not_reached();
+ }
+
+ return -EINVAL;
+}
+
/*
* Sheepdog support two kinds of redundancy, full replication and erasure
* coding.
@@ -1892,60 +1957,61 @@ out_with_err_set:
* # create a erasure coded vdi with x data strips and y parity strips
* -o redundancy=x:y (x must be one of {2,4,8,16} and 1 <= y < SD_EC_MAX_STRIP)
*/
-static int parse_redundancy(BDRVSheepdogState *s, const char *opt)
+static SheepdogRedundancy *parse_redundancy_str(const char *opt)
{
- struct SheepdogInode *inode = &s->inode;
+ SheepdogRedundancy *redundancy;
const char *n1, *n2;
long copy, parity;
char p[10];
+ int ret;
pstrcpy(p, sizeof(p), opt);
n1 = strtok(p, ":");
n2 = strtok(NULL, ":");
if (!n1) {
- return -EINVAL;
+ return NULL;
}
- copy = strtol(n1, NULL, 10);
- /* FIXME fix error checking by switching to qemu_strtol() */
- if (copy > SD_MAX_COPIES || copy < 1) {
- return -EINVAL;
- }
- if (!n2) {
- inode->copy_policy = 0;
- inode->nr_copies = copy;
- return 0;
+ ret = qemu_strtol(n1, NULL, 10, &copy);
+ if (ret < 0) {
+ return NULL;
}
- if (copy != 2 && copy != 4 && copy != 8 && copy != 16) {
- return -EINVAL;
- }
+ redundancy = g_new0(SheepdogRedundancy, 1);
+ if (!n2) {
+ *redundancy = (SheepdogRedundancy) {
+ .type = SHEEPDOG_REDUNDANCY_TYPE_FULL,
+ .u.full.copies = copy,
+ };
+ } else {
+ ret = qemu_strtol(n2, NULL, 10, &parity);
+ if (ret < 0) {
+ return NULL;
+ }
- parity = strtol(n2, NULL, 10);
- /* FIXME fix error checking by switching to qemu_strtol() */
- if (parity >= SD_EC_MAX_STRIP || parity < 1) {
- return -EINVAL;
+ *redundancy = (SheepdogRedundancy) {
+ .type = SHEEPDOG_REDUNDANCY_TYPE_ERASURE_CODED,
+ .u.erasure_coded = {
+ .data_strips = copy,
+ .parity_strips = parity,
+ },
+ };
}
- /*
- * 4 bits for parity and 4 bits for data.
- * We have to compress upper data bits because it can't represent 16
- */
- inode->copy_policy = ((copy / 2) << 4) + parity;
- inode->nr_copies = copy + parity;
-
- return 0;
+ return redundancy;
}
-static int parse_block_size_shift(BDRVSheepdogState *s, QemuOpts *opt)
+static int parse_block_size_shift(BDRVSheepdogState *s,
+ BlockdevCreateOptionsSheepdog *opts)
{
struct SheepdogInode *inode = &s->inode;
uint64_t object_size;
int obj_order;
- object_size = qemu_opt_get_size_del(opt, BLOCK_OPT_OBJECT_SIZE, 0);
- if (object_size) {
+ if (opts->has_object_size) {
+ object_size = opts->object_size;
+
if ((object_size - 1) & object_size) { /* not a power of 2? */
return -EINVAL;
}
@@ -1959,57 +2025,55 @@ static int parse_block_size_shift(BDRVSheepdogState *s, QemuOpts *opt)
return 0;
}
-static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
- Error **errp)
+static int sd_co_create(BlockdevCreateOptions *options, Error **errp)
{
- Error *err = NULL;
+ BlockdevCreateOptionsSheepdog *opts = &options->u.sheepdog;
int ret = 0;
uint32_t vid = 0;
char *backing_file = NULL;
char *buf = NULL;
BDRVSheepdogState *s;
- SheepdogConfig cfg;
uint64_t max_vdi_size;
bool prealloc = false;
+ assert(options->driver == BLOCKDEV_DRIVER_SHEEPDOG);
+
s = g_new0(BDRVSheepdogState, 1);
- if (strstr(filename, "://")) {
- sd_parse_uri(&cfg, filename, &err);
- } else {
- parse_vdiname(&cfg, filename, &err);
- }
- if (err) {
- error_propagate(errp, err);
+ /* Steal SocketAddress from QAPI, set NULL to prevent double free */
+ s->addr = opts->location->server;
+ opts->location->server = NULL;
+
+ if (strlen(opts->location->vdi) >= sizeof(s->name)) {
+ error_setg(errp, "'vdi' string too long");
+ ret = -EINVAL;
goto out;
}
+ pstrcpy(s->name, sizeof(s->name), opts->location->vdi);
- buf = cfg.port ? g_strdup_printf("%d", cfg.port) : NULL;
- s->addr = sd_socket_address(cfg.path, cfg.host, buf);
- g_free(buf);
- strcpy(s->name, cfg.vdi);
- sd_config_done(&cfg);
+ s->inode.vdi_size = opts->size;
+ backing_file = opts->backing_file;
- s->inode.vdi_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
- BDRV_SECTOR_SIZE);
- 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")) {
+ if (!opts->has_preallocation) {
+ opts->preallocation = PREALLOC_MODE_OFF;
+ }
+ switch (opts->preallocation) {
+ case PREALLOC_MODE_OFF:
prealloc = false;
- } else if (!strcmp(buf, "full")) {
+ break;
+ case PREALLOC_MODE_FULL:
prealloc = true;
- } else {
- error_setg(errp, "Invalid preallocation mode: '%s'", buf);
+ break;
+ default:
+ error_setg(errp, "Preallocation mode not supported for Sheepdog");
ret = -EINVAL;
goto out;
}
- g_free(buf);
- buf = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY);
- if (buf) {
- ret = parse_redundancy(s, buf);
+ if (opts->has_redundancy) {
+ ret = parse_redundancy(s, opts->redundancy);
if (ret < 0) {
- error_setg(errp, "Invalid redundancy mode: '%s'", buf);
+ error_setg(errp, "Invalid redundancy mode");
goto out;
}
}
@@ -2021,20 +2085,20 @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
goto out;
}
- if (backing_file) {
+ if (opts->has_backing_file) {
BlockBackend *blk;
BDRVSheepdogState *base;
BlockDriver *drv;
/* Currently, only Sheepdog backing image is supported. */
- drv = bdrv_find_protocol(backing_file, true, NULL);
+ drv = bdrv_find_protocol(opts->backing_file, true, NULL);
if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
error_setg(errp, "backing_file must be a sheepdog image");
ret = -EINVAL;
goto out;
}
- blk = blk_new_open(backing_file, NULL, NULL,
+ blk = blk_new_open(opts->backing_file, NULL, NULL,
BDRV_O_PROTOCOL, errp);
if (blk == NULL) {
ret = -EIO;
@@ -2102,28 +2166,96 @@ static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
}
if (prealloc) {
- BlockDriverState *bs;
- QDict *opts;
-
- opts = qdict_new();
- qdict_put_str(opts, "driver", "sheepdog");
- bs = bdrv_open(filename, NULL, opts, BDRV_O_PROTOCOL | BDRV_O_RDWR,
- errp);
- if (!bs) {
- goto out;
- }
-
- ret = sd_prealloc(bs, 0, s->inode.vdi_size, errp);
-
- bdrv_unref(bs);
+ ret = sd_create_prealloc(opts->location, opts->size, errp);
}
out:
g_free(backing_file);
g_free(buf);
+ g_free(s->addr);
g_free(s);
return ret;
}
+static int coroutine_fn sd_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
+{
+ BlockdevCreateOptions *create_options = NULL;
+ QDict *qdict, *location_qdict;
+ QObject *crumpled;
+ Visitor *v;
+ const char *redundancy;
+ Error *local_err = NULL;
+ int ret;
+
+ redundancy = qemu_opt_get_del(opts, BLOCK_OPT_REDUNDANCY);
+
+ qdict = qemu_opts_to_qdict(opts, NULL);
+ qdict_put_str(qdict, "driver", "sheepdog");
+
+ location_qdict = qdict_new();
+ qdict_put(qdict, "location", location_qdict);
+
+ sd_parse_filename(filename, location_qdict, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ qdict_flatten(qdict);
+
+ /* Change legacy command line options into QMP ones */
+ static const QDictRenames opt_renames[] = {
+ { BLOCK_OPT_BACKING_FILE, "backing-file" },
+ { BLOCK_OPT_OBJECT_SIZE, "object-size" },
+ { NULL, NULL },
+ };
+
+ if (!qdict_rename_keys(qdict, opt_renames, errp)) {
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ /* Get the QAPI object */
+ crumpled = qdict_crumple(qdict, errp);
+ if (crumpled == NULL) {
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ v = qobject_input_visitor_new_keyval(crumpled);
+ visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
+ visit_free(v);
+ qobject_decref(crumpled);
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ assert(create_options->driver == BLOCKDEV_DRIVER_SHEEPDOG);
+ create_options->u.sheepdog.size =
+ ROUND_UP(create_options->u.sheepdog.size, BDRV_SECTOR_SIZE);
+
+ if (redundancy) {
+ create_options->u.sheepdog.has_redundancy = true;
+ create_options->u.sheepdog.redundancy =
+ parse_redundancy_str(redundancy);
+ if (create_options->u.sheepdog.redundancy == NULL) {
+ error_setg(errp, "Invalid redundancy mode");
+ ret = -EINVAL;
+ goto fail;
+ }
+ }
+
+ ret = sd_co_create(create_options, errp);
+fail:
+ qapi_free_BlockdevCreateOptions(create_options);
+ QDECREF(qdict);
+ return ret;
+}
+
static void sd_close(BlockDriverState *bs)
{
Error *local_err = NULL;
@@ -3103,6 +3235,7 @@ static BlockDriver bdrv_sheepdog = {
.bdrv_reopen_commit = sd_reopen_commit,
.bdrv_reopen_abort = sd_reopen_abort,
.bdrv_close = sd_close,
+ .bdrv_co_create = sd_co_create,
.bdrv_co_create_opts = sd_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_getlength = sd_getlength,
@@ -3139,6 +3272,7 @@ static BlockDriver bdrv_sheepdog_tcp = {
.bdrv_reopen_commit = sd_reopen_commit,
.bdrv_reopen_abort = sd_reopen_abort,
.bdrv_close = sd_close,
+ .bdrv_co_create = sd_co_create,
.bdrv_co_create_opts = sd_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_getlength = sd_getlength,
@@ -3175,6 +3309,7 @@ static BlockDriver bdrv_sheepdog_unix = {
.bdrv_reopen_commit = sd_reopen_commit,
.bdrv_reopen_abort = sd_reopen_abort,
.bdrv_close = sd_close,
+ .bdrv_co_create = sd_co_create,
.bdrv_co_create_opts = sd_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_getlength = sd_getlength,