diff --git a/block/quorum.c b/block/quorum.c
index ee6bc45..0217593 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -611,6 +611,192 @@ static coroutine_fn int quorum_co_flush(BlockDriverState *bs)
     return result;
 }
 
+static int quorum_parse_uint_step_next(const char *start,
+                                       const char *name,
+                                       const char separator,
+                                       unsigned long long *value,
+                                       char **next,
+                                       Error **errp)
+{
+    int ret;
+    if (start[0] == '\0') {
+        error_set(errp, QERR_MISSING_PARAMETER, name);
+        return -EINVAL;
+    }
+    ret = parse_uint(start, value, next, 10);
+    if (ret < 0) {
+        error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, "int");
+        return ret;
+    }
+    if (**next != separator) {
+        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+                      "%c separator required after %s",
+                      separator, name);
+        return -EINVAL;
+    }
+    *next += 1;
+    return 0;
+}
+
+static int quorum_parse_url(BDRVQuorumState *s, const char *url, Error **errp)
+{
+    int i, j, k, len, ret = 0;
+    char *a, *b, *names;
+    const char *start;
+    bool escape;
+
+    /* Parse the quorum: prefix */
+    if (!strstart(url, "quorum:", &start)) {
+        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+                  "Invalid quorum url");
+        return -EINVAL;
+    }
+
+    /* Get threshold */
+    ret = quorum_parse_uint_step_next(start, "threshold", '/',
+                                      &s->threshold, &a, errp);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* Get total */
+    ret = quorum_parse_uint_step_next(a, "total", ':',
+                                      &s->total, &b, errp);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (s->threshold < 1) {
+        error_set(errp, QERR_INVALID_PARAMETER_VALUE,
+                  "threshold", "value >= 1");
+        return -ERANGE;
+    }
+
+    if (s->total < 2) {
+        error_set(errp, QERR_INVALID_PARAMETER_VALUE, "total", "value >= 2");
+        return -ERANGE;
+    }
+
+    if (s->threshold > s->total) {
+        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+                  "threshold <= total must be true");
+        return -ERANGE;
+    }
+
+    s->bs = g_malloc0(sizeof(BlockDriverState *) * s->total);
+    /* Two allocations for all filenames: simpler to free */
+    s->filenames = g_malloc0(sizeof(char *) * s->total);
+    names = g_strdup(b);
+
+    /* Get the filenames pointers */
+    escape = false;
+    s->filenames[0] = names;
+    len = strlen(names);
+    for (i = j = k = 0; i < len && j < s->total; i++) {
+        /* separation between two files */
+        if (!escape && names[i] == ':') {
+            char *prev = s->filenames[j];
+            prev[k] = '\0';
+            s->filenames[++j] = prev + k + 1;
+            k = 0;
+            continue;
+        }
+
+        escape = !escape && names[i] == '\\';
+
+        /* if we are not escaping copy */
+        if (!escape) {
+            s->filenames[j][k++] = names[i];
+        }
+    }
+    /* terminate last string */
+    s->filenames[j][k] = '\0';
+
+    return j + 1;
+}
+
+static int quorum_validate_url(BDRVQuorumState *s, int ret, Error **errp)
+{
+    if (ret == s->total) {
+        return 0;
+    }
+
+    error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+              "Number of provided file must be equal to total");
+    return -EINVAL;
+}
+
+static void quorum_free(BDRVQuorumState *s)
+{
+    g_free(s->filenames[0]);
+    g_free(s->filenames);
+    s->filenames = NULL;
+    g_free(s->bs);
+}
+
+static bool quorum_are_states_compatibles(BDRVQuorumState *a,
+                                          BDRVQuorumState *b,
+                                          Error **errp)
+{
+    if (a->threshold != b->threshold) {
+        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+                  "Theshold must be the same as previously");
+        return false;
+    }
+
+    if (a->total != b->total) {
+        error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+                  "Total must be the same as previously");
+        return false;
+    }
+
+    return true;
+
+}
+
+static void quorum_snapshot_img_create(BlockDriverState *bs,
+                                       const char *filename, const char *fmt,
+                                       const char *base_filename,
+                                       const char *base_fmt,
+                                       char *options, uint64_t img_size,
+                                       int flags, Error **errp)
+{
+    BDRVQuorumState *s = bs->opaque;
+    int i;
+    int ret = 0;
+    bool compatible;
+    BDRVQuorumState new_s;
+
+    memset(&new_s, 0, sizeof(BDRVQuorumState));
+
+    ret = quorum_parse_url(&new_s, filename, errp);
+    if (ret < 0) {
+        return;
+    }
+
+    ret = quorum_validate_url(&new_s, ret, errp);
+    if (ret < 0) {
+        goto free_new_s_exit;
+    }
+
+    compatible = quorum_are_states_compatibles(s, &new_s, errp);
+    if (!compatible) {
+        goto free_new_s_exit;
+    }
+
+    for (i = 0; i < new_s.total; i++) {
+        bdrv_img_create(new_s.filenames[i], fmt,
+                        s->filenames[i], s->bs[i]->drv->format_name,
+                        options, img_size, flags, errp);
+        if (error_is_set(errp)) {
+            break;
+        }
+    }
+
+free_new_s_exit:
+    quorum_free(&new_s);
+}
+
 static BlockDriver bdrv_quorum = {
     .format_name        = "quorum",
     .protocol_name      = "quorum",
@@ -625,6 +811,8 @@ static BlockDriver bdrv_quorum = {
     .bdrv_aio_writev    = quorum_aio_writev,
     .bdrv_invalidate_cache = quorum_invalidate_cache,
     .bdrv_co_is_allocated  = quorum_co_is_allocated,
+
+    .bdrv_ext_snapshot_img_create = quorum_snapshot_img_create,
 };
 
 static void bdrv_quorum_init(void)
