提交 b64842de 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging

Block layer fixes for 2.9.0-rc0

# gpg: Signature made Tue 07 Mar 2017 14:59:18 GMT
# gpg:                using RSA key 0x7F09B272C88F2FD6
# 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: (27 commits)
  commit: Don't use error_abort in commit_start
  block: Don't use error_abort in blk_new_open
  sheepdog: Support blockdev-add
  qapi-schema: Rename SocketAddressFlat's variant tcp to inet
  qapi-schema: Rename GlusterServer to SocketAddressFlat
  gluster: Plug memory leaks in qemu_gluster_parse_json()
  gluster: Don't duplicate qapi-util.c's qapi_enum_parse()
  gluster: Drop assumptions on SocketTransport names
  sheepdog: Implement bdrv_parse_filename()
  sheepdog: Use SocketAddress and socket_connect()
  sheepdog: Report errors in pseudo-filename more usefully
  sheepdog: Don't truncate long VDI name in _open(), _create()
  sheepdog: Fix snapshot ID parsing in _open(), _create, _goto()
  sheepdog: Mark sd_snapshot_delete() lossage FIXME
  sheepdog: Fix error handling sd_create()
  sheepdog: Fix error handling in sd_snapshot_delete()
  sheepdog: Defuse time bomb in sd_open() error handling
  block: Fix error handling in bdrv_replace_in_backing_chain()
  block: Handle permission errors in change_parent_backing_link()
  block: Ignore multiple children in bdrv_check_update_perm()
  ...
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
...@@ -1403,7 +1403,8 @@ static int bdrv_fill_options(QDict **options, const char *filename, ...@@ -1403,7 +1403,8 @@ static int bdrv_fill_options(QDict **options, const char *filename,
* or bdrv_abort_perm_update(). * or bdrv_abort_perm_update().
*/ */
static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms, static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms,
uint64_t cumulative_shared_perms, Error **errp) uint64_t cumulative_shared_perms,
GSList *ignore_children, Error **errp)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
BdrvChild *c; BdrvChild *c;
...@@ -1439,7 +1440,8 @@ static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms, ...@@ -1439,7 +1440,8 @@ static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms,
drv->bdrv_child_perm(bs, c, c->role, drv->bdrv_child_perm(bs, c, c->role,
cumulative_perms, cumulative_shared_perms, cumulative_perms, cumulative_shared_perms,
&cur_perm, &cur_shared); &cur_perm, &cur_shared);
ret = bdrv_child_check_perm(c, cur_perm, cur_shared, errp); ret = bdrv_child_check_perm(c, cur_perm, cur_shared, ignore_children,
errp);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
...@@ -1559,15 +1561,15 @@ static char *bdrv_perm_names(uint64_t perm) ...@@ -1559,15 +1561,15 @@ static char *bdrv_perm_names(uint64_t perm)
/* /*
* Checks whether a new reference to @bs can be added if the new user requires * Checks whether a new reference to @bs can be added if the new user requires
* @new_used_perm/@new_shared_perm as its permissions. If @ignore_child is set, * @new_used_perm/@new_shared_perm as its permissions. If @ignore_children is
* this old reference is ignored in the calculations; this allows checking * set, the BdrvChild objects in this list are ignored in the calculations;
* permission updates for an existing reference. * this allows checking permission updates for an existing reference.
* *
* Needs to be followed by a call to either bdrv_set_perm() or * Needs to be followed by a call to either bdrv_set_perm() or
* bdrv_abort_perm_update(). */ * bdrv_abort_perm_update(). */
static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm, static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm,
uint64_t new_shared_perm, uint64_t new_shared_perm,
BdrvChild *ignore_child, Error **errp) GSList *ignore_children, Error **errp)
{ {
BdrvChild *c; BdrvChild *c;
uint64_t cumulative_perms = new_used_perm; uint64_t cumulative_perms = new_used_perm;
...@@ -1577,7 +1579,7 @@ static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm, ...@@ -1577,7 +1579,7 @@ static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm,
assert(new_shared_perm & BLK_PERM_WRITE_UNCHANGED); assert(new_shared_perm & BLK_PERM_WRITE_UNCHANGED);
QLIST_FOREACH(c, &bs->parents, next_parent) { QLIST_FOREACH(c, &bs->parents, next_parent) {
if (c == ignore_child) { if (g_slist_find(ignore_children, c)) {
continue; continue;
} }
...@@ -1607,15 +1609,22 @@ static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm, ...@@ -1607,15 +1609,22 @@ static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm,
cumulative_shared_perms &= c->shared_perm; cumulative_shared_perms &= c->shared_perm;
} }
return bdrv_check_perm(bs, cumulative_perms, cumulative_shared_perms, errp); return bdrv_check_perm(bs, cumulative_perms, cumulative_shared_perms,
ignore_children, errp);
} }
/* Needs to be followed by a call to either bdrv_child_set_perm() or /* Needs to be followed by a call to either bdrv_child_set_perm() or
* bdrv_child_abort_perm_update(). */ * bdrv_child_abort_perm_update(). */
int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared, int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
Error **errp) GSList *ignore_children, Error **errp)
{ {
return bdrv_check_update_perm(c->bs, perm, shared, c, errp); int ret;
ignore_children = g_slist_prepend(g_slist_copy(ignore_children), c);
ret = bdrv_check_update_perm(c->bs, perm, shared, ignore_children, errp);
g_slist_free(ignore_children);
return ret;
} }
void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared) void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared)
...@@ -1640,7 +1649,7 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, ...@@ -1640,7 +1649,7 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
{ {
int ret; int ret;
ret = bdrv_child_check_perm(c, perm, shared, errp); ret = bdrv_child_check_perm(c, perm, shared, NULL, errp);
if (ret < 0) { if (ret < 0) {
bdrv_child_abort_perm_update(c); bdrv_child_abort_perm_update(c);
return ret; return ret;
...@@ -1718,11 +1727,10 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, ...@@ -1718,11 +1727,10 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
*nshared = shared; *nshared = shared;
} }
static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs, static void bdrv_replace_child_noperm(BdrvChild *child,
bool check_new_perm) BlockDriverState *new_bs)
{ {
BlockDriverState *old_bs = child->bs; BlockDriverState *old_bs = child->bs;
uint64_t perm, shared_perm;
if (old_bs) { if (old_bs) {
if (old_bs->quiesce_counter && child->role->drained_end) { if (old_bs->quiesce_counter && child->role->drained_end) {
...@@ -1732,13 +1740,6 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs, ...@@ -1732,13 +1740,6 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
child->role->detach(child); child->role->detach(child);
} }
QLIST_REMOVE(child, next_parent); QLIST_REMOVE(child, next_parent);
/* Update permissions for old node. This is guaranteed to succeed
* because we're just taking a parent away, so we're loosening
* restrictions. */
bdrv_get_cumulative_perm(old_bs, &perm, &shared_perm);
bdrv_check_perm(old_bs, perm, shared_perm, &error_abort);
bdrv_set_perm(old_bs, perm, shared_perm);
} }
child->bs = new_bs; child->bs = new_bs;
...@@ -1749,15 +1750,35 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs, ...@@ -1749,15 +1750,35 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
child->role->drained_begin(child); child->role->drained_begin(child);
} }
if (child->role->attach) {
child->role->attach(child);
}
}
}
static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
bool check_new_perm)
{
BlockDriverState *old_bs = child->bs;
uint64_t perm, shared_perm;
if (old_bs) {
/* Update permissions for old node. This is guaranteed to succeed
* because we're just taking a parent away, so we're loosening
* restrictions. */
bdrv_get_cumulative_perm(old_bs, &perm, &shared_perm);
bdrv_check_perm(old_bs, perm, shared_perm, NULL, &error_abort);
bdrv_set_perm(old_bs, perm, shared_perm);
}
bdrv_replace_child_noperm(child, new_bs);
if (new_bs) {
bdrv_get_cumulative_perm(new_bs, &perm, &shared_perm); bdrv_get_cumulative_perm(new_bs, &perm, &shared_perm);
if (check_new_perm) { if (check_new_perm) {
bdrv_check_perm(new_bs, perm, shared_perm, &error_abort); bdrv_check_perm(new_bs, perm, shared_perm, NULL, &error_abort);
} }
bdrv_set_perm(new_bs, perm, shared_perm); bdrv_set_perm(new_bs, perm, shared_perm);
if (child->role->attach) {
child->role->attach(child);
}
} }
} }
...@@ -2891,35 +2912,82 @@ void bdrv_close_all(void) ...@@ -2891,35 +2912,82 @@ void bdrv_close_all(void)
assert(QTAILQ_EMPTY(&all_bdrv_states)); assert(QTAILQ_EMPTY(&all_bdrv_states));
} }
static void change_parent_backing_link(BlockDriverState *from, static bool should_update_child(BdrvChild *c, BlockDriverState *to)
BlockDriverState *to) {
BdrvChild *to_c;
if (c->role->stay_at_node) {
return false;
}
if (c->role == &child_backing) {
/* If @from is a backing file of @to, ignore the child to avoid
* creating a loop. We only want to change the pointer of other
* parents. */
QLIST_FOREACH(to_c, &to->children, next) {
if (to_c == c) {
break;
}
}
if (to_c) {
return false;
}
}
return true;
}
void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
Error **errp)
{ {
BdrvChild *c, *next, *to_c; BdrvChild *c, *next;
GSList *list = NULL, *p;
uint64_t old_perm, old_shared;
uint64_t perm = 0, shared = BLK_PERM_ALL;
int ret;
assert(!atomic_read(&from->in_flight));
assert(!atomic_read(&to->in_flight));
/* Make sure that @from doesn't go away until we have successfully attached
* all of its parents to @to. */
bdrv_ref(from);
/* Put all parents into @list and calculate their cumulative permissions */
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) { QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
if (c->role->stay_at_node) { if (!should_update_child(c, to)) {
continue; continue;
} }
if (c->role == &child_backing) { list = g_slist_prepend(list, c);
/* If @from is a backing file of @to, ignore the child to avoid perm |= c->perm;
* creating a loop. We only want to change the pointer of other shared &= c->shared_perm;
* parents. */ }
QLIST_FOREACH(to_c, &to->children, next) {
if (to_c == c) { /* Check whether the required permissions can be granted on @to, ignoring
break; * all BdrvChild in @list so that they can't block themselves. */
} ret = bdrv_check_update_perm(to, perm, shared, list, errp);
} if (ret < 0) {
if (to_c) { bdrv_abort_perm_update(to);
continue; goto out;
} }
}
/* Now actually perform the change. We performed the permission check for
* all elements of @list at once, so set the permissions all at once at the
* very end. */
for (p = list; p != NULL; p = p->next) {
c = p->data;
bdrv_ref(to); bdrv_ref(to);
/* FIXME Are we sure that bdrv_replace_child() can't run into bdrv_replace_child_noperm(c, to);
* &error_abort because of permissions? */
bdrv_replace_child(c, to, true);
bdrv_unref(from); bdrv_unref(from);
} }
bdrv_get_cumulative_perm(to, &old_perm, &old_shared);
bdrv_set_perm(to, old_perm | perm, old_shared | shared);
out:
g_slist_free(list);
bdrv_unref(from);
} }
/* /*
...@@ -2943,16 +3011,18 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, ...@@ -2943,16 +3011,18 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
{ {
Error *local_err = NULL; Error *local_err = NULL;
assert(!atomic_read(&bs_top->in_flight));
assert(!atomic_read(&bs_new->in_flight));
bdrv_set_backing_hd(bs_new, bs_top, &local_err); bdrv_set_backing_hd(bs_new, bs_top, &local_err);
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
goto out; goto out;
} }
change_parent_backing_link(bs_top, bs_new); bdrv_replace_node(bs_top, bs_new, &local_err);
if (local_err) {
error_propagate(errp, local_err);
bdrv_set_backing_hd(bs_new, NULL, &error_abort);
goto out;
}
/* bs_new is now referenced by its new parents, we don't need the /* bs_new is now referenced by its new parents, we don't need the
* additional reference any more. */ * additional reference any more. */
...@@ -2960,18 +3030,6 @@ out: ...@@ -2960,18 +3030,6 @@ out:
bdrv_unref(bs_new); bdrv_unref(bs_new);
} }
void bdrv_replace_in_backing_chain(BlockDriverState *old, BlockDriverState *new)
{
assert(!bdrv_requests_pending(old));
assert(!bdrv_requests_pending(new));
bdrv_ref(old);
change_parent_backing_link(old, new);
bdrv_unref(old);
}
static void bdrv_delete(BlockDriverState *bs) static void bdrv_delete(BlockDriverState *bs)
{ {
assert(!bs->job); assert(!bs->job);
......
...@@ -213,7 +213,12 @@ BlockBackend *blk_new_open(const char *filename, const char *reference, ...@@ -213,7 +213,12 @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
} }
blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->root = bdrv_root_attach_child(bs, "root", &child_root,
perm, BLK_PERM_ALL, blk, &error_abort); perm, BLK_PERM_ALL, blk, errp);
if (!blk->root) {
bdrv_unref(bs);
blk_unref(blk);
return NULL;
}
return blk; return blk;
} }
......
...@@ -316,8 +316,20 @@ void commit_start(const char *job_id, BlockDriverState *bs, ...@@ -316,8 +316,20 @@ void commit_start(const char *job_id, BlockDriverState *bs,
goto fail; goto fail;
} }
bdrv_set_backing_hd(commit_top_bs, top, &error_abort); bdrv_set_backing_hd(commit_top_bs, top, &local_err);
bdrv_set_backing_hd(overlay_bs, commit_top_bs, &error_abort); if (local_err) {
bdrv_unref(commit_top_bs);
commit_top_bs = NULL;
error_propagate(errp, local_err);
goto fail;
}
bdrv_set_backing_hd(overlay_bs, commit_top_bs, &local_err);
if (local_err) {
bdrv_unref(commit_top_bs);
commit_top_bs = NULL;
error_propagate(errp, local_err);
goto fail;
}
s->commit_top_bs = commit_top_bs; s->commit_top_bs = commit_top_bs;
bdrv_unref(commit_top_bs); bdrv_unref(commit_top_bs);
...@@ -364,7 +376,7 @@ void commit_start(const char *job_id, BlockDriverState *bs, ...@@ -364,7 +376,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
/* Required permissions are already taken with block_job_add_bdrv() */ /* Required permissions are already taken with block_job_add_bdrv() */
s->top = blk_new(0, BLK_PERM_ALL); s->top = blk_new(0, BLK_PERM_ALL);
blk_insert_bs(s->top, top, errp); ret = blk_insert_bs(s->top, top, errp);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "block/block_int.h" #include "block/block_int.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "qapi/util.h"
#include "qemu/uri.h" #include "qemu/uri.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/cutils.h" #include "qemu/cutils.h"
...@@ -151,7 +152,7 @@ static QemuOptsList runtime_type_opts = { ...@@ -151,7 +152,7 @@ static QemuOptsList runtime_type_opts = {
{ {
.name = GLUSTER_OPT_TYPE, .name = GLUSTER_OPT_TYPE,
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
.help = "tcp|unix", .help = "inet|unix",
}, },
{ /* end of list */ } { /* end of list */ }
}, },
...@@ -170,14 +171,14 @@ static QemuOptsList runtime_unix_opts = { ...@@ -170,14 +171,14 @@ static QemuOptsList runtime_unix_opts = {
}, },
}; };
static QemuOptsList runtime_tcp_opts = { static QemuOptsList runtime_inet_opts = {
.name = "gluster_tcp", .name = "gluster_inet",
.head = QTAILQ_HEAD_INITIALIZER(runtime_tcp_opts.head), .head = QTAILQ_HEAD_INITIALIZER(runtime_inet_opts.head),
.desc = { .desc = {
{ {
.name = GLUSTER_OPT_TYPE, .name = GLUSTER_OPT_TYPE,
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
.help = "tcp|unix", .help = "inet|unix",
}, },
{ {
.name = GLUSTER_OPT_HOST, .name = GLUSTER_OPT_HOST,
...@@ -320,7 +321,7 @@ static int parse_volume_options(BlockdevOptionsGluster *gconf, char *path) ...@@ -320,7 +321,7 @@ static int parse_volume_options(BlockdevOptionsGluster *gconf, char *path)
static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf, static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
const char *filename) const char *filename)
{ {
GlusterServer *gsconf; SocketAddressFlat *gsconf;
URI *uri; URI *uri;
QueryParams *qp = NULL; QueryParams *qp = NULL;
bool is_unix = false; bool is_unix = false;
...@@ -331,19 +332,19 @@ static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf, ...@@ -331,19 +332,19 @@ static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
return -EINVAL; return -EINVAL;
} }
gconf->server = g_new0(GlusterServerList, 1); gconf->server = g_new0(SocketAddressFlatList, 1);
gconf->server->value = gsconf = g_new0(GlusterServer, 1); gconf->server->value = gsconf = g_new0(SocketAddressFlat, 1);
/* transport */ /* transport */
if (!uri->scheme || !strcmp(uri->scheme, "gluster")) { if (!uri->scheme || !strcmp(uri->scheme, "gluster")) {
gsconf->type = GLUSTER_TRANSPORT_TCP; gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_INET;
} else if (!strcmp(uri->scheme, "gluster+tcp")) { } else if (!strcmp(uri->scheme, "gluster+tcp")) {
gsconf->type = GLUSTER_TRANSPORT_TCP; gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_INET;
} else if (!strcmp(uri->scheme, "gluster+unix")) { } else if (!strcmp(uri->scheme, "gluster+unix")) {
gsconf->type = GLUSTER_TRANSPORT_UNIX; gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_UNIX;
is_unix = true; is_unix = true;
} else if (!strcmp(uri->scheme, "gluster+rdma")) { } else if (!strcmp(uri->scheme, "gluster+rdma")) {
gsconf->type = GLUSTER_TRANSPORT_TCP; gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_INET;
error_report("Warning: rdma feature is not supported, falling " error_report("Warning: rdma feature is not supported, falling "
"back to tcp"); "back to tcp");
} else { } else {
...@@ -373,11 +374,11 @@ static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf, ...@@ -373,11 +374,11 @@ static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
} }
gsconf->u.q_unix.path = g_strdup(qp->p[0].value); gsconf->u.q_unix.path = g_strdup(qp->p[0].value);
} else { } else {
gsconf->u.tcp.host = g_strdup(uri->server ? uri->server : "localhost"); gsconf->u.inet.host = g_strdup(uri->server ? uri->server : "localhost");
if (uri->port) { if (uri->port) {
gsconf->u.tcp.port = g_strdup_printf("%d", uri->port); gsconf->u.inet.port = g_strdup_printf("%d", uri->port);
} else { } else {
gsconf->u.tcp.port = g_strdup_printf("%d", GLUSTER_DEFAULT_PORT); gsconf->u.inet.port = g_strdup_printf("%d", GLUSTER_DEFAULT_PORT);
} }
} }
...@@ -395,7 +396,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf, ...@@ -395,7 +396,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
struct glfs *glfs; struct glfs *glfs;
int ret; int ret;
int old_errno; int old_errno;
GlusterServerList *server; SocketAddressFlatList *server;
unsigned long long port; unsigned long long port;
glfs = glfs_find_preopened(gconf->volume); glfs = glfs_find_preopened(gconf->volume);
...@@ -411,21 +412,19 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf, ...@@ -411,21 +412,19 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
glfs_set_preopened(gconf->volume, glfs); glfs_set_preopened(gconf->volume, glfs);
for (server = gconf->server; server; server = server->next) { for (server = gconf->server; server; server = server->next) {
if (server->value->type == GLUSTER_TRANSPORT_UNIX) { if (server->value->type == SOCKET_ADDRESS_FLAT_TYPE_UNIX) {
ret = glfs_set_volfile_server(glfs, ret = glfs_set_volfile_server(glfs, "unix",
GlusterTransport_lookup[server->value->type],
server->value->u.q_unix.path, 0); server->value->u.q_unix.path, 0);
} else { } else {
if (parse_uint_full(server->value->u.tcp.port, &port, 10) < 0 || if (parse_uint_full(server->value->u.inet.port, &port, 10) < 0 ||
port > 65535) { port > 65535) {
error_setg(errp, "'%s' is not a valid port number", error_setg(errp, "'%s' is not a valid port number",
server->value->u.tcp.port); server->value->u.inet.port);
errno = EINVAL; errno = EINVAL;
goto out; goto out;
} }
ret = glfs_set_volfile_server(glfs, ret = glfs_set_volfile_server(glfs, "tcp",
GlusterTransport_lookup[server->value->type], server->value->u.inet.host,
server->value->u.tcp.host,
(int)port); (int)port);
} }
...@@ -444,13 +443,13 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf, ...@@ -444,13 +443,13 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
error_setg(errp, "Gluster connection for volume %s, path %s failed" error_setg(errp, "Gluster connection for volume %s, path %s failed"
" to connect", gconf->volume, gconf->path); " to connect", gconf->volume, gconf->path);
for (server = gconf->server; server; server = server->next) { for (server = gconf->server; server; server = server->next) {
if (server->value->type == GLUSTER_TRANSPORT_UNIX) { if (server->value->type == SOCKET_ADDRESS_FLAT_TYPE_UNIX) {
error_append_hint(errp, "hint: failed on socket %s ", error_append_hint(errp, "hint: failed on socket %s ",
server->value->u.q_unix.path); server->value->u.q_unix.path);
} else { } else {
error_append_hint(errp, "hint: failed on host %s and port %s ", error_append_hint(errp, "hint: failed on host %s and port %s ",
server->value->u.tcp.host, server->value->u.inet.host,
server->value->u.tcp.port); server->value->u.inet.port);
} }
} }
...@@ -474,23 +473,6 @@ out: ...@@ -474,23 +473,6 @@ out:
return NULL; return NULL;
} }
static int qapi_enum_parse(const char *opt)
{
int i;
if (!opt) {
return GLUSTER_TRANSPORT__MAX;
}
for (i = 0; i < GLUSTER_TRANSPORT__MAX; i++) {
if (!strcmp(opt, GlusterTransport_lookup[i])) {
return i;
}
}
return i;
}
/* /*
* Convert the json formatted command line into qapi. * Convert the json formatted command line into qapi.
*/ */
...@@ -498,8 +480,8 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, ...@@ -498,8 +480,8 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
QDict *options, Error **errp) QDict *options, Error **errp)
{ {
QemuOpts *opts; QemuOpts *opts;
GlusterServer *gsconf; SocketAddressFlat *gsconf = NULL;
GlusterServerList *curr = NULL; SocketAddressFlatList *curr = NULL;
QDict *backing_options = NULL; QDict *backing_options = NULL;
Error *local_err = NULL; Error *local_err = NULL;
char *str = NULL; char *str = NULL;
...@@ -547,25 +529,31 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, ...@@ -547,25 +529,31 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
} }
ptr = qemu_opt_get(opts, GLUSTER_OPT_TYPE); ptr = qemu_opt_get(opts, GLUSTER_OPT_TYPE);
gsconf = g_new0(GlusterServer, 1);
gsconf->type = qapi_enum_parse(ptr);
if (!ptr) { if (!ptr) {
error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_TYPE); error_setg(&local_err, QERR_MISSING_PARAMETER, GLUSTER_OPT_TYPE);
error_append_hint(&local_err, GERR_INDEX_HINT, i); error_append_hint(&local_err, GERR_INDEX_HINT, i);
goto out; goto out;
} }
if (gsconf->type == GLUSTER_TRANSPORT__MAX) { gsconf = g_new0(SocketAddressFlat, 1);
error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE, if (!strcmp(ptr, "tcp")) {
GLUSTER_OPT_TYPE, "tcp or unix"); ptr = "inet"; /* accept legacy "tcp" */
}
gsconf->type = qapi_enum_parse(SocketAddressFlatType_lookup, ptr,
SOCKET_ADDRESS_FLAT_TYPE__MAX, -1,
&local_err);
if (local_err) {
error_append_hint(&local_err,
"Parameter '%s' may be 'inet' or 'unix'\n",
GLUSTER_OPT_TYPE);
error_append_hint(&local_err, GERR_INDEX_HINT, i); error_append_hint(&local_err, GERR_INDEX_HINT, i);
goto out; goto out;
} }
qemu_opts_del(opts); qemu_opts_del(opts);
if (gsconf->type == GLUSTER_TRANSPORT_TCP) { if (gsconf->type == SOCKET_ADDRESS_FLAT_TYPE_INET) {
/* create opts info from runtime_tcp_opts list */ /* create opts info from runtime_inet_opts list */
opts = qemu_opts_create(&runtime_tcp_opts, NULL, 0, &error_abort); opts = qemu_opts_create(&runtime_inet_opts, NULL, 0, &error_abort);
qemu_opts_absorb_qdict(opts, backing_options, &local_err); qemu_opts_absorb_qdict(opts, backing_options, &local_err);
if (local_err) { if (local_err) {
goto out; goto out;
...@@ -578,7 +566,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, ...@@ -578,7 +566,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
error_append_hint(&local_err, GERR_INDEX_HINT, i); error_append_hint(&local_err, GERR_INDEX_HINT, i);
goto out; goto out;
} }
gsconf->u.tcp.host = g_strdup(ptr); gsconf->u.inet.host = g_strdup(ptr);
ptr = qemu_opt_get(opts, GLUSTER_OPT_PORT); ptr = qemu_opt_get(opts, GLUSTER_OPT_PORT);
if (!ptr) { if (!ptr) {
error_setg(&local_err, QERR_MISSING_PARAMETER, error_setg(&local_err, QERR_MISSING_PARAMETER,
...@@ -586,28 +574,28 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, ...@@ -586,28 +574,28 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
error_append_hint(&local_err, GERR_INDEX_HINT, i); error_append_hint(&local_err, GERR_INDEX_HINT, i);
goto out; goto out;
} }
gsconf->u.tcp.port = g_strdup(ptr); gsconf->u.inet.port = g_strdup(ptr);
/* defend for unsupported fields in InetSocketAddress, /* defend for unsupported fields in InetSocketAddress,
* i.e. @ipv4, @ipv6 and @to * i.e. @ipv4, @ipv6 and @to
*/ */
ptr = qemu_opt_get(opts, GLUSTER_OPT_TO); ptr = qemu_opt_get(opts, GLUSTER_OPT_TO);
if (ptr) { if (ptr) {
gsconf->u.tcp.has_to = true; gsconf->u.inet.has_to = true;
} }
ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV4); ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV4);
if (ptr) { if (ptr) {
gsconf->u.tcp.has_ipv4 = true; gsconf->u.inet.has_ipv4 = true;
} }
ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV6); ptr = qemu_opt_get(opts, GLUSTER_OPT_IPV6);
if (ptr) { if (ptr) {
gsconf->u.tcp.has_ipv6 = true; gsconf->u.inet.has_ipv6 = true;
} }
if (gsconf->u.tcp.has_to) { if (gsconf->u.inet.has_to) {
error_setg(&local_err, "Parameter 'to' not supported"); error_setg(&local_err, "Parameter 'to' not supported");
goto out; goto out;
} }
if (gsconf->u.tcp.has_ipv4 || gsconf->u.tcp.has_ipv6) { if (gsconf->u.inet.has_ipv4 || gsconf->u.inet.has_ipv6) {
error_setg(&local_err, "Parameters 'ipv4/ipv6' not supported"); error_setg(&local_err, "Parameters 'ipv4/ipv6' not supported");
goto out; goto out;
} }
...@@ -632,16 +620,18 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, ...@@ -632,16 +620,18 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
} }
if (gconf->server == NULL) { if (gconf->server == NULL) {
gconf->server = g_new0(GlusterServerList, 1); gconf->server = g_new0(SocketAddressFlatList, 1);
gconf->server->value = gsconf; gconf->server->value = gsconf;
curr = gconf->server; curr = gconf->server;
} else { } else {
curr->next = g_new0(GlusterServerList, 1); curr->next = g_new0(SocketAddressFlatList, 1);
curr->next->value = gsconf; curr->next->value = gsconf;
curr = curr->next; curr = curr->next;
} }
gsconf = NULL;
qdict_del(backing_options, str); QDECREF(backing_options);
backing_options = NULL;
g_free(str); g_free(str);
str = NULL; str = NULL;
} }
...@@ -650,11 +640,10 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf, ...@@ -650,11 +640,10 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
out: out:
error_propagate(errp, local_err); error_propagate(errp, local_err);
qapi_free_SocketAddressFlat(gsconf);
qemu_opts_del(opts); qemu_opts_del(opts);
if (str) { g_free(str);
qdict_del(backing_options, str); QDECREF(backing_options);
g_free(str);
}
errno = EINVAL; errno = EINVAL;
return -errno; return -errno;
} }
...@@ -683,7 +672,7 @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf, ...@@ -683,7 +672,7 @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
"file.volume=testvol,file.path=/path/a.qcow2" "file.volume=testvol,file.path=/path/a.qcow2"
"[,file.debug=9]" "[,file.debug=9]"
"[,file.logfile=/path/filename.log]," "[,file.logfile=/path/filename.log],"
"file.server.0.type=tcp," "file.server.0.type=inet,"
"file.server.0.host=1.2.3.4," "file.server.0.host=1.2.3.4,"
"file.server.0.port=24007," "file.server.0.port=24007,"
"file.server.1.transport=unix," "file.server.1.transport=unix,"
......
...@@ -509,6 +509,13 @@ static void mirror_exit(BlockJob *job, void *opaque) ...@@ -509,6 +509,13 @@ static void mirror_exit(BlockJob *job, void *opaque)
* block_job_completed(). */ * block_job_completed(). */
bdrv_ref(src); bdrv_ref(src);
bdrv_ref(mirror_top_bs); bdrv_ref(mirror_top_bs);
bdrv_ref(target_bs);
/* Remove target parent that still uses BLK_PERM_WRITE/RESIZE before
* inserting target_bs at s->to_replace, where we might not be able to get
* these permissions. */
blk_unref(s->target);
s->target = NULL;
/* We don't access the source any more. Dropping any WRITE/RESIZE is /* We don't access the source any more. Dropping any WRITE/RESIZE is
* required before it could become a backing file of target_bs. */ * required before it could become a backing file of target_bs. */
...@@ -543,8 +550,12 @@ static void mirror_exit(BlockJob *job, void *opaque) ...@@ -543,8 +550,12 @@ static void mirror_exit(BlockJob *job, void *opaque)
/* The mirror job has no requests in flight any more, but we need to /* The mirror job has no requests in flight any more, but we need to
* drain potential other users of the BDS before changing the graph. */ * drain potential other users of the BDS before changing the graph. */
bdrv_drained_begin(target_bs); bdrv_drained_begin(target_bs);
bdrv_replace_in_backing_chain(to_replace, target_bs); bdrv_replace_node(to_replace, target_bs, &local_err);
bdrv_drained_end(target_bs); bdrv_drained_end(target_bs);
if (local_err) {
error_report_err(local_err);
data->ret = -EPERM;
}
} }
if (s->to_replace) { if (s->to_replace) {
bdrv_op_unblock_all(s->to_replace, s->replace_blocker); bdrv_op_unblock_all(s->to_replace, s->replace_blocker);
...@@ -555,19 +566,19 @@ static void mirror_exit(BlockJob *job, void *opaque) ...@@ -555,19 +566,19 @@ static void mirror_exit(BlockJob *job, void *opaque)
aio_context_release(replace_aio_context); aio_context_release(replace_aio_context);
} }
g_free(s->replaces); g_free(s->replaces);
blk_unref(s->target); bdrv_unref(target_bs);
s->target = NULL;
/* Remove the mirror filter driver from the graph. Before this, get rid of /* Remove the mirror filter driver from the graph. Before this, get rid of
* the blockers on the intermediate nodes so that the resulting state is * the blockers on the intermediate nodes so that the resulting state is
* valid. */ * valid. Also give up permissions on mirror_top_bs->backing, which might
* block the removal. */
block_job_remove_all_bdrv(job); block_job_remove_all_bdrv(job);
bdrv_replace_in_backing_chain(mirror_top_bs, backing_bs(mirror_top_bs)); bdrv_child_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL);
bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);
/* We just changed the BDS the job BB refers to (with either or both of the /* We just changed the BDS the job BB refers to (with either or both of the
* bdrv_replace_in_backing_chain() calls), so switch the BB back so the * bdrv_replace_node() calls), so switch the BB back so the cleanup does
* cleanup does the right thing. We don't need any permissions any more * the right thing. We don't need any permissions any more now. */
* now. */
blk_remove_bs(job->blk); blk_remove_bs(job->blk);
blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort); blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort);
blk_insert_bs(job->blk, mirror_top_bs, &error_abort); blk_insert_bs(job->blk, mirror_top_bs, &error_abort);
...@@ -1189,10 +1200,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs, ...@@ -1189,10 +1200,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp); s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
if (!s->dirty_bitmap) { if (!s->dirty_bitmap) {
g_free(s->replaces); goto fail;
blk_unref(s->target);
block_job_unref(&s->common);
return;
} }
/* Required permissions are already taken with blk_new() */ /* Required permissions are already taken with blk_new() */
...@@ -1228,7 +1236,8 @@ fail: ...@@ -1228,7 +1236,8 @@ fail:
block_job_unref(&s->common); block_job_unref(&s->common);
} }
bdrv_replace_in_backing_chain(mirror_top_bs, backing_bs(mirror_top_bs)); bdrv_child_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL);
bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);
} }
void mirror_start(const char *job_id, BlockDriverState *bs, void mirror_start(const char *job_id, BlockDriverState *bs,
......
此差异已折叠。
...@@ -1614,6 +1614,7 @@ typedef struct ExternalSnapshotState { ...@@ -1614,6 +1614,7 @@ typedef struct ExternalSnapshotState {
BlockDriverState *old_bs; BlockDriverState *old_bs;
BlockDriverState *new_bs; BlockDriverState *new_bs;
AioContext *aio_context; AioContext *aio_context;
bool overlay_appended;
} ExternalSnapshotState; } ExternalSnapshotState;
static void external_snapshot_prepare(BlkActionState *common, static void external_snapshot_prepare(BlkActionState *common,
...@@ -1780,6 +1781,7 @@ static void external_snapshot_prepare(BlkActionState *common, ...@@ -1780,6 +1781,7 @@ static void external_snapshot_prepare(BlkActionState *common,
error_propagate(errp, local_err); error_propagate(errp, local_err);
return; return;
} }
state->overlay_appended = true;
} }
static void external_snapshot_commit(BlkActionState *common) static void external_snapshot_commit(BlkActionState *common)
...@@ -1803,8 +1805,8 @@ static void external_snapshot_abort(BlkActionState *common) ...@@ -1803,8 +1805,8 @@ static void external_snapshot_abort(BlkActionState *common)
ExternalSnapshotState *state = ExternalSnapshotState *state =
DO_UPCAST(ExternalSnapshotState, common, common); DO_UPCAST(ExternalSnapshotState, common, common);
if (state->new_bs) { if (state->new_bs) {
if (state->new_bs->backing) { if (state->overlay_appended) {
bdrv_replace_in_backing_chain(state->new_bs, state->old_bs); bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
} }
} }
} }
......
...@@ -238,8 +238,8 @@ int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp); ...@@ -238,8 +238,8 @@ int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp);
BlockDriverState *bdrv_new(void); BlockDriverState *bdrv_new(void);
void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
Error **errp); Error **errp);
void bdrv_replace_in_backing_chain(BlockDriverState *old, void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
BlockDriverState *new); Error **errp);
int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough); int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough);
int bdrv_parse_discard_flags(const char *mode, int *flags); int bdrv_parse_discard_flags(const char *mode, int *flags);
......
...@@ -441,8 +441,8 @@ typedef struct BdrvAioNotifier { ...@@ -441,8 +441,8 @@ typedef struct BdrvAioNotifier {
} BdrvAioNotifier; } BdrvAioNotifier;
struct BdrvChildRole { struct BdrvChildRole {
/* If true, bdrv_replace_in_backing_chain() doesn't change the node this /* If true, bdrv_replace_node() doesn't change the node this BdrvChild
* BdrvChild points to. */ * points to. */
bool stay_at_node; bool stay_at_node;
void (*inherit_options)(int *child_flags, QDict *child_options, void (*inherit_options)(int *child_flags, QDict *child_options,
...@@ -890,7 +890,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs, ...@@ -890,7 +890,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
void bdrv_root_unref_child(BdrvChild *child); void bdrv_root_unref_child(BdrvChild *child);
int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared, int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
Error **errp); GSList *ignore_children, Error **errp);
void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared); void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared);
void bdrv_child_abort_perm_update(BdrvChild *c); void bdrv_child_abort_perm_update(BdrvChild *c);
int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
......
...@@ -4100,6 +4100,44 @@ ...@@ -4100,6 +4100,44 @@
'vsock': 'VsockSocketAddress', 'vsock': 'VsockSocketAddress',
'fd': 'String' } } 'fd': 'String' } }
##
# @SocketAddressFlatType:
#
# Available SocketAddressFlat types
#
# @inet: Internet address
#
# @unix: Unix domain socket
#
# Since: 2.9
##
{ 'enum': 'SocketAddressFlatType',
'data': [ 'unix', 'inet' ] }
##
# @SocketAddressFlat:
#
# Captures the address of a socket
#
# @type: Transport type
#
# This is similar to SocketAddress, only distinction:
#
# 1. SocketAddressFlat is a flat union, SocketAddress is a simple union.
# A flat union is nicer than simple because it avoids nesting
# (i.e. more {}) on the wire.
#
# 2. SocketAddressFlat supports only types 'unix' and 'inet', because
# that's what its current users need.
#
# Since: 2.9
##
{ 'union': 'SocketAddressFlat',
'base': { 'type': 'SocketAddressFlatType' },
'discriminator': 'type',
'data': { 'unix': 'UnixSocketAddress',
'inet': 'InetSocketAddress' } }
## ##
# @getfd: # @getfd:
# #
......
...@@ -2124,6 +2124,7 @@ ...@@ -2124,6 +2124,7 @@
# @ssh: Since 2.8 # @ssh: Since 2.8
# @iscsi: Since 2.9 # @iscsi: Since 2.9
# @rbd: Since 2.9 # @rbd: Since 2.9
# @sheepdog: Since 2.9
# #
# Since: 2.0 # Since: 2.0
## ##
...@@ -2132,8 +2133,8 @@ ...@@ -2132,8 +2133,8 @@
'dmg', 'file', 'ftp', 'ftps', 'gluster', 'host_cdrom', 'dmg', 'file', 'ftp', 'ftps', 'gluster', 'host_cdrom',
'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs', 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed', 'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
'quorum', 'raw', 'rbd', 'replication', 'ssh', 'vdi', 'vhdx', 'vmdk', 'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
'vpc', 'vvfat' ] } 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] }
## ##
# @BlockdevOptionsFile: # @BlockdevOptionsFile:
...@@ -2545,50 +2546,6 @@ ...@@ -2545,50 +2546,6 @@
'*rewrite-corrupted': 'bool', '*rewrite-corrupted': 'bool',
'*read-pattern': 'QuorumReadPattern' } } '*read-pattern': 'QuorumReadPattern' } }
##
# @GlusterTransport:
#
# An enumeration of Gluster transport types
#
# @tcp: TCP - Transmission Control Protocol
#
# @unix: UNIX - Unix domain socket
#
# Since: 2.7
##
{ 'enum': 'GlusterTransport',
'data': [ 'unix', 'tcp' ] }
##
# @GlusterServer:
#
# Captures the address of a socket
#
# Details for connecting to a gluster server
#
# @type: Transport type used for gluster connection
#
# This is similar to SocketAddress, only distinction:
#
# 1. GlusterServer is a flat union, SocketAddress is a simple union.
# A flat union is nicer than simple because it avoids nesting
# (i.e. more {}) on the wire.
#
# 2. GlusterServer lacks case 'fd', since gluster doesn't let you
# pass in a file descriptor.
#
# GlusterServer is actually not Gluster-specific, its a
# compatibility evolved into an alternate for SocketAddress.
#
# Since: 2.7
##
{ 'union': 'GlusterServer',
'base': { 'type': 'GlusterTransport' },
'discriminator': 'type',
'data': { 'unix': 'UnixSocketAddress',
'tcp': 'InetSocketAddress' } }
## ##
# @BlockdevOptionsGluster: # @BlockdevOptionsGluster:
# #
...@@ -2610,7 +2567,7 @@ ...@@ -2610,7 +2567,7 @@
{ 'struct': 'BlockdevOptionsGluster', { 'struct': 'BlockdevOptionsGluster',
'data': { 'volume': 'str', 'data': { 'volume': 'str',
'path': 'str', 'path': 'str',
'server': ['GlusterServer'], 'server': ['SocketAddressFlat'],
'*debug': 'int', '*debug': 'int',
'*logfile': 'str' } } '*logfile': 'str' } }
...@@ -2735,6 +2692,26 @@ ...@@ -2735,6 +2692,26 @@
'*auth-supported': ['RbdAuthMethod'], '*auth-supported': ['RbdAuthMethod'],
'*password-secret': 'str' } } '*password-secret': 'str' } }
##
# @BlockdevOptionsSheepdog:
#
# Driver specific block device options for sheepdog
#
# @vdi: Virtual disk image name
# @addr: The Sheepdog server to connect to
# @snap-id: Snapshot ID
# @tag: Snapshot tag name
#
# Only one of @snap-id and @tag may be present.
#
# Since: 2.9
##
{ 'struct': 'BlockdevOptionsSheepdog',
'data': { 'addr': 'SocketAddressFlat',
'vdi': 'str',
'*snap-id': 'uint32',
'*tag': 'str' } }
## ##
# @ReplicationMode: # @ReplicationMode:
# #
...@@ -2935,7 +2912,7 @@ ...@@ -2935,7 +2912,7 @@
'raw': 'BlockdevOptionsRaw', 'raw': 'BlockdevOptionsRaw',
'rbd': 'BlockdevOptionsRbd', 'rbd': 'BlockdevOptionsRbd',
'replication':'BlockdevOptionsReplication', 'replication':'BlockdevOptionsReplication',
# TODO sheepdog: Wait for structured options 'sheepdog': 'BlockdevOptionsSheepdog',
'ssh': 'BlockdevOptionsSsh', 'ssh': 'BlockdevOptionsSsh',
'vdi': 'BlockdevOptionsGenericFormat', 'vdi': 'BlockdevOptionsGenericFormat',
'vhdx': 'BlockdevOptionsGenericFormat', 'vhdx': 'BlockdevOptionsGenericFormat',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册