mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 15:53:54 -06:00
Block layer fixes for 2.9.0-rc0
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJYvsrGAAoJEH8JsnLIjy/W5N4QAJAx81OUMvn4b+owj+a5U8T+ uu6kOhIkRkeNtNFGxolQqRq1vIuTNfCwPsaFR5E6Qv7MyNKK50korFfI9MHOwbg5 VNiRfsw88wI4u5PHw1cHEcpdJPJx5D7gLz0tdM8dYSjdZPIe5myO3C7bMwElEz4t 1PJdpNZueiW/HAw+10IVxn1E2oCEC+6LWPOZRtVmwiItZgJHbZXJ3izNCFaNAFmF Xb1YMG4gZKxH0DiMKbBAE+Np+8h6dKQw/guVV6aoOfRoLc5cEkbB1VHW50PQO8w9 Z0Hb++xTAT7KugxrVQlImh8HGZ0ICxj4zILw8owLmXeB9DeJ1MKQhsoWkirQ65T9 OnYqDwPtWqAvO738ygGIYGXhm5ltyUfXKdwfQDvSgJqQP4lJcz4RMs7ZgiuaPLZY nr/CTR6867Bv2jIoEXpx2zGpYiWnMjCbA6uorHIVlEOPPFuvOqa5ClU1BwT6bojO QnWWu99SXH27fioin/1TFiL1KQqCXXmEznFLXp2CNALkR+GwMO/kUSKbQeYDFy0E 7KlfLac0tKJC4qzsXyeDgtvETVUJAn2Pz04y97RF3ESsI/JPI4KaSa3ARrOmEa3g kayR/C+UmsH8phn6HyqgR3miv0oRuVQuhTVX04z7aH11a2Bgca3nHjjcjag8E+I4 GNOaGdmQkG5P4GCM5xW8 =0adR -----END PGP SIGNATURE----- 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: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
b64842dee4
11 changed files with 626 additions and 329 deletions
184
block.c
184
block.c
|
@ -1403,7 +1403,8 @@ static int bdrv_fill_options(QDict **options, const char *filename,
|
|||
* or bdrv_abort_perm_update().
|
||||
*/
|
||||
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;
|
||||
BdrvChild *c;
|
||||
|
@ -1439,7 +1440,8 @@ static int bdrv_check_perm(BlockDriverState *bs, uint64_t cumulative_perms,
|
|||
drv->bdrv_child_perm(bs, c, c->role,
|
||||
cumulative_perms, cumulative_shared_perms,
|
||||
&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) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -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
|
||||
* @new_used_perm/@new_shared_perm as its permissions. If @ignore_child is set,
|
||||
* this old reference is ignored in the calculations; this allows checking
|
||||
* permission updates for an existing reference.
|
||||
* @new_used_perm/@new_shared_perm as its permissions. If @ignore_children is
|
||||
* set, the BdrvChild objects in this list are ignored in the calculations;
|
||||
* this allows checking permission updates for an existing reference.
|
||||
*
|
||||
* Needs to be followed by a call to either bdrv_set_perm() or
|
||||
* bdrv_abort_perm_update(). */
|
||||
static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_perm,
|
||||
uint64_t new_shared_perm,
|
||||
BdrvChild *ignore_child, Error **errp)
|
||||
GSList *ignore_children, Error **errp)
|
||||
{
|
||||
BdrvChild *c;
|
||||
uint64_t cumulative_perms = 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);
|
||||
|
||||
QLIST_FOREACH(c, &bs->parents, next_parent) {
|
||||
if (c == ignore_child) {
|
||||
if (g_slist_find(ignore_children, c)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1607,15 +1609,22 @@ static int bdrv_check_update_perm(BlockDriverState *bs, uint64_t new_used_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
|
||||
* bdrv_child_abort_perm_update(). */
|
||||
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)
|
||||
|
@ -1640,7 +1649,7 @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = bdrv_child_check_perm(c, perm, shared, errp);
|
||||
ret = bdrv_child_check_perm(c, perm, shared, NULL, errp);
|
||||
if (ret < 0) {
|
||||
bdrv_child_abort_perm_update(c);
|
||||
return ret;
|
||||
|
@ -1718,11 +1727,10 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
|
|||
*nshared = shared;
|
||||
}
|
||||
|
||||
static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
|
||||
bool check_new_perm)
|
||||
static void bdrv_replace_child_noperm(BdrvChild *child,
|
||||
BlockDriverState *new_bs)
|
||||
{
|
||||
BlockDriverState *old_bs = child->bs;
|
||||
uint64_t perm, shared_perm;
|
||||
|
||||
if (old_bs) {
|
||||
if (old_bs->quiesce_counter && child->role->drained_end) {
|
||||
|
@ -1732,13 +1740,6 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
|
|||
child->role->detach(child);
|
||||
}
|
||||
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;
|
||||
|
@ -1749,18 +1750,38 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
|
|||
child->role->drained_begin(child);
|
||||
}
|
||||
|
||||
bdrv_get_cumulative_perm(new_bs, &perm, &shared_perm);
|
||||
if (check_new_perm) {
|
||||
bdrv_check_perm(new_bs, perm, shared_perm, &error_abort);
|
||||
}
|
||||
bdrv_set_perm(new_bs, perm, shared_perm);
|
||||
|
||||
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);
|
||||
if (check_new_perm) {
|
||||
bdrv_check_perm(new_bs, perm, shared_perm, NULL, &error_abort);
|
||||
}
|
||||
bdrv_set_perm(new_bs, perm, shared_perm);
|
||||
}
|
||||
}
|
||||
|
||||
BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
|
||||
const char *child_name,
|
||||
const BdrvChildRole *child_role,
|
||||
|
@ -2891,35 +2912,82 @@ void bdrv_close_all(void)
|
|||
assert(QTAILQ_EMPTY(&all_bdrv_states));
|
||||
}
|
||||
|
||||
static void change_parent_backing_link(BlockDriverState *from,
|
||||
BlockDriverState *to)
|
||||
static bool should_update_child(BdrvChild *c, BlockDriverState *to)
|
||||
{
|
||||
BdrvChild *c, *next, *to_c;
|
||||
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;
|
||||
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) {
|
||||
if (c->role->stay_at_node) {
|
||||
if (!should_update_child(c, to)) {
|
||||
continue;
|
||||
}
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
list = g_slist_prepend(list, c);
|
||||
perm |= c->perm;
|
||||
shared &= c->shared_perm;
|
||||
}
|
||||
|
||||
/* Check whether the required permissions can be granted on @to, ignoring
|
||||
* all BdrvChild in @list so that they can't block themselves. */
|
||||
ret = bdrv_check_update_perm(to, perm, shared, list, errp);
|
||||
if (ret < 0) {
|
||||
bdrv_abort_perm_update(to);
|
||||
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);
|
||||
/* FIXME Are we sure that bdrv_replace_child() can't run into
|
||||
* &error_abort because of permissions? */
|
||||
bdrv_replace_child(c, to, true);
|
||||
bdrv_replace_child_noperm(c, to);
|
||||
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,
|
|||
{
|
||||
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);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
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
|
||||
* additional reference any more. */
|
||||
|
@ -2960,18 +3030,6 @@ out:
|
|||
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)
|
||||
{
|
||||
assert(!bs->job);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue