diff --git a/block.c b/block.c
index 0558525..09aada5 100644
--- a/block.c
+++ b/block.c
@@ -1038,6 +1038,73 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
     return 0;
 }
 
+static int make_snapshot(BlockDriverState *bs, int64_t total_size,
+                         const char **pfilename, BlockDriver **pdrv,
+                         Error **errp)
+{
+    const char *filename = *pfilename;
+    BlockDriver *drv = *pdrv;
+    int ret;
+    BlockDriver *bdrv_qcow2;
+    QEMUOptionParameter *create_options;
+    char backing_filename[PATH_MAX];
+    /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
+    char tmp_filename[PATH_MAX + 1];
+    Error *local_err = NULL;
+
+    assert(filename != NULL);
+    total_size &= BDRV_SECTOR_MASK;
+
+    /* if snapshot, we create a temporary backing file and open it
+       instead of opening 'filename' directly */
+
+    ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
+    if (ret < 0) {
+        goto fail;
+    }
+
+    /* Real path is meaningless for protocols */
+    if (path_has_protocol(filename)) {
+        snprintf(backing_filename, sizeof(backing_filename),
+                 "%s", filename);
+    } else if (!realpath(filename, backing_filename)) {
+        ret = -errno;
+        error_setg_errno(errp, errno, "Could not resolve path '%s'", filename);
+        goto fail;
+    }
+
+    bdrv_qcow2 = bdrv_find_format("qcow2");
+    create_options = parse_option_parameters("", bdrv_qcow2->create_options,
+                                             NULL);
+
+    set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size);
+    set_option_parameter(create_options, BLOCK_OPT_BACKING_FILE,
+                         backing_filename);
+    if (drv) {
+        set_option_parameter(create_options, BLOCK_OPT_BACKING_FMT,
+                             drv->format_name);
+    }
+
+    ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err);
+    free_option_parameters(create_options);
+    if (ret < 0) {
+        error_setg_errno(errp, -ret, "Could not create temporary overlay "
+                         "'%s': %s", tmp_filename,
+                         error_get_pretty(local_err));
+        error_free(local_err);
+        local_err = NULL;
+        goto fail;
+    }
+
+    *pfilename = tmp_filename;
+    *pdrv = bdrv_qcow2;
+    bs->is_temporary = 1;
+    return 0;
+
+fail:
+    return ret;
+}
+
 /*
  * Opens a disk image (raw, qcow2, vmdk, ...)
  *
@@ -1050,8 +1117,6 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
               int flags, BlockDriver *drv, Error **errp)
 {
     int ret;
-    /* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
-    char tmp_filename[PATH_MAX + 1];
     BlockDriverState *file = NULL;
     QDict *file_options = NULL;
     const char *drvname;
@@ -1069,73 +1134,27 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
     if (flags & BDRV_O_SNAPSHOT) {
         BlockDriverState *bs1;
         int64_t total_size;
-        BlockDriver *bdrv_qcow2;
-        QEMUOptionParameter *create_options;
-        char backing_filename[PATH_MAX];
 
         if (qdict_size(options) != 0) {
             error_setg(errp, "Can't use snapshot=on with driver-specific options");
             ret = -EINVAL;
             goto fail;
         }
-        assert(filename != NULL);
-
-        /* if snapshot, we create a temporary backing file and open it
-           instead of opening 'filename' directly */
 
-        /* if there is a backing file, use it */
-        bs1 = bdrv_new_int("", bs);
+        bs1 = bdrv_new_int("", NULL);
         ret = bdrv_open(bs1, filename, NULL, 0, drv, &local_err);
         if (ret < 0) {
             bdrv_unref(bs1);
             goto fail;
         }
-        total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
 
+        total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
         bdrv_unref(bs1);
 
-        ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
-        if (ret < 0) {
-            error_setg_errno(errp, -ret, "Could not get temporary filename");
-            goto fail;
-        }
-
-        /* Real path is meaningless for protocols */
-        if (path_has_protocol(filename)) {
-            snprintf(backing_filename, sizeof(backing_filename),
-                     "%s", filename);
-        } else if (!realpath(filename, backing_filename)) {
-            ret = -errno;
-            error_setg_errno(errp, errno, "Could not resolve path '%s'", filename);
-            goto fail;
-        }
-
-        bdrv_qcow2 = bdrv_find_format("qcow2");
-        create_options = parse_option_parameters("", bdrv_qcow2->create_options,
-                                                 NULL);
-
-        set_option_parameter_int(create_options, BLOCK_OPT_SIZE, total_size);
-        set_option_parameter(create_options, BLOCK_OPT_BACKING_FILE,
-                             backing_filename);
-        if (drv) {
-            set_option_parameter(create_options, BLOCK_OPT_BACKING_FMT,
-                drv->format_name);
-        }
-
-        ret = bdrv_create(bdrv_qcow2, tmp_filename, create_options, &local_err);
-        free_option_parameters(create_options);
+        ret = make_snapshot(bs, total_size, &filename, &drv, errp);
         if (ret < 0) {
-            error_setg_errno(errp, -ret, "Could not create temporary overlay "
-                             "'%s': %s", tmp_filename,
-                             error_get_pretty(local_err));
-            error_free(local_err);
-            local_err = NULL;
             goto fail;
         }
-
-        filename = tmp_filename;
-        drv = bdrv_qcow2;
-        bs->is_temporary = 1;
     }
 
     /* Open image file without format layer */
