block.c (0978623e0f485266b015f533e76f2efab0769100) block.c (3bb0e2980a96db6276e5032dcb2ccbf41f699b59)
1/*
2 * QEMU System Emulator block driver
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights

--- 2259 unchanged lines hidden (view full) ---

2268 .clean = g_free,
2269};
2270
2271/*
2272 * bdrv_replace_child_safe
2273 *
2274 * Note: real unref of old_bs is done only on commit.
2275 */
1/*
2 * QEMU System Emulator block driver
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights

--- 2259 unchanged lines hidden (view full) ---

2268 .clean = g_free,
2269};
2270
2271/*
2272 * bdrv_replace_child_safe
2273 *
2274 * Note: real unref of old_bs is done only on commit.
2275 */
2276__attribute__((unused))
2277static void bdrv_replace_child_safe(BdrvChild *child, BlockDriverState *new_bs,
2278 Transaction *tran)
2279{
2280 BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
2281 *s = (BdrvReplaceChildState) {
2282 .child = child,
2283 .old_bs = child->bs,
2284 };

--- 2587 unchanged lines hidden (view full) ---

4872 * With auto_skip=false the error is returned if from has a parent which should
4873 * not be updated.
4874 */
4875static int bdrv_replace_node_common(BlockDriverState *from,
4876 BlockDriverState *to,
4877 bool auto_skip, Error **errp)
4878{
4879 BdrvChild *c, *next;
2276static void bdrv_replace_child_safe(BdrvChild *child, BlockDriverState *new_bs,
2277 Transaction *tran)
2278{
2279 BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
2280 *s = (BdrvReplaceChildState) {
2281 .child = child,
2282 .old_bs = child->bs,
2283 };

--- 2587 unchanged lines hidden (view full) ---

4871 * With auto_skip=false the error is returned if from has a parent which should
4872 * not be updated.
4873 */
4874static int bdrv_replace_node_common(BlockDriverState *from,
4875 BlockDriverState *to,
4876 bool auto_skip, Error **errp)
4877{
4878 BdrvChild *c, *next;
4880 GSList *list = NULL, *p;
4881 uint64_t perm = 0, shared = BLK_PERM_ALL;
4879 Transaction *tran = tran_new();
4880 g_autoptr(GHashTable) found = NULL;
4881 g_autoptr(GSList) refresh_list = NULL;
4882 int ret;
4883
4884 /* Make sure that @from doesn't go away until we have successfully attached
4885 * all of its parents to @to. */
4886 bdrv_ref(from);
4887
4888 assert(qemu_get_current_aio_context() == qemu_get_aio_context());
4889 assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to));
4890 bdrv_drained_begin(from);
4891
4882 int ret;
4883
4884 /* Make sure that @from doesn't go away until we have successfully attached
4885 * all of its parents to @to. */
4886 bdrv_ref(from);
4887
4888 assert(qemu_get_current_aio_context() == qemu_get_aio_context());
4889 assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to));
4890 bdrv_drained_begin(from);
4891
4892 /* Put all parents into @list and calculate their cumulative permissions */
4892 /*
4893 * Do the replacement without permission update.
4894 * Replacement may influence the permissions, we should calculate new
4895 * permissions based on new graph. If we fail, we'll roll-back the
4896 * replacement.
4897 */
4893 QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
4894 assert(c->bs == from);
4895 if (!should_update_child(c, to)) {
4896 if (auto_skip) {
4897 continue;
4898 }
4899 ret = -EINVAL;
4900 error_setg(errp, "Should not change '%s' link to '%s'",
4901 c->name, from->node_name);
4902 goto out;
4903 }
4904 if (c->frozen) {
4905 ret = -EPERM;
4906 error_setg(errp, "Cannot change '%s' link to '%s'",
4907 c->name, from->node_name);
4908 goto out;
4909 }
4898 QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
4899 assert(c->bs == from);
4900 if (!should_update_child(c, to)) {
4901 if (auto_skip) {
4902 continue;
4903 }
4904 ret = -EINVAL;
4905 error_setg(errp, "Should not change '%s' link to '%s'",
4906 c->name, from->node_name);
4907 goto out;
4908 }
4909 if (c->frozen) {
4910 ret = -EPERM;
4911 error_setg(errp, "Cannot change '%s' link to '%s'",
4912 c->name, from->node_name);
4913 goto out;
4914 }
4910 list = g_slist_prepend(list, c);
4911 perm |= c->perm;
4912 shared &= c->shared_perm;
4915 bdrv_replace_child_safe(c, to, tran);
4913 }
4914
4916 }
4917
4915 /* Check whether the required permissions can be granted on @to, ignoring
4916 * all BdrvChild in @list so that they can't block themselves. */
4917 ret = bdrv_check_update_perm(to, NULL, perm, shared, list, errp);
4918 found = g_hash_table_new(NULL, NULL);
4919
4920 refresh_list = bdrv_topological_dfs(refresh_list, found, to);
4921 refresh_list = bdrv_topological_dfs(refresh_list, found, from);
4922
4923 ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp);
4918 if (ret < 0) {
4924 if (ret < 0) {
4919 bdrv_abort_perm_update(to);
4920 goto out;
4921 }
4922
4925 goto out;
4926 }
4927
4923 /* Now actually perform the change. We performed the permission check for
4924 * all elements of @list at once, so set the permissions all at once at the
4925 * very end. */
4926 for (p = list; p != NULL; p = p->next) {
4927 c = p->data;
4928
4929 bdrv_ref(to);
4930 bdrv_replace_child_noperm(c, to);
4931 bdrv_unref(from);
4932 }
4933
4934 bdrv_set_perm(to);
4935
4936 ret = 0;
4937
4938out:
4928 ret = 0;
4929
4930out:
4939 g_slist_free(list);
4931 tran_finalize(tran, ret);
4932
4940 bdrv_drained_end(from);
4941 bdrv_unref(from);
4942
4943 return ret;
4944}
4945
4946int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
4947 Error **errp)

--- 2635 unchanged lines hidden ---
4933 bdrv_drained_end(from);
4934 bdrv_unref(from);
4935
4936 return ret;
4937}
4938
4939int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
4940 Error **errp)

--- 2635 unchanged lines hidden ---