[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [RFC] tools/libxl: add disk snapshot support



add internal disk snapshot support through qemu qmp, including create,
delete and list.

Signed-off-by: Bamvor Jian Zhang <bjzhang@xxxxxxxx>
---
 tools/libxl/libxl.c          |  29 ++++++++++
 tools/libxl/libxl.h          |   9 +++
 tools/libxl/libxl_internal.h |  15 +++++
 tools/libxl/libxl_qmp.c      | 132 +++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_types.idl  |  12 ++++
 tools/libxl/xl.h             |   3 +
 tools/libxl/xl_cmdimpl.c     | 114 +++++++++++++++++++++++++++++++++++++
 tools/libxl/xl_cmdtable.c    |  18 ++++++
 8 files changed, 332 insertions(+)

diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 30b0b06..76b4c65 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -5661,6 +5661,35 @@ int libxl_fd_set_cloexec(libxl_ctx *ctx, int fd, int 
cloexec)
 int libxl_fd_set_nonblock(libxl_ctx *ctx, int fd, int nonblock)
   { return fd_set_flags(ctx,fd, F_GETFL,F_SETFL,"FL", O_NONBLOCK, nonblock); }
 
+int libxl__disk_snapshot_create(libxl_ctx *ctx, int domid,
+                                libxl_snapshot *snapshot)
+{
+    int rc;
+    GC_INIT(ctx);
+    rc = libxl__qmp_disk_snapshot_internal(gc, domid, snapshot);
+    GC_FREE;
+    return rc;
+}
+
+int libxl__disk_snapshot_delete(libxl_ctx *ctx, int domid,
+                                libxl_snapshot *snapshot)
+{
+    int rc;
+    GC_INIT(ctx);
+    rc = libxl__qmp_disk_snapshot_delete_internal(gc, domid, snapshot);
+    GC_FREE;
+    return rc;
+}
+
+int libxl__disk_snapshot_list(libxl_ctx *ctx, int domid,
+                              libxl_snapshot **snapshotp)
+{
+    GC_INIT(ctx);
+    libxl__qmp_disk_snapshot_list_internal(gc, domid, snapshotp);
+    GC_FREE;
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index b2c3015..5139a01 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -1151,6 +1151,15 @@ int libxl_flask_getenforce(libxl_ctx *ctx);
 int libxl_flask_setenforce(libxl_ctx *ctx, int mode);
 int libxl_flask_loadpolicy(libxl_ctx *ctx, void *policy, uint32_t size);
 
+/* disk snapshot api
+ * support create, delete and list for internal snapshot of a single disk
+ */
+int libxl__disk_snapshot_create(libxl_ctx *ctx, int domid,
+                                libxl_snapshot *snapshot);
+int libxl__disk_snapshot_delete(libxl_ctx *ctx, int domid,
+                                libxl_snapshot *snapshot);
+int libxl__disk_snapshot_list(libxl_ctx *ctx, int domid,
+                              libxl_snapshot **snapshotp);
 /* misc */
 
 /* Each of these sets or clears the flag according to whether the
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index c2b73c4..ab73a1d 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1585,6 +1585,21 @@ _hidden int libxl__qmp_set_global_dirty_log(libxl__gc 
*gc, int domid, bool enabl
 _hidden int libxl__qmp_insert_cdrom(libxl__gc *gc, int domid, const 
libxl_device_disk *disk);
 /* Add a virtual CPU */
 _hidden int libxl__qmp_cpu_add(libxl__gc *gc, int domid, int index);
+/* disk internal snapshot */
+int libxl__qmp_disk_snapshot_internal(libxl__gc *gc, int domid,
+                                      libxl_snapshot *snapshot);
+/* caller should ensure that the id and name at lease exist one and only exist
+ * one. */
+int libxl__qmp_disk_snapshot_delete_internal(libxl__gc *gc, int domid,
+                                             libxl_snapshot *snapshot);
+int libxl__qmp_disk_snapshot_list_internal(libxl__gc *gc, int domid,
+                                           libxl_snapshot **snapshotp);
+/* tranaction operation for disk snapshot: support internal and external
+ * snapshot */
+int libxl__qmp_disk_snapshot_transaction(libxl__gc *gc, int domid,
+                                         libxl_snapshot *snapshot, int nb);
+/* run and get qmp result */
+int libxl__qmp_test(libxl__gc *gc, int domid, const char* command);
 /* close and free the QMP handler */
 _hidden void libxl__qmp_close(libxl__qmp_handler *qmp);
 /* remove the socket file, if the file has already been removed,
diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c
index 8433e42..5f7cbf4 100644
--- a/tools/libxl/libxl_qmp.c
+++ b/tools/libxl/libxl_qmp.c
@@ -939,6 +939,138 @@ int libxl__qmp_cpu_add(libxl__gc *gc, int domid, int idx)
     return qmp_run_command(gc, domid, "cpu-add", args, NULL, NULL);
 }
 
+int libxl__qmp_disk_snapshot_transaction(libxl__gc *gc, int domid,
+                                         libxl_snapshot *snapshot, int nb)
+{
+    libxl__json_object *args = NULL;
+    libxl__json_object *types = NULL;
+    libxl__json_object **type = NULL;
+    libxl__json_object **device = NULL;
+    int i;
+
+    type = (libxl__json_object**)calloc(nb, sizeof(libxl__json_object*));
+    device = (libxl__json_object**)calloc(nb, sizeof(libxl__json_object*));
+    types = libxl__json_object_alloc(gc, JSON_ARRAY);
+    for ( i = 0; i < nb; i++ ) {
+        qmp_parameters_add_string(gc, &type[i], "type",
+                                  "blockdev-snapshot-internal-sync");
+        qmp_parameters_add_string(gc, &device[i], "device", 
snapshot[i].device);
+        qmp_parameters_add_string(gc, &device[i], "name", snapshot[i].name);
+        qmp_parameters_common_add(gc, &type[i], "data", device[i]);
+        flexarray_append(types->u.array, (void*)type[i]);
+    }
+    qmp_parameters_common_add(gc, &args, "actions", types);
+    return qmp_run_command(gc, domid, "transaction", args, NULL, NULL);
+}
+
+int libxl__qmp_disk_snapshot_internal(libxl__gc *gc, int domid,
+                                      libxl_snapshot *snapshot)
+{
+    return libxl__qmp_disk_snapshot_transaction(gc, domid, snapshot, 1);
+}
+
+static int qmp_disk_snapshot_list_internal_callback(libxl__qmp_handler *qmp,
+                                                    const libxl__json_object 
*response,
+                                                    void *opaque)
+{
+    const libxl__json_object *obj = NULL;
+    const libxl__json_object *label = NULL;
+    const libxl__json_object *insert_dev = NULL;
+    const libxl__json_object *image = NULL;
+    const libxl__json_object *snapshot_array = NULL;
+    const libxl__json_object *snapshot_node = NULL;
+    int i = 0;
+    int j = 0;
+    libxl_snapshot **snapshotp = (libxl_snapshot**)opaque;
+    char *device = strdup((*snapshotp)[0].device);
+    libxl_snapshot *snapshot;
+    int count;
+
+    for (i = 0; (obj = libxl__json_array_get(response, i)); i++) {
+        if (!libxl__json_object_is_map(obj))
+            continue;
+
+        label = libxl__json_map_get("device", obj, JSON_STRING);
+        if ( strcmp(libxl__json_object_get_string(label), device) )
+            continue;
+
+        insert_dev = libxl__json_map_get("inserted", obj, JSON_MAP);
+        if ( insert_dev == NULL ) {
+            goto not_found;
+        }
+
+        image = libxl__json_map_get("image", insert_dev, JSON_MAP);
+        if ( image == NULL ) {
+            goto not_found;
+        }
+
+        snapshot_array = libxl__json_map_get("snapshots", image, JSON_ARRAY);
+        if ( snapshot_array == NULL ) {
+            goto not_found;
+        }
+
+        count = libxl__json_object_get_array(snapshot_array)->count;
+        *snapshotp = realloc(*snapshotp, sizeof(libxl_snapshot)*(count + 1));
+        memset(*snapshotp, 0, sizeof(libxl_snapshot)*(count + 1));
+        for ( j = 0; j < count; j++ ) {
+            snapshot_node = libxl__json_array_get(snapshot_array, j);
+            snapshot = &(*snapshotp)[j];
+            snapshot->device = strdup(device);
+            label = libxl__json_map_get("id", snapshot_node, JSON_STRING);
+            snapshot->id = strdup(libxl__json_object_get_string(label));
+            label = libxl__json_map_get("name", snapshot_node, JSON_STRING);
+            snapshot->name = strdup(libxl__json_object_get_string(label));
+            label = libxl__json_map_get("vm-state-size", snapshot_node,
+                                        JSON_INTEGER);
+            snapshot->vm_state_size = libxl__json_object_get_integer(label);
+            label = libxl__json_map_get("date-sec", snapshot_node,
+                                        JSON_INTEGER);
+            snapshot->date_sec = libxl__json_object_get_integer(label);
+            label = libxl__json_map_get("date-nsec", snapshot_node,
+                                        JSON_INTEGER);
+            snapshot->date_nsec = libxl__json_object_get_integer(label);
+            label = libxl__json_map_get("vm-clock-sec", snapshot_node,
+                                        JSON_INTEGER);
+            snapshot->vm_clock_sec = libxl__json_object_get_integer(label);
+            label = libxl__json_map_get("vm-clock-nsec", snapshot_node,
+                                        JSON_INTEGER);
+            snapshot->vm_clock_nsec = libxl__json_object_get_integer(label);
+        }
+        goto found;
+    }
+not_found:
+    free((*snapshotp)[0].device);
+    (*snapshotp)[0].device = NULL;
+found:
+    free(device);
+    return 0;
+}
+
+int libxl__qmp_disk_snapshot_delete_internal(libxl__gc *gc, int domid,
+                                             libxl_snapshot *snapshot)
+{
+    libxl__json_object *args = NULL;
+
+    qmp_parameters_add_string(gc, &args, "device", snapshot->device);
+    if (snapshot->id)
+        qmp_parameters_add_string(gc, &args, "id", snapshot->id);
+    else if (snapshot->name)
+        qmp_parameters_add_string(gc, &args, "name", snapshot->name);
+    else
+        return -1;
+
+    return qmp_run_command(gc, domid, "blockdev-snapshot-delete-internal-sync",
+                           args, NULL, NULL);
+}
+
+
+int libxl__qmp_disk_snapshot_list_internal(libxl__gc *gc, int domid,
+                                          libxl_snapshot **snapshotp)
+{
+    return qmp_run_command(gc, domid, "query-block", NULL,
+                           qmp_disk_snapshot_list_internal_callback, 
snapshotp);
+}
+
 int libxl__qmp_initializations(libxl__gc *gc, uint32_t domid,
                                const libxl_domain_config *guest_config)
 {
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 612645c..ca4bf36 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -598,3 +598,15 @@ libxl_event = Struct("event",[
                                  ])),
            ("domain_create_console_available", Struct(None, [])),
            ]))])
+
+libxl_snapshot = Struct("snapshot",[
+    ("device",        string),
+    ("name",          string),
+    ("id",            string),
+    ("vm_state_size", uint64),
+    ("date_sec",      uint64),
+    ("date_nsec",     uint64),
+    ("vm_clock_sec",  uint64),
+    ("vm_clock_nsec", uint64),
+    ])
+
diff --git a/tools/libxl/xl.h b/tools/libxl/xl.h
index 10a2e66..d3894c0 100644
--- a/tools/libxl/xl.h
+++ b/tools/libxl/xl.h
@@ -110,6 +110,9 @@ int main_loadpolicy(int argc, char **argv);
 int main_remus(int argc, char **argv);
 #endif
 int main_devd(int argc, char **argv);
+int main_disk_snapshot_create(int argc, char **argv);
+int main_disk_snapshot_delete(int argc, char **argv);
+int main_disk_snapshot_list(int argc, char **argv);
 
 void help(const char *command);
 
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index 8389468..215270e 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -7381,6 +7381,120 @@ out:
     return ret;
 }
 
+int main_disk_snapshot_create(int argc, char **argv) {
+    uint32_t domid;
+    int opt;
+    int rc = 0;
+    libxl_snapshot snapshot;
+    struct timeval timeval;
+
+    memset(&snapshot, 0, sizeof(libxl_snapshot));
+    SWITCH_FOREACH_OPT(opt, "n:", NULL, "disk-snapshot-create", 2) {
+    case 'n':
+        snapshot.name = strdup(optarg);
+        break;
+    }
+
+    if ( !snapshot.name ) {
+        snapshot.name = (char*)malloc(sizeof(time_t) * 8 + 1);
+        gettimeofday(&timeval, NULL);
+        sprintf(snapshot.name, "%ld", timeval.tv_sec);
+    }
+
+    if ( argc - optind != 2 ) {
+        fprintf(stderr, "no domain name and disk, exit!!!\n");
+        return -1;
+    }
+    domid = find_domain(argv[optind++]);
+    snapshot.device = strdup(argv[optind++]);
+    rc = libxl__disk_snapshot_create(ctx, domid, &snapshot);
+    libxl_snapshot_dispose(&snapshot);
+
+    return rc;
+}
+
+int main_disk_snapshot_delete(int argc, char **argv) {
+    uint32_t domid;
+    int opt;
+    int rc = 0;
+    libxl_snapshot snapshot;
+
+    memset(&snapshot, 0, sizeof(libxl_snapshot));
+    SWITCH_FOREACH_OPT(opt, "i:n:", NULL, "disk-snapshot-delete", 2) {
+    case 'i':
+        snapshot.id = strdup(optarg);
+        break;
+    case 'n':
+        snapshot.name = strdup(optarg);
+        break;
+    }
+
+    if ( snapshot.id == NULL && snapshot.name == NULL ) {
+        fprintf(stderr, "should provide id or name for deleting\n");
+        return -1;
+    }
+    domid = find_domain(argv[optind++]);
+    snapshot.device = strdup(argv[optind++]);
+    rc = libxl__disk_snapshot_delete(ctx, domid, &snapshot);
+    libxl_snapshot_dispose(&snapshot);
+
+    return rc;
+}
+
+int main_disk_snapshot_list(int argc, char **argv) {
+    uint32_t domid;
+    int opt;
+    libxl_snapshot *snapshot;
+    int rc = 0;
+    int i = 0;
+    struct tm *tm;
+    time_t time;
+
+    SWITCH_FOREACH_OPT(opt, "", NULL, "disk-snapshot-list", 2) {
+        /* No options */
+    }
+
+    snapshot = (libxl_snapshot*)malloc(sizeof(libxl_snapshot));
+    memset(snapshot, 0, sizeof(libxl_snapshot));
+    domid = find_domain(argv[optind++]);
+    snapshot[0].device = strdup(argv[optind++]);
+
+    rc = libxl__disk_snapshot_list(ctx, domid, &snapshot);
+    if (snapshot[0].device == NULL ) {
+        fprintf(stderr, "snapshot on this device does not exist\n");
+        rc = -1;
+        goto error;
+    }
+    if (snapshot[0].name == NULL && snapshot[0].id == NULL ) {
+        fprintf(stderr, "no this device: %s\n", snapshot[0].device);
+        rc = -1;
+        goto error;
+    }
+    printf("Snapshot list:\n");
+    printf("ID        TAG                 VM SIZE                DATE"
+            "       VM CLOCK\n");
+    while(snapshot[i].name != NULL && snapshot[i].id != NULL ) {
+        printf("%-10s", snapshot[i].id);
+        printf("%-20s", snapshot[i].name);
+        printf("%7lu", snapshot[i].vm_state_size);
+        time = (time_t)snapshot[i].date_sec;
+        tm = gmtime(&time);
+        printf(" %04d-%02d-%02d %02d:%02d:%02d", tm->tm_year + 1900, 
tm->tm_mon + 1,
+                tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+        printf("   %02lu:%02lu:%02lu.%03lu\n", snapshot[i].vm_clock_sec / 3600,
+                snapshot[i].vm_clock_sec / 60, snapshot[i].vm_clock_sec % 60,
+                snapshot[i].vm_clock_nsec / 1000000);
+        libxl_snapshot_dispose(&snapshot[i]);
+        i++;
+    }
+    goto exit;
+error:
+    libxl_snapshot_dispose(&snapshot[0]);
+exit:
+    free(snapshot);
+    return rc;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/xl_cmdtable.c b/tools/libxl/xl_cmdtable.c
index e8ab93a..930da22 100644
--- a/tools/libxl/xl_cmdtable.c
+++ b/tools/libxl/xl_cmdtable.c
@@ -497,6 +497,24 @@ struct cmd_spec cmd_table[] = {
       "[options]",
       "-F                      Run in the foreground",
     },
+    { "disk-snapshot-create",
+      &main_disk_snapshot_create, 0, 1,
+      "Do domain disk snapshot create",
+      "[-n] <Domain>",
+      "  -n name                        snapshot name. if ignore, use second 
from Epoch",
+    },
+    { "disk-snapshot-delete",
+      &main_disk_snapshot_delete, 0, 1,
+      "Do domain disk snapshot delete",
+      "[-n|-i] <Domain> <device>",
+      "  -n name                        snapshot name\n"
+      "  -i id                          snapshot id",
+    },
+    { "disk-snapshot-list",
+      &main_disk_snapshot_list, 0, 1,
+      "Do domain disk snapshot list",
+      "<Domain> <device>",
+    },
 };
 
 int cmdtable_len = sizeof(cmd_table)/sizeof(struct cmd_spec);
-- 
1.8.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.