diff --git a/block.c b/block.c
index 0ce9b61c978674ffd76bbab5e7443ce76a851f57..14810e042676e8d8aff1610b8eeadf421424645f 100644
--- a/block.c
+++ b/block.c
@@ -2571,6 +2571,7 @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
 BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
                                   const char *child_name,
                                   const BdrvChildClass *child_class,
+                                  BdrvChildRole child_role,
                                   AioContext *ctx,
                                   uint64_t perm, uint64_t shared_perm,
                                   void *opaque, Error **errp)
@@ -2592,6 +2593,7 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
         .bs             = NULL,
         .name           = g_strdup(child_name),
         .klass          = child_class,
+        .role           = child_role,
         .perm           = perm,
         .shared_perm    = shared_perm,
         .opaque         = opaque,
@@ -2644,6 +2646,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
                              BlockDriverState *child_bs,
                              const char *child_name,
                              const BdrvChildClass *child_class,
+                             BdrvChildRole child_role,
                              Error **errp)
 {
     BdrvChild *child;
@@ -2656,7 +2659,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
                     perm, shared_perm, &perm, &shared_perm);
 
     child = bdrv_root_attach_child(child_bs, child_name, child_class,
-                                   bdrv_get_aio_context(parent_bs),
+                                   child_role, bdrv_get_aio_context(parent_bs),
                                    perm, shared_perm, parent_bs, errp);
     if (child == NULL) {
         return NULL;
@@ -2774,7 +2777,7 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
     }
 
     bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing,
-                                    errp);
+                                    0, errp);
     /* If backing_hd was already part of bs's backing chain, and
      * inherits_from pointed recursively to bs then let's update it to
      * point directly to bs (else it will become NULL). */
@@ -2965,6 +2968,7 @@ BdrvChild *bdrv_open_child(const char *filename,
                            QDict *options, const char *bdref_key,
                            BlockDriverState *parent,
                            const BdrvChildClass *child_class,
+                           BdrvChildRole child_role,
                            bool allow_none, Error **errp)
 {
     BlockDriverState *bs;
@@ -2975,7 +2979,8 @@ BdrvChild *bdrv_open_child(const char *filename,
         return NULL;
     }
 
-    return bdrv_attach_child(parent, bs, bdref_key, child_class, errp);
+    return bdrv_attach_child(parent, bs, bdref_key, child_class, child_role,
+                             errp);
 }
 
 /*
diff --git a/block/backup-top.c b/block/backup-top.c
index 282845a410319a3f5937fcf07b4c32dead1da520..f891dd7838ad3026aae219de7bff93c5de05d101 100644
--- a/block/backup-top.c
+++ b/block/backup-top.c
@@ -214,7 +214,8 @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
              source->supported_zero_flags);
 
     bdrv_ref(target);
-    state->target = bdrv_attach_child(top, target, "target", &child_file, errp);
+    state->target = bdrv_attach_child(top, target, "target", &child_file, 0,
+                                      errp);
     if (!state->target) {
         bdrv_unref(target);
         bdrv_unref(top);
diff --git a/block/blkdebug.c b/block/blkdebug.c
index f369d54ee4247d6ab97dd83c9fa82aa308eae87c..c91e78d5c876bd1434816a1724f8f3ef471e9e4b 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -497,7 +497,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
 
     /* Open the image file */
     bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
-                               bs, &child_file, false, &local_err);
+                               bs, &child_file, 0, false, &local_err);
     if (local_err) {
         ret = -EINVAL;
         error_propagate(errp, local_err);
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
index f3b3259d8d3b96766a297f2d584278212909cf1a..739db6dcf684b57a6577d7aeadef53c788642523 100644
--- a/block/blklogwrites.c
+++ b/block/blklogwrites.c
@@ -157,7 +157,7 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
     }
 
     /* Open the file */
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false,
                                &local_err);
     if (local_err) {
         ret = -EINVAL;
@@ -166,8 +166,8 @@ static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags,
     }
 
     /* Open the log file */
-    s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, false,
-                                  &local_err);
+    s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, 0,
+                                  false, &local_err);
     if (local_err) {
         ret = -EINVAL;
         error_propagate(errp, local_err);
diff --git a/block/blkreplay.c b/block/blkreplay.c
index 131c9e84770cd45d72f9211e968e255bf939889d..9b2814fc5885b514c77f2c0073d34f7122c7aebb 100644
--- a/block/blkreplay.c
+++ b/block/blkreplay.c
@@ -28,7 +28,7 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
 
     /* Open the image file */
     bs->file = bdrv_open_child(NULL, options, "image",
-                               bs, &child_file, false, &local_err);
+                               bs, &child_file, 0, false, &local_err);
     if (local_err) {
         ret = -EINVAL;
         error_propagate(errp, local_err);
diff --git a/block/blkverify.c b/block/blkverify.c
index ba6b1853ae382aaa2aef996e6aff8f0f05932210..ba4f6d7b7c30de16c2e31a10d6e9699aa8d73d98 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -125,7 +125,7 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
 
     /* Open the raw file */
     bs->file = bdrv_open_child(qemu_opt_get(opts, "x-raw"), options, "raw",
-                               bs, &child_file, false, &local_err);
+                               bs, &child_file, 0, false, &local_err);
     if (local_err) {
         ret = -EINVAL;
         error_propagate(errp, local_err);
@@ -134,7 +134,7 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
 
     /* Open the test file */
     s->test_file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options,
-                                   "test", bs, &child_format, false,
+                                   "test", bs, &child_format, 0, false,
                                    &local_err);
     if (local_err) {
         ret = -EINVAL;
diff --git a/block/block-backend.c b/block/block-backend.c
index c0af79147ae45153bfb5a936db2aa7c62145ef27..efc7acb3d85e14d696a673cd011381d4103b4eb5 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -423,7 +423,7 @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
         return NULL;
     }
 
-    blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
+    blk->root = bdrv_root_attach_child(bs, "root", &child_root, 0, blk->ctx,
                                        perm, BLK_PERM_ALL, blk, errp);
     if (!blk->root) {
         blk_unref(blk);
@@ -834,7 +834,7 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
 {
     ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
     bdrv_ref(bs);
-    blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->ctx,
+    blk->root = bdrv_root_attach_child(bs, "root", &child_root, 0, blk->ctx,
                                        blk->perm, blk->shared_perm, blk, errp);
     if (blk->root == NULL) {
         return -EPERM;
diff --git a/block/bochs.c b/block/bochs.c
index e7bbeaa1c45d27b34fb3de9aeee08dcc3641e0c3..b013e7306307dea27d294fb78ca3851c5641f3c4 100644
--- a/block/bochs.c
+++ b/block/bochs.c
@@ -110,7 +110,7 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
         return ret;
     }
 
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0,
                                false, errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/cloop.c b/block/cloop.c
index f90f1a4b4c865e9b71f5bbb66b8487197d46c13d..3ed9fa63cc14f242ba5919154516b7c5aad377df 100644
--- a/block/cloop.c
+++ b/block/cloop.c
@@ -71,7 +71,7 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
         return ret;
     }
 
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0,
                                false, errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
index 7504ca6ffce38aa603c80ecc70df762c9d77a9fd..a2c4e6dc5802ecf96c67ce951f758701890e0b59 100644
--- a/block/copy-on-read.c
+++ b/block/copy-on-read.c
@@ -28,7 +28,7 @@
 static int cor_open(BlockDriverState *bs, QDict *options, int flags,
                     Error **errp)
 {
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false,
                                errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/crypto.c b/block/crypto.c
index bdb2b27475d64bfe68d301f589761a9b8de91046..8b516bfee22737ce182e4b5e9bb7ad7f9a1b6de7 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -218,7 +218,7 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
     unsigned int cflags = 0;
     QDict *cryptoopts = NULL;
 
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0,
                                false, errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/dmg.c b/block/dmg.c
index ef3c6e771d766f245af5d4f1d65edb006efef3af..af8188638c093b16f2e28b309c9fb022d78f7a7d 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -439,7 +439,7 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
         return ret;
     }
 
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0,
                                false, errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/filter-compress.c b/block/filter-compress.c
index 82c315b298f343cf79bbe3d9ea8a69286aafa94c..4dc5f9fb8c4ca869d11aa1533e6191647fdead42 100644
--- a/block/filter-compress.c
+++ b/block/filter-compress.c
@@ -30,7 +30,7 @@
 static int compress_open(BlockDriverState *bs, QDict *options, int flags,
                          Error **errp)
 {
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0, false,
                                errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/parallels.c b/block/parallels.c
index bd5f6ffa09aa8e0a5aec2304623c969622e41714..9855ac1162129e317d6259b36dee89c62e793fb0 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -739,7 +739,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
     Error *local_err = NULL;
     char *buf;
 
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0,
                                false, errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/qcow.c b/block/qcow.c
index 6a72dea049e391eb7f9f331f39f44f1136374092..13583f033960bc32184294f8300ce84cc35cd232 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -130,7 +130,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
     qdict_extract_subqdict(options, &encryptopts, "encrypt.");
     encryptfmt = qdict_get_try_str(encryptopts, "format");
 
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0,
                                false, errp);
     if (!bs->file) {
         ret = -EINVAL;
diff --git a/block/qcow2.c b/block/qcow2.c
index 76bec61ee94075353512b34efeb8a4773511fc63..86335d9403af8920630f2b8896c3d18f18a73f26 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1591,7 +1591,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
 
     /* Open external data file */
     s->data_file = bdrv_open_child(NULL, options, "data-file", bs, &child_file,
-                                   true, &local_err);
+                                   0, true, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         ret = -EINVAL;
@@ -1601,7 +1601,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
     if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
         if (!s->data_file && s->image_data_file) {
             s->data_file = bdrv_open_child(s->image_data_file, options,
-                                           "data-file", bs, &child_file,
+                                           "data-file", bs, &child_file, 0,
                                            false, errp);
             if (!s->data_file) {
                 ret = -EINVAL;
@@ -1863,7 +1863,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
         .ret = -EINPROGRESS
     };
 
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0,
                                false, errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/qed.c b/block/qed.c
index 337eb6dbb6b7b24502fce1fd29b6a494318789f1..1ad2aba810ece0e31b9f636f397aad6dc8008033 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -547,7 +547,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
         .ret = -EINPROGRESS
     };
 
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0,
                                false, errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/quorum.c b/block/quorum.c
index a0824c300d8a02d7a8f5809bdcd5cbf72eabc847..024de76e6f14cdd9ff479263f2e95aa30145ec78 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -977,7 +977,7 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
         assert(ret < 32);
 
         s->children[i] = bdrv_open_child(NULL, options, indexstr, bs,
-                                         &child_format, false, &local_err);
+                                         &child_format, 0, false, &local_err);
         if (local_err) {
             ret = -EINVAL;
             goto close_exit;
@@ -1053,7 +1053,7 @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
     /* We can safely add the child now */
     bdrv_ref(child_bs);
 
-    child = bdrv_attach_child(bs, child_bs, indexstr, &child_format, errp);
+    child = bdrv_attach_child(bs, child_bs, indexstr, &child_format, 0, errp);
     if (child == NULL) {
         s->next_child_index--;
         goto out;
diff --git a/block/raw-format.c b/block/raw-format.c
index 00e13bb41e769a0d4fde6d794847b4f908adfe38..4b8d4ce8beb17f2e2f6001e7af50126ed499a8a4 100644
--- a/block/raw-format.c
+++ b/block/raw-format.c
@@ -428,7 +428,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
     BDRVRawState *s = bs->opaque;
     int ret;
 
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0,
                                false, errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/replication.c b/block/replication.c
index af428c5b66ea17407713917010a390554d5cd7ed..052c7ef6011b7df42a97ef562bbefe6743fbd079 100644
--- a/block/replication.c
+++ b/block/replication.c
@@ -90,7 +90,7 @@ static int replication_open(BlockDriverState *bs, QDict *options,
     const char *mode;
     const char *top_id;
 
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0,
                                false, errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/throttle.c b/block/throttle.c
index 71f4bb0ad127ec34db8a0dd943b50a38f624cebc..2dea913be78cb51dace0440ea91cc614c726672a 100644
--- a/block/throttle.c
+++ b/block/throttle.c
@@ -82,7 +82,7 @@ static int throttle_open(BlockDriverState *bs, QDict *options,
     int ret;
 
     bs->file = bdrv_open_child(NULL, options, "file", bs,
-                               &child_file, false, errp);
+                               &child_file, 0, false, errp);
     if (!bs->file) {
         return -EINVAL;
     }
diff --git a/block/vdi.c b/block/vdi.c
index 0ef733ae190c24fd55b730bd3f609a0d52874041..653acb5fc1f8cbb2acd6cc7f2e3002f08e7f3f5b 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -378,7 +378,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
     Error *local_err = NULL;
     QemuUUID uuid_link, uuid_parent;
 
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0,
                                false, errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/vhdx.c b/block/vhdx.c
index e692cf80ccae2cad03305392a2bf0171a78d4ad8..dde156c97bd095db811b19485e352cb534238552 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -996,7 +996,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
     uint64_t signature;
     Error *local_err = NULL;
 
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0,
                                false, errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/vmdk.c b/block/vmdk.c
index 56e85689f3fe1153a8e4e07888d262a070a7d678..c2cb741e2db1cd8f71afa7003b9515f134443796 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1152,7 +1152,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
         assert(ret < 32);
 
         extent_file = bdrv_open_child(extent_path, options, extent_opt_prefix,
-                                      bs, &child_file, false, &local_err);
+                                      bs, &child_file, 0, false, &local_err);
         g_free(extent_path);
         if (local_err) {
             error_propagate(errp, local_err);
@@ -1257,7 +1257,7 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
     uint32_t magic;
     Error *local_err = NULL;
 
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0,
                                false, errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/vpc.c b/block/vpc.c
index 46a2d48659857f9d8a69b5bb8a4ec24ace47c280..b2a86074a5eb1674709dada7673b3720e403bb1c 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -228,7 +228,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
     int ret;
     int64_t bs_size;
 
-    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
+    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 0,
                                false, errp);
     if (!bs->file) {
         return -EINVAL;
diff --git a/block/vvfat.c b/block/vvfat.c
index f845d9b485aac1d1334bd43a0c5a1e4fbadc5bbe..cd8ae50a2cbd27d94d78076b395b49db9ae445f1 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -3183,7 +3183,7 @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
     options = qdict_new();
     qdict_put_str(options, "write-target.driver", "qcow");
     s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
-                              &child_vvfat_qcow, false, errp);
+                              &child_vvfat_qcow, 0, false, errp);
     qobject_unref(options);
     if (!s->qcow) {
         ret = -EINVAL;
diff --git a/blockjob.c b/blockjob.c
index be38c8c550f2da214a1d7a2b24b267b20d0acafd..470facfd47a08b3c084796cc64e7521774a3175b 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -217,8 +217,9 @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
     if (job->job.aio_context != qemu_get_aio_context()) {
         aio_context_release(job->job.aio_context);
     }
-    c = bdrv_root_attach_child(bs, name, &child_job, job->job.aio_context,
-                               perm, shared_perm, job, errp);
+    c = bdrv_root_attach_child(bs, name, &child_job, 0,
+                               job->job.aio_context, perm, shared_perm, job,
+                               errp);
     if (job->job.aio_context != qemu_get_aio_context()) {
         aio_context_acquire(job->job.aio_context);
     }
diff --git a/include/block/block.h b/include/block/block.h
index 35f1a1cecf10025637f6ad6ccc746cceffa07285..25e299605e19231b38449d090cc46d7b84b4d6ec 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -353,6 +353,7 @@ BdrvChild *bdrv_open_child(const char *filename,
                            QDict *options, const char *bdref_key,
                            BlockDriverState* parent,
                            const BdrvChildClass *child_class,
+                           BdrvChildRole child_role,
                            bool allow_none, Error **errp);
 BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp);
 void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
@@ -598,6 +599,7 @@ BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
                              BlockDriverState *child_bs,
                              const char *child_name,
                              const BdrvChildClass *child_class,
+                             BdrvChildRole child_role,
                              Error **errp);
 
 bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 9a78b981e4863a2f055b057ebd30ff5910238343..1c6641c17aa08310f49e5464f1453e0037512b0c 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -746,6 +746,7 @@ struct BdrvChild {
     BlockDriverState *bs;
     char *name;
     const BdrvChildClass *klass;
+    BdrvChildRole role;
     void *opaque;
 
     /**
@@ -1233,6 +1234,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
 BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
                                   const char *child_name,
                                   const BdrvChildClass *child_class,
+                                  BdrvChildRole child_role,
                                   AioContext *ctx,
                                   uint64_t perm, uint64_t shared_perm,
                                   void *opaque, Error **errp);
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
index 9d683a6c11d2efb88b3c4c8909c5da6e92c859c4..c03705ea37201929f233904cedc086c7092dc816 100644
--- a/tests/test-bdrv-drain.c
+++ b/tests/test-bdrv-drain.c
@@ -1202,7 +1202,7 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
 
     null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
                         &error_abort);
-    bdrv_attach_child(bs, null_bs, "null-child", &child_file, &error_abort);
+    bdrv_attach_child(bs, null_bs, "null-child", &child_file, 0, &error_abort);
 
     /* This child will be the one to pass to requests through to, and
      * it will stall until a drain occurs */
@@ -1211,13 +1211,13 @@ static void do_test_delete_by_drain(bool detach_instead_of_delete,
     child_bs->total_sectors = 65536 >> BDRV_SECTOR_BITS;
     /* Takes our reference to child_bs */
     tts->wait_child = bdrv_attach_child(bs, child_bs, "wait-child", &child_file,
-                                        &error_abort);
+                                        0, &error_abort);
 
     /* This child is just there to be deleted
      * (for detach_instead_of_delete == true) */
     null_bs = bdrv_open("null-co://", NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
                         &error_abort);
-    bdrv_attach_child(bs, null_bs, "null-child", &child_file, &error_abort);
+    bdrv_attach_child(bs, null_bs, "null-child", &child_file, 0, &error_abort);
 
     blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
     blk_insert_bs(blk, bs, &error_abort);
@@ -1314,7 +1314,7 @@ static void detach_indirect_bh(void *opaque)
 
     bdrv_ref(data->c);
     data->child_c = bdrv_attach_child(data->parent_b, data->c, "PB-C",
-                                      &child_file, &error_abort);
+                                      &child_file, 0, &error_abort);
 }
 
 static void detach_by_parent_aio_cb(void *opaque, int ret)
@@ -1396,13 +1396,15 @@ static void test_detach_indirect(bool by_parent_cb)
     /* Set child relationships */
     bdrv_ref(b);
     bdrv_ref(a);
-    child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_file, &error_abort);
-    child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_backing, &error_abort);
+    child_b = bdrv_attach_child(parent_b, b, "PB-B", &child_file, 0,
+                                &error_abort);
+    child_a = bdrv_attach_child(parent_b, a, "PB-A", &child_backing, 0,
+                                &error_abort);
 
     bdrv_ref(a);
     bdrv_attach_child(parent_a, a, "PA-A",
                       by_parent_cb ? &child_file : &detach_by_driver_cb_class,
-                      &error_abort);
+                      0, &error_abort);
 
     g_assert_cmpint(parent_a->refcnt, ==, 1);
     g_assert_cmpint(parent_b->refcnt, ==, 1);
@@ -1813,7 +1815,7 @@ static void test_drop_intermediate_poll(void)
             /* Takes the reference to chain[i - 1] */
             chain[i]->backing = bdrv_attach_child(chain[i], chain[i - 1],
                                                   "chain", &chain_child_class,
-                                                  &error_abort);
+                                                  0, &error_abort);
         }
     }
 
@@ -2031,7 +2033,7 @@ static void do_test_replace_child_mid_drain(int old_drain_count,
 
     bdrv_ref(old_child_bs);
     parent_bs->backing = bdrv_attach_child(parent_bs, old_child_bs, "child",
-                                           &child_backing, &error_abort);
+                                           &child_backing, 0, &error_abort);
 
     for (i = 0; i < old_drain_count; i++) {
         bdrv_drained_begin(old_child_bs);
diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c
index fef42cb294ad11307a4f29bfa34a07a049c8b389..8b8c186c9f5ec3f4aeb11edf9ee27c447b563bcc 100644
--- a/tests/test-bdrv-graph-mod.c
+++ b/tests/test-bdrv-graph-mod.c
@@ -111,7 +111,7 @@ static void test_update_perm_tree(void)
 
     blk_insert_bs(root, bs, &error_abort);
 
-    bdrv_attach_child(filter, bs, "child", &child_file, &error_abort);
+    bdrv_attach_child(filter, bs, "child", &child_file, 0, &error_abort);
 
     bdrv_append(filter, bs, &local_err);
 
@@ -177,7 +177,7 @@ static void test_should_update_child(void)
     bdrv_set_backing_hd(target, bs, &error_abort);
 
     g_assert(target->backing->bs == bs);
-    bdrv_attach_child(filter, target, "target", &child_file, &error_abort);
+    bdrv_attach_child(filter, target, "target", &child_file, 0, &error_abort);
     bdrv_append(filter, bs, &error_abort);
     g_assert(target->backing->bs == bs);