Device manager support for shared snapshots. Refactor status code to simplift it. Implement status and message support for multisnapshots. Implement functions for creating and deleting individual snapshots. Signed-off-by: Mikulas Patocka --- lib/activate/activate.c | 44 ++++++++++++ lib/activate/activate.h | 5 + lib/activate/dev_manager.c | 165 ++++++++++++++++++++++++++++++++++++++++++--- lib/activate/dev_manager.h | 7 + 4 files changed, 210 insertions(+), 11 deletions(-) Index: LVM2.2.02.85/lib/activate/dev_manager.c =================================================================== --- LVM2.2.02.85.orig/lib/activate/dev_manager.c 2011-05-23 16:13:29.000000000 +0200 +++ LVM2.2.02.85/lib/activate/dev_manager.c 2011-05-23 16:17:52.000000000 +0200 @@ -307,11 +307,11 @@ static const struct dm_info *_cached_inf return dinfo; } -#if 0 +#if 1 /* FIXME Interface must cope with multiple targets */ static int _status_run(const char *name, const char *uuid, unsigned long long *s, unsigned long long *l, - char **t, uint32_t t_size, char **p, uint32_t p_size) + char *t, uint32_t t_size, char *p, uint32_t p_size) { int r = 0; struct dm_task *dmt; @@ -337,13 +337,21 @@ static int _status_run(const char *name, next = dm_get_next_target(dmt, next, &start, &length, &type, ¶ms); if (type) { - *s = start; - *l = length; + if (s) + *s = start; + if (l) + *l = length; /* Make sure things are null terminated */ - strncpy(*t, type, t_size); - (*t)[t_size - 1] = '\0'; - strncpy(*p, params, p_size); - (*p)[p_size - 1] = '\0'; + if (t) { + strncpy(t, type, t_size); + if (t_size) + t[t_size - 1] = '\0'; + } + if (p) { + strncpy(p, params, p_size); + if (p_size) + p[p_size - 1] = '\0'; + } r = 1; /* FIXME Cope with multiple targets! */ @@ -359,12 +367,12 @@ static int _status_run(const char *name, static int _status(const char *name, const char *uuid, unsigned long long *start, unsigned long long *length, - char **type, uint32_t type_size, char **params, - uint32_t param_size) __attribute__ ((unused)); + char *type, uint32_t type_size, char *params, + uint32_t param_size); static int _status(const char *name, const char *uuid, unsigned long long *start, unsigned long long *length, - char **type, uint32_t type_size, char **params, + char *type, uint32_t type_size, char *params, uint32_t param_size) { if (uuid && *uuid) { @@ -760,6 +768,141 @@ int dev_manager_mirror_percent(struct de return 1; } +static int _multisnap_message(struct dev_manager *dm, const char *dlid, + const char *fmt, ...) +{ + char str[256]; + + int r; + struct dm_task *dmt; + va_list ap; + + va_start(ap, fmt); + vsnprintf(str, sizeof str, fmt, ap); + va_end(ap); + + if (strlen(str) == sizeof(str) - 1) { + log_error("_multisnap_message: too long message"); + return_0; + } + + dmt = _setup_task(NULL, dlid, NULL, DM_DEVICE_TARGET_MSG, 0, 0); + if (!dmt) + return 0; + + r = 0; + if (!dm_task_set_message(dmt, str)) + goto destroy_task; + + if (!dm_task_run(dmt)) + goto destroy_task; + + r = 1; + +destroy_task: + dm_task_destroy(dmt); + return r; +} + +static int _multisnapshot_status(struct dev_manager *dm, const char *dlid, + int *error, char **snapid, uint64_t *total, + uint64_t *allocated, uint64_t *metadata) +{ + int m; + char t[16]; + char s[1024]; + + int nargs; + + union { + char *sink_string; + int sink_int; + uint64_t sink_uint64_t; + } sink; + + if (!snapid) snapid = &sink.sink_string; + if (!error) error = &sink.sink_int; + if (!total) total = &sink.sink_uint64_t; + if (!allocated) allocated = &sink.sink_uint64_t; + if (!metadata) metadata = &sink.sink_uint64_t; + + *snapid = dm_pool_alloc(dm->mem, 1024); + if (!*snapid) { + log_error("_multisnapshot_status: pool allocation failed"); + return 0; + } + + if (!_status(NULL, dlid, NULL, NULL, t, sizeof t, s, sizeof s)) + return 0; + + if (strcmp(t, "multisnapshot")) { + log_error("_multisnapshot_status: not multisnapshot target: %s", t); + return 0; + } + + m = sscanf(s, "%u %d %s %"SCNu64" %"SCNu64" %"SCNu64"", &nargs, error, *snapid, total, allocated, metadata); + if (m != 6) { + log_error("_multisnapshot_status: matched only %d entries of '%s'", m, s); + return 0; + } + + return 1; +} + +int dev_manager_multisnap_prepare_create(struct dev_manager *dm, + struct logical_volume *lv, + char **snapid) +{ + const char *dlid; + int err; + + if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, NULL))) { + log_error("uuid build failed for %s", lv->name); + return 0; + } + + log_debug("Getting new snapshot id for %s", lv->name); + + if (!_multisnap_message(dm, dlid, "create")) + return 0; + + if (!_multisnapshot_status(dm, dlid, &err, snapid, NULL, NULL, NULL)) + return 0; + + if (err < 0) { + log_error("%s: target reports error %s", lv->name, strerror(-err)); + return 0; + } + + *snapid = dm_pool_strdup(lv->vg->cmd->mem, *snapid); + if (!*snapid) { + log_error("dev_manager_multisnap_prepare_create: allocation failed"); + return 0; + } + + return 1; +} + +int dev_manager_multisnap_delete(struct dev_manager *dm, + struct logical_volume *lv, + const char *snapid) +{ + const char *dlid; + + if (!(dlid = build_dm_uuid(dm->mem, lv->lvid.s, NULL))) { + log_error("uuid build failed for %s", lv->name); + return 0; + } + + log_debug("Deleting snapshot id %s from %s", snapid, lv->name); + + if (!_multisnap_message(dm, dlid, "delete %s", snapid)) + return 0; + + return 1; +} + + #if 0 log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", name); Index: LVM2.2.02.85/lib/activate/activate.c =================================================================== --- LVM2.2.02.85.orig/lib/activate/activate.c 2011-05-23 16:13:29.000000000 +0200 +++ LVM2.2.02.85/lib/activate/activate.c 2011-05-23 16:21:30.000000000 +0200 @@ -211,6 +211,14 @@ int lv_activate_with_filter(struct cmd_c { return 1; } +int lv_multisnap_prepare_create(struct cmd_context *cmd, struct logical_volume *lv, char **snapid) +{ + return 0; +} +int lv_multisnap_delete(struct cmd_context *cmd, struct logical_volume *lv, const char *snapid) +{ + return 0; +} int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv) { return 1; @@ -1448,6 +1456,42 @@ int lv_activate_with_filter(struct cmd_c return 1; } +int lv_multisnap_prepare_create(struct cmd_context *cmd, struct logical_volume *lv, char **snapid) +{ + struct dev_manager *dm; + int r; + + if (!activation()) + return 0; + + if (!(dm = dev_manager_create(cmd, lv->vg->name))) + return_0; + + r = dev_manager_multisnap_prepare_create(dm, lv, snapid); + + dev_manager_destroy(dm); + + return r; +} + +int lv_multisnap_delete(struct cmd_context *cmd, struct logical_volume *lv, const char *snapid) +{ + struct dev_manager *dm; + int r; + + if (!activation()) + return 0; + + if (!(dm = dev_manager_create(cmd, lv->vg->name))) + return_0; + + r = dev_manager_multisnap_delete(dm, lv, snapid); + + dev_manager_destroy(dm); + + return r; +} + int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv) { int r = 1; Index: LVM2.2.02.85/lib/activate/activate.h =================================================================== --- LVM2.2.02.85.orig/lib/activate/activate.h 2011-05-23 16:13:29.000000000 +0200 +++ LVM2.2.02.85/lib/activate/activate.h 2011-05-23 16:17:52.000000000 +0200 @@ -63,6 +63,11 @@ int lv_activate_with_filter(struct cmd_c int exclusive); int lv_deactivate(struct cmd_context *cmd, const char *lvid_s); +int lv_multisnap_prepare_create(struct cmd_context *cmd, + struct logical_volume *lv, char **snapid); +int lv_multisnap_delete(struct cmd_context *cmd, + struct logical_volume *lv, const char *snapid); + int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv); /* Index: LVM2.2.02.85/lib/activate/dev_manager.h =================================================================== --- LVM2.2.02.85.orig/lib/activate/dev_manager.h 2011-05-23 16:13:29.000000000 +0200 +++ LVM2.2.02.85/lib/activate/dev_manager.h 2011-05-23 16:17:52.000000000 +0200 @@ -60,6 +60,13 @@ int dev_manager_transient(struct dev_man int dev_manager_mknodes(const struct logical_volume *lv); +int dev_manager_multisnap_prepare_create(struct dev_manager *dm, + struct logical_volume *lv, + char **snapid); +int dev_manager_multisnap_delete(struct dev_manager *dm, + struct logical_volume *lv, + const char *snapid); + /* * Put the desired changes into effect. */