diff --git a/block.c b/block.c
index 2562424..c0415ae 100644
--- a/block.c
+++ b/block.c
@@ -3323,6 +3323,11 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
 
 static bool is_inactivated;
 
+void bdrv_set_mirror(BlockDriverState *bs, bool is_mirror_driver)
+{
+    bs->is_mirror_driver = is_mirror_driver;
+}
+
 bool bdrv_is_inactivated(void)
 {
     return is_inactivated;
@@ -3409,6 +3414,41 @@ out:
     return ret;
 }
 
+int bdrv_inactivate_without_mirror_bs(void)
+{
+    BlockDriverState *bs = NULL;
+    BdrvNextIterator it;
+    int ret = 0;
+    int pass;
+
+    for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
+         if (!bs->is_mirror_driver) {
+             aio_context_acquire(bdrv_get_aio_context(bs));
+         }
+    }
+
+    /* We do two passes of inactivation. The first pass calls to drivers'
+     * .bdrv_inactivate callbacks recursively so all cache is flushed to disk;
+     * the second pass sets the BDRV_O_INACTIVE flag so that no further write
+     * is allowed. */
+    for (pass = 0; pass < 2; pass++) {
+        for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
+             if (bs->is_mirror_driver) {
+                 /* filter the mirror bs */
+                 continue;
+             }
+
+            ret = bdrv_inactivate_recurse(bs, pass);
+            if (ret < 0) {
+                goto out;
+            }
+        }
+    }
+
+out:
+    for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
+         if (!bs->is_mirror_driver) {
+             aio_context_release(bdrv_get_aio_context(bs));
+         }
+    }
+
+    if (!ret) {
+        is_inactivated = true;
+    }
+    return ret;
+}
+
 /**************************************************************/
 /* removable device support */
 
diff --git a/blockdev.c b/blockdev.c
index 52802a0..29003f1 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3599,6 +3599,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
     if (!target_bs) {
         goto out;
     }
+    bdrv_set_mirror(target_bs, true);
 
     bdrv_set_aio_context(target_bs, aio_context);
 
diff --git a/include/block/block.h b/include/block/block.h
index 4e188c1..8f95cb4 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -327,7 +327,9 @@ int bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf);
 void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp);
 void bdrv_invalidate_cache_all(Error **errp);
 int bdrv_inactivate_all(void);
+int bdrv_inactivate_without_mirror_bs(void);
 bool bdrv_is_inactivated(void);
+void bdrv_set_mirror(BlockDriverState *bs, bool mirror);
 
 /* Ensure contents are flushed to disk.  */
 int bdrv_flush(BlockDriverState *bs);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index e6ddb93..68cb834 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -535,6 +535,7 @@ struct BlockDriverState {
     unsigned io_plugged;
 
     int quiesce_counter;
+    bool is_mirror_driver;
 };
 
 struct BlockBackendRootState {
diff --git a/migration/migration.c b/migration/migration.c
index 27575be..784346d 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -2066,7 +2066,7 @@ static void migration_completion(MigrationState *s, int current_active_state,
              * we will go into COLO stage later.
              */
             if (ret >= 0 && !migrate_colo_enabled()) {
-                ret = bdrv_inactivate_all();
+                ret = bdrv_inactivate_without_mirror_bs();
             }
             if (ret >= 0) {
                 qemu_file_set_rate_limit(s->to_dst_file, INT64_MAX);
