summaryrefslogtreecommitdiffstats
path: root/xlators/mgmt/glusterd/src/glusterd-snapshot.c
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/mgmt/glusterd/src/glusterd-snapshot.c')
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-snapshot.c1015
1 files changed, 955 insertions, 60 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot.c b/xlators/mgmt/glusterd/src/glusterd-snapshot.c
index 1c1e28a86..f3428ff03 100644
--- a/xlators/mgmt/glusterd/src/glusterd-snapshot.c
+++ b/xlators/mgmt/glusterd/src/glusterd-snapshot.c
@@ -17,6 +17,7 @@
#include <unistd.h>
#include <sys/resource.h>
#include <sys/statvfs.h>
+#include <sys/mount.h>
#include "globals.h"
#include "compat.h"
@@ -38,6 +39,184 @@
#include "cli1-xdr.h"
#include "xdr-generic.h"
+#ifdef GF_LINUX_HOST_OS
+#include <mntent.h>
+#endif
+
+int
+glusterd_handle_snapshot_fn (rpcsvc_request_t *req)
+{
+ int32_t ret = 0;
+ dict_t *dict = NULL;
+ gf_cli_req cli_req = {{0},};
+ glusterd_op_t cli_op = GD_OP_SNAP;
+ int type = 0;
+ glusterd_conf_t *conf = NULL;
+ char *host_uuid = NULL;
+ char err_str[2048] = {0,};
+ xlator_t *this = NULL;
+
+ GF_ASSERT (req);
+
+ this = THIS;
+ GF_ASSERT (this);
+ conf = this->private;
+ GF_ASSERT (conf);
+
+ ret = xdr_to_generic (req->msg[0], &cli_req,
+ (xdrproc_t)xdr_gf_cli_req);
+ if (ret < 0) {
+ req->rpc_err = GARBAGE_ARGS;
+ goto out;
+ }
+
+ if (cli_req.dict.dict_len > 0) {
+ dict = dict_new ();
+ if (!dict)
+ goto out;
+
+ ret = dict_unserialize (cli_req.dict.dict_val,
+ cli_req.dict.dict_len,
+ &dict);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR, "failed to "
+ "unserialize req-buffer to dictionary");
+ snprintf (err_str, sizeof (err_str), "Unable to decode "
+ "the command");
+ goto out;
+ }
+
+ dict->extra_stdfree = cli_req.dict.dict_val;
+
+ host_uuid = gf_strdup (uuid_utoa(MY_UUID));
+ if (host_uuid == NULL) {
+ snprintf (err_str, sizeof (err_str), "Failed to get "
+ "the uuid of local glusterd");
+ ret = -1;
+ goto out;
+ }
+ ret = dict_set_dynstr (dict, "host-uuid", host_uuid);
+ if (ret)
+ goto out;
+
+ } else {
+ gf_log (this->name, GF_LOG_ERROR, "request dict length is %d",
+ cli_req.dict.dict_len);
+ goto out;
+ }
+
+ ret = dict_get_int32 (dict, "type", &type);
+ if (ret < 0) {
+ snprintf (err_str, sizeof (err_str), "Command type not found");
+ gf_log (this->name, GF_LOG_ERROR, "%s", err_str);
+ goto out;
+ }
+
+ switch (type) {
+ case GF_SNAP_OPTION_TYPE_CREATE:
+ ret = glusterd_mgmt_v3_initiate_all_phases (req, cli_op, dict);
+ break;
+ case GF_SNAP_OPTION_TYPE_LIST:
+ ret = glusterd_handle_snapshot_list (req, cli_op, dict);
+ break;
+ default:
+ gf_log (this->name, GF_LOG_ERROR, "Unkown snapshot request "
+ "type (%d)", type);
+ ret = -1; /* Failure */
+ }
+
+out:
+ if (ret) {
+ GF_FREE (host_uuid);
+ if (err_str[0] == '\0')
+ snprintf (err_str, sizeof (err_str),
+ "Operation failed");
+ ret = glusterd_op_send_cli_response (cli_op, ret, 0, req,
+ dict, err_str);
+ }
+
+ return ret;
+}
+
+int
+glusterd_handle_snapshot (rpcsvc_request_t *req)
+{
+ return glusterd_big_locked_handler (req, glusterd_handle_snapshot_fn);
+}
+
+int
+glusterd_snapshot_prevalidate (dict_t *dict, char **op_errstr,
+ dict_t *rsp_dict)
+{
+ char *volname = NULL;
+ glusterd_volinfo_t *volinfo = NULL;
+ int64_t volume_count = 0;
+ char volname_buf[PATH_MAX] = {0, };
+ int64_t i = 0;
+ int snap_command = 0;
+ xlator_t *this = NULL;
+ int ret = -1;
+
+ this = THIS;
+
+ GF_ASSERT (this);
+ GF_ASSERT (dict);
+ GF_ASSERT (rsp_dict); //not sure if this is needed, verify.
+ ret = dict_get_int32 (dict, "type", &snap_command);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "unable to get the type of "
+ "the snapshot command");
+ goto out;
+ }
+
+ switch (snap_command) {
+ case (GF_SNAP_OPTION_TYPE_CREATE):
+ {
+ ret = dict_get_int64 (dict, "volcount", &volume_count);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "failed to "
+ "get the volume count");
+ goto out;
+ }
+ for (i = 0; i < volume_count; i++) {
+ snprintf (volname_buf, sizeof (volname_buf),
+ "volname%ld", i+1);
+ ret = dict_get_str (dict, volname_buf,
+ &volname);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "failed to get volume name");
+ goto out;
+ }
+ ret = glusterd_volinfo_find (volname, &volinfo);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "failed to get the volinfo for "
+ "the volume %s", volname);
+ goto out;
+ }
+ if (glusterd_is_defrag_on (volinfo)) {
+ gf_log (this->name, GF_LOG_WARNING,
+ "rebalance process is running "
+ "for the volume %s", volname);
+ goto out;
+ }
+ //Also check whether geo replication is running
+ }
+ break;
+ }
+ default:
+ gf_log (this->name, GF_LOG_WARNING, "invalid snap command");
+ goto out;
+ break;
+ }
+
+ ret = 0;
+
+out:
+ return ret;
+}
+
glusterd_snap_t*
glusterd_new_snap_object()
{
@@ -107,7 +286,7 @@ glusterd_add_snap (glusterd_volinfo_t *volinfo, glusterd_snap_t *snap)
}
last = entry;
}
- list_add (&snap->snap_list, &last->snap_list);
+ list_add_tail (&snap->snap_list, &volinfo->snaps);
gf_log (THIS->name, GF_LOG_DEBUG, "Snap %s added @ %"PRIu64,
snap->snap_name, count);
@@ -343,7 +522,6 @@ glusterd_delete_snap_volume (glusterd_volinfo_t *volinfo,
glusterd_volinfo_t *snapinfo)
{
int ret = -1;
-
GF_ASSERT (volinfo);
ret = glusterd_store_delete_volume (volinfo, snapinfo);
@@ -1334,99 +1512,816 @@ out:
return ret;
}
+/* this should be the last thing to be done.
+ 1. Do op stage related checks such as whether volume is there or not etc
+ 2. Do quorum checks.
+ 3. Then do this and take the snapshot OR take the snapshot and build the
+ snap object (Can be decided later)
+*/
+int32_t
+glusterd_snap_create (glusterd_volinfo_t *volinfo,
+ glusterd_volinfo_t *snap_volinfo,
+ char *description, uuid_t cg_id)
+{
+ glusterd_snap_t *snap = NULL;
+ xlator_t *this = NULL;
+ glusterd_conf_t *priv = NULL;
+ int ret = -1;
+ uuid_t snap_uuid;
+
+ this = THIS;
+ priv = this->private;
+
+ if (!volinfo) {
+ gf_log (this->name, GF_LOG_ERROR, "volinfo is NULL");
+ goto out;
+ }
+
+ snap = glusterd_new_snap_object ();
+ if (!snap) {
+ gf_log (this->name, GF_LOG_ERROR, "could not create "
+ "the snap object fot the volume %s (snap: %s)",
+ volinfo->volname, snap_volinfo->volname);
+ goto out;
+ }
+
+
+ // for now ignore if description is not strduped
+ if (description)
+ snap->description = gf_strdup (description);
+ snap->time_stamp = time (NULL);
+ uuid_generate (snap_uuid);
+ uuid_copy (snap->snap_id, snap_uuid);
+ if (!uuid_is_null (cg_id))
+ uuid_copy (snap->cg_id, cg_id);
+ snap->snap_volume = snap_volinfo;
+ uuid_copy (snap_volinfo->volume_id, snap_uuid);
+ strcpy (snap->snap_name, snap_volinfo->volname);
+ //TODO: replace strcpy with strncpy
+
+ ret = glusterd_add_snap (volinfo, snap);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "could not add the snap "
+ "object %s to the snap list of the volume %s",
+ snap_volinfo->volname, volinfo->volname);
+ goto out;
+ }
+
+out:
+ if (ret) {
+ if (snap) {
+ list_del_init (&snap->snap_list);
+ LOCK_DESTROY (&snap->lock);
+ GF_FREE (snap->description);
+ GF_FREE (snap->snap_volume);
+ GF_FREE (snap);
+ }
+ }
+ return ret;
+}
+
int
-glusterd_handle_snapshot_fn (rpcsvc_request_t *req)
+glusterd_remove_snapshot (glusterd_brickinfo_t *brickinfo, char *volname,
+ char *snapname, const char *snap_device)
{
- int32_t ret = 0;
- dict_t *dict = NULL;
- gf_cli_req cli_req = {{0},};
- glusterd_op_t cli_op = GD_OP_SNAP;
- int type = 0;
- glusterd_conf_t *priv = NULL;
- char *host_uuid = NULL;
- char err_str[2048] = {0,};
- xlator_t *this = NULL;
+ int ret = -1;
+ xlator_t *this = NULL;
+ glusterd_conf_t *priv = NULL;
+ runner_t runner = {0,};
+ char msg[1024] = {0, };
- GF_ASSERT (req);
+ this = THIS;
+ priv = this->private;
+
+ if (!brickinfo) {
+ gf_log (this->name, GF_LOG_ERROR, "brickinfo NULL");
+ goto out;
+ }
+
+ snprintf (msg, sizeof(msg), "remove snapshot of the brick %s:%s, "
+ "device: %s", brickinfo->hostname, brickinfo->path,
+ snap_device);
+ runner_add_args (&runner, "/sbin/lvmremove", snap_device);
+ runner_log (&runner, "", GF_LOG_DEBUG, msg);
+
+ //let glusterd get blocked till snapshot is over
+ synclock_unlock (&priv->big_lock);
+ ret = runner_run (&runner);
+ synclock_lock (&priv->big_lock);
+
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "removing snapshot of the "
+ "brick (%s:%s) of device %s failed",
+ brickinfo->hostname, brickinfo->path, snap_device);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+int32_t
+glusterd_brick_snapshot_remove (glusterd_volinfo_t *snap_volinfo,
+ glusterd_volinfo_t *actual_volinfo, char *name)
+{
+ char *mnt_pt = NULL;
+ struct mntent *entry = NULL;
+ int32_t ret = -1;
+ glusterd_brickinfo_t *brickinfo = NULL;
+ xlator_t *this = NULL;
+ FILE *mtab = NULL;
this = THIS;
GF_ASSERT (this);
- priv = this->private;
- GF_ASSERT (priv);
- ret = xdr_to_generic (req->msg[0], &cli_req,
- (xdrproc_t)xdr_gf_cli_req);
- if (ret < 0) {
- req->rpc_err = GARBAGE_ARGS;
+ if (!snap_volinfo) {
+ gf_log (this->name, GF_LOG_ERROR, "snap volinfo is NULL");
goto out;
}
- if (cli_req.dict.dict_len) {
- dict = dict_new ();
- if (!dict)
+ if (!actual_volinfo) {
+ gf_log (this->name, GF_LOG_ERROR, "volinfo for the volume "
+ "is NULL");
+ goto out;
+ }
+
+ if (!name) {
+ gf_log (this->name, GF_LOG_ERROR, "snapname is NULL "
+ "(volume: %s)", actual_volinfo->volname);
+ goto out;
+ }
+
+ list_for_each_entry (brickinfo, &snap_volinfo->bricks, brick_list) {
+ ret = glusterd_get_brick_root (brickinfo->path, &mnt_pt);
+ if (ret)
goto out;
- ret = dict_unserialize (cli_req.dict.dict_val,
- cli_req.dict.dict_len,
- &dict);
- if (ret < 0) {
+ entry = glusterd_get_mnt_entry_info (mnt_pt, mtab);
+ if (!entry) {
+ ret = -1;
+ goto out;
+ }
+ ret = glusterd_remove_snapshot (brickinfo,
+ actual_volinfo->volname,
+ name, entry->mnt_fsname);
+ if (ret) {
gf_log (this->name, GF_LOG_ERROR, "failed to "
- "unserialize req-buffer to dictionary");
- snprintf (err_str, sizeof (err_str), "Unable to decode "
- "the command");
+ "remove the snapshot %s (%s)",
+ brickinfo->path, entry->mnt_fsname);
goto out;
- } else {
- dict->extra_stdfree = cli_req.dict.dict_val;
}
+ }
- host_uuid = gf_strdup (uuid_utoa(MY_UUID));
- if (host_uuid == NULL) {
- snprintf (err_str, sizeof (err_str), "Failed to get "
- "the uuid of local glusterd");
+ ret = 0;
+
+out:
+ if (mtab)
+ endmntent (mtab);
+ return ret;
+}
+
+/* This function is called to get the device path of the snap lvm. Usually
+ if /dev/<group-name>/<group-name>-<lvm-name> is the device for the lvm,
+ then the snap device will be /dev/<group-name>/<group-name>-<snap-name>.
+ This function takes care of building the path for the snap device.
+*/
+char *
+glusterd_build_snap_device_path (char *device, char *snapname)
+{
+ char *tmp = NULL;
+ char snap[PATH_MAX] = {0, };
+ char msg[1024] = {0, };
+ char *str = NULL;
+ int device_len = 0;
+ int tmp_len = 0;
+ int var = 0;
+ char *snap_device = NULL;
+ xlator_t *this = NULL;
+
+ this = THIS;
+ GF_ASSERT (this);
+ if (!device) {
+ gf_log (this->name, GF_LOG_ERROR, "device is NULL");
+ goto out;
+ }
+
+ device_len = strlen (device);
+
+ tmp = strrchr (device, '/');
+ if (tmp)
+ tmp++;
+ str = gf_strdup (tmp);
+ if (!str) {
+ goto out;
+ }
+
+ tmp_len = strlen (str);
+ var = device_len - tmp_len;
+ device[var] = '\0';
+ tmp = strchr (str, '-');
+ if (tmp)
+ tmp++;
+ device_len = tmp_len;
+ tmp_len = strlen (tmp);
+ var = device_len - tmp_len;
+ str[var] = '\0';
+ msg[0] = '\0';
+ strcpy (msg, str);
+ strcat (msg, snapname);
+ strcpy (snap, device);
+ strcat (snap, msg);
+ snap_device = gf_strdup (snap);
+ if (!snap_device) {
+ gf_log (this->name, GF_LOG_WARNING, "cannot copy the "
+ "snapshot device name (volname: %s, "
+ "snapname: %s)", snapname);
+ goto out;
+ }
+
+out:
+ GF_FREE (str);
+ return snap_device;
+}
+
+/* This function actually calls the command (or the API) for taking the
+ snapshot of the backend brick filesystem. If this is successful,
+ then call the glusterd_snap_create function to create the snap object
+ for glusterd
+*/
+int
+glusterd_take_snapshot (glusterd_brickinfo_t *brickinfo, char *volname,
+ char *snapname, dict_t *dict, char **snap_device)
+{
+ int ret = -1;
+ xlator_t *this = NULL;
+ glusterd_conf_t *priv = NULL;
+ runner_t runner = {0,};
+ char *device = NULL;
+ char msg[1024] = {0, };
+ char *tmp = NULL;
+
+ this = THIS;
+ priv = this->private;
+
+ if (!brickinfo) {
+ gf_log (this->name, GF_LOG_ERROR, "brickinfo NULL");
+ goto out;
+ }
+
+ device = glusterd_get_brick_mount_details (brickinfo);
+ if (!device) {
+ gf_log (this->name, GF_LOG_ERROR, "getting device name for "
+ "the brick %s:%s failed", brickinfo->hostname,
+ brickinfo->path);
+ goto out;
+ }
+
+ runinit (&runner);
+ snprintf (msg, sizeof (msg), "taking snapshot of the brick %s:%s",
+ brickinfo->hostname, brickinfo->path);
+ runner_add_args (&runner, "/sbin/lvcreate", "-s", device, "--name",
+ snapname);
+ runner_log (&runner, "", GF_LOG_DEBUG, msg);
+
+ //let glusterd get blocked till snapshot is over
+ synclock_unlock (&priv->big_lock);
+ ret = runner_run (&runner);
+ synclock_lock (&priv->big_lock);
+
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "taking snapshot of the "
+ "brick (%s:%s) of device %s failed",
+ brickinfo->hostname, brickinfo->path, device);
+ goto out;
+ }
+
+ gf_log (this->name, GF_LOG_INFO, "device: %s", device);
+ if (device) {
+ tmp = glusterd_build_snap_device_path (device, snapname);
+ *snap_device = tmp;
+ if (!*snap_device) {
+ gf_log (this->name, GF_LOG_WARNING, "cannot copy the "
+ "snapshot device name (volname: %s, "
+ "snapname: %s)", volname, snapname);
ret = -1;
goto out;
}
- ret = dict_set_dynstr (dict, "host-uuid", host_uuid);
+ }
+
+out:
+ return ret;
+}
+
+int32_t
+glusterd_snap_brick_create (char *device, glusterd_volinfo_t *snap_volinfo,
+ glusterd_brickinfo_t *original_brickinfo)
+{
+ int32_t ret = -1;
+ xlator_t *this = NULL;
+ glusterd_conf_t *priv = NULL;
+ glusterd_brickinfo_t *snap_brickinfo = NULL;
+ char snap_brick_mount_path[PATH_MAX] = {0, };
+ char *tmp = NULL;
+ char *mnt_pt = NULL;
+ struct mntent *entry = NULL;
+ FILE *mtab = NULL;
+ char msg[PATH_MAX] = {0, };
+
+ this = THIS;
+ priv = this->private;
+
+ if (!device) {
+ gf_log (this->name, GF_LOG_ERROR, "device is NULL");
+ goto out;
+ }
+
+ if (!snap_volinfo) {
+ gf_log (this->name, GF_LOG_ERROR, "snap volinfo is NULL");
+ goto out;
+ }
+
+ if (!original_brickinfo) {
+ gf_log (this->name, GF_LOG_ERROR, "original brickinfo is NULL"
+ "(snap: %s)", snap_volinfo->volname);
+ goto out;
+ }
+
+ tmp = gf_strdup (device);
+ if (!tmp) {
+ gf_log (this->name, GF_LOG_INFO, "out of memory");
+ goto out;
+ }
+
+ glusterd_replace_slash_with_hyphen (tmp);
+ if (tmp[0] == '-')
+ tmp[0] = '/';
+
+ snprintf (snap_brick_mount_path, sizeof (snap_brick_mount_path), "%s"
+ "/%s%s-brick", GLUSTERD_DEFAULT_SNAPS_BRICK_DIR,
+ snap_volinfo->volname, tmp);
+
+ ret = glusterd_get_brick_root (original_brickinfo->path, &mnt_pt);
+ if (ret)
+ goto out;
+
+ entry = glusterd_get_mnt_entry_info (mnt_pt, mtab);
+ if (!entry) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = mkdir_p (snap_brick_mount_path, 0777, _gf_true);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "creating the brick directory"
+ " %s for the snapshot %s(device: %s) failed",
+ snap_brick_mount_path, snap_volinfo->volname, device);
+ goto out;
+ }
+ /* mount the snap logical device on the directory inside
+ /var/run/gluster/snaps/<snapname>/@snap_brick_mount_path
+ */
+ ret = mount (device, snap_brick_mount_path, entry->mnt_type, MS_MGC_VAL,
+ "nouuid");
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "mounting the snapshot "
+ "logical device %s failed (error: %s)", device,
+ strerror (errno));
+ goto out;
+ }
+
+ ret = glusterd_brickinfo_new (&snap_brickinfo);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "initializing the brick for the snap "
+ "volume failed (snapname: %s)", snap_volinfo->volname);
+ goto out;
+ }
+
+ strcpy (snap_brickinfo->hostname, original_brickinfo->hostname);
+ strcpy (snap_brickinfo->path, snap_brick_mount_path);
+ LOCK (&snap_volinfo->lock);
+ {
+ list_add_tail (&snap_brickinfo->brick_list,
+ &snap_volinfo->bricks);
+ }
+ UNLOCK (&snap_volinfo->lock);
+out:
+ GF_FREE (tmp);
+ if (ret) {
+ umount (snap_brick_mount_path);
+ if (snap_brickinfo)
+ glusterd_brickinfo_delete (snap_brickinfo);
+ }
+ if (mtab)
+ endmntent (mtab);
+ return ret;
+}
+
+/* TODO: lvm uses '-' as the delimter for differentiating the logical volume
+ name and the volume group name. So as of now, if the snapname given from
+ cli contains '-', it confuses lvm. Handle it.
+*/
+int32_t
+glusterd_do_snap (glusterd_volinfo_t *volinfo, char *name, dict_t *dict,
+ gf_boolean_t cg, uuid_t cg_id)
+{
+ int32_t ret = -1;
+ xlator_t *this = NULL;
+ glusterd_conf_t *priv = NULL;
+ char volfile[PATH_MAX] = {0,};
+ char exp_path[PATH_MAX] = {0,};
+ char logfile[PATH_MAX] = {0,};
+ int port = 0;
+ int rdma_port = 0;
+ char socketpath[PATH_MAX] = {0};
+ glusterd_brickinfo_t *brickinfo = NULL;
+ char *device = NULL;
+ char snapname[PATH_MAX] = {0, };
+ char tmp[2046] = {0, };
+ glusterd_volinfo_t *snap_volume = NULL;
+ char *description = NULL;
+
+ this = THIS;
+ GF_ASSERT (this);
+
+ priv = this->private;
+ GF_ASSERT (priv);
+
+ strcpy (snapname, name);
+ if (cg) {
+ snprintf (tmp, sizeof (tmp), "%s-snap", volinfo->volname);
+ strcat (snapname, tmp);
+ }
+
+ ret = glusterd_volinfo_dup (volinfo, &snap_volume);
+ strcpy (snap_volume->volname, snapname);
+
+ list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) {
+ if (!glusterd_is_brick_started (brickinfo))
+ continue;
+
+ ret = glusterd_take_snapshot (brickinfo,
+ volinfo->volname,
+ snapname, dict, &device);
+ /* continue with the snapshot even though snapshot
+ on one of the bricks fails. At the end check
+ whether the snapshot volume meets quorum or not.
+ If so, then the snapshot can be treated as success.
+ If not, undo the changes and return failure to cli.
+ */
if (ret)
+ continue;
+
+ /*create the complete brick here and add it to the
+ volinfo
+ */
+ ret = glusterd_snap_brick_create (device, snap_volume,
+ brickinfo);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "not able to"
+ " create the brickinfo for the snap %s"
+ ", volume %s", snapname,
+ volinfo->volname);
goto out;
+ }
+ }
+
+ //TODO: the quorum check of the snap volume here
+
+ ret = dict_get_str (dict, "snap-description", &description);
+ // for now continue the snap, if getting description fails.
+ ret = glusterd_snap_create (volinfo, snap_volume, description, cg_id);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "creating the"
+ "snap object failed for the volume %s",
+ volinfo->volname);
+ goto out;
}
- ret = dict_get_int32 (dict, "type", &type);
- if (ret < 0) {
- snprintf (err_str, sizeof (err_str), "Command type not found");
- gf_log (this->name, GF_LOG_ERROR, "%s", err_str);
+ ret = glusterd_store_perform_snap_store (volinfo);
+ if (ret) {
+ gf_log (this->name, GF_LOG_WARNING, "could not do volume store"
+ " after taking the snapshot (volume: %s)",
+ volinfo->volname);
goto out;
}
- switch (type) {
- case GF_SNAP_OPTION_TYPE_CREATE:
- ret = glusterd_mgmt_v3_initiate_all_phases (req, cli_op, dict);
- break;
- case GF_SNAP_OPTION_TYPE_LIST:
- ret = glusterd_handle_snapshot_list (req, cli_op, dict);
- break;
- default:
- gf_log (this->name, GF_LOG_ERROR, "Unkown snapshot request "
- "type (%d)", type);
- ret = -1; /* Failure */
+ ret = generate_snap_brick_volfiles (volinfo, snap_volume);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "generating the brick "
+ "volfiles for the snap %s (volume: %s) failed",
+ snapname, volinfo->volname);
+ goto out;
}
-out:
+ ret = generate_snap_client_volfiles (volinfo, snap_volume,
+ GF_CLIENT_TRUSTED);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "generating the trusted "
+ "client volfiles for the snap %s (volume: %s) failed",
+ snapname, volinfo->volname);
+ goto out;
+ }
+ ret = generate_snap_client_volfiles (volinfo, snap_volume,
+ GF_CLIENT_OTHER);
if (ret) {
- if (err_str[0] == '\0')
- snprintf (err_str, sizeof (err_str),
- "Operation failed");
- ret = glusterd_op_send_cli_response (cli_op, ret, 0, req,
- dict, err_str);
+ gf_log (this->name, GF_LOG_ERROR, "generating the client "
+ "volfiles for the snap %s (volume: %s) failed",
+ snapname, volinfo->volname);
+ goto out;
}
+ list_for_each_entry (brickinfo, &snap_volume->bricks, brick_list) {
+ ret = glusterd_snap_brick_start (volinfo, snap_volume, brickinfo,
+ _gf_true);
+ if (ret) {
+ gf_log (this->name, GF_LOG_WARNING, "starting the "
+ "brick %s:%s for the snap %s (volume: %s) "
+ "failed", brickinfo->hostname,
+ brickinfo->path, snapname, volinfo->volname);
+ goto out;
+ }
+ }
+
+out:
return ret;
}
-int
-glusterd_handle_snapshot (rpcsvc_request_t *req)
+int32_t
+glusterd_do_snap_remove (glusterd_volinfo_t *volinfo, char *name, dict_t *dict)
{
- return glusterd_big_locked_handler (req, glusterd_handle_snapshot_fn);
+ int32_t ret = -1;
+ xlator_t *this = NULL;
+ glusterd_conf_t *priv = NULL;
+ glusterd_snap_t *snap = NULL;
+ glusterd_snap_cg_t *cg = NULL;
+ int i = 0;
+
+ this = THIS;
+ priv = this->private;
+
+ if (!volinfo) {
+ gf_log (this->name, GF_LOG_ERROR, "volinfo NULL");
+ goto out;
+ }
+
+ if (!name) {
+ gf_log (this->name, GF_LOG_ERROR, "name is NULL (volume: %s)",
+ volinfo->volname);
+ goto out;
+ }
+
+ snap = glusterd_find_snap_by_name (volinfo, name);
+ if (!snap) {
+ cg = glusterd_find_snap_cg_by_name (priv, volinfo->volname);
+ if (!cg) {
+ gf_log (this->name, GF_LOG_ERROR, "could not find "
+ "the snap or the cg object by the name %s",
+ name);
+ goto out;
+ }
+ }
+
+ if (snap) {
+ ret = glusterd_brick_snapshot_remove (snap->snap_volume,
+ volinfo, name);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "removing the bricks"
+ " snapshots for the snap %s (volume: %s) "
+ "failed", name, volinfo->volname);
+ goto out;
+ }
+ }
+
+ if (cg) {
+ for (i = 0; i < cg->volume_count ; i++) {
+ ret = glusterd_brick_snapshot_remove (&cg->volumes[i],
+ volinfo, name);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "removing the"
+ " bricks snapshots for the snap %s "
+ "(volume: %s) failed", name,
+ volinfo->volname);
+ goto out;
+ }
+ }
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+
+/* This function helps in generating the names for either the snapshot
+ (if only one volume name is given in the snap create command) or
+ the consistency group (if multiple volume names are given in the snaap
+ create command). Apart from that, it also helps in generating the names
+ for the snaps of the individual volumes in a consistency group.
+*/
+char *
+generate_snapname (char *volname, char *name, gf_boolean_t volume_from_cg)
+{
+ char internal_snapname[PATH_MAX] = {0, };
+ char timestr[256] = {0, };
+ int ret = -1;
+ char *snapname = NULL;
+ struct timeval tv = {0, };
+ xlator_t *this = NULL;
+ int i = 0;
+
+ this = THIS;
+ GF_ASSERT (this);
+
+ if (name) {
+ GF_ASSERT (volname);
+ if (volume_from_cg) {
+ snprintf (internal_snapname, sizeof (internal_snapname),
+ "%s_%s", volname, name);
+ } else {
+ snprintf (internal_snapname, sizeof (internal_snapname),
+ "%s", name);
+ }
+ } else {
+ ret = gettimeofday (&tv, NULL);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "getting time failed. snapname is not given via"
+ "cli. ");
+ goto out;
+ }
+ gf_time_fmt (timestr, sizeof (timestr),
+ tv.tv_sec, gf_timefmt_FT);
+ snprintf (timestr + strlen (timestr),
+ sizeof timestr - strlen (timestr),
+ ".%"GF_PRI_SUSECONDS,
+ tv.tv_usec);
+
+ for (i = 0; i < strlen (timestr); i++) {
+ if (timestr[i] == ' ' || timestr[i] == ':' ||
+ timestr[i] == '.' || timestr[i] == '-')
+ timestr[i] = '_';
+ }
+
+ snprintf (internal_snapname,
+ sizeof (internal_snapname), "%s%s",
+ (volume_from_cg)?"cg_":"",
+ timestr);
+ }
+
+ snapname = gf_strdup (internal_snapname);
+out:
+ return snapname;
+}
+
+/* name can be either the snapname if @volnames contains only one volume or
+ cg name if there are multiple volume names in volnames string
+*/
+
+int32_t
+glusterd_snapshot (dict_t *dict, char **op_errstr, dict_t *rsp_dict)
+{
+ char *name = NULL;
+ char *volname = NULL;
+ glusterd_volinfo_t *volinfo = NULL;
+ int64_t volume_count = 0;
+ char volname_buf[PATH_MAX] = {0, };
+ int i = 0;
+ int snap_command = 0;
+ xlator_t *this = NULL;
+ int ret = -1;
+ glusterd_snap_cg_t *cg = NULL;
+ gf_boolean_t is_cg = _gf_false;
+ uuid_t cg_id;
+ glusterd_conf_t *priv = NULL;
+ char *tmp = NULL;
+
+ this = THIS;
+
+ GF_ASSERT (this);
+ GF_ASSERT (dict);
+ GF_ASSERT (rsp_dict); //not sure if this is needed, verify.
+
+ priv = this->private;
+ GF_ASSERT (priv);
+
+ ret = dict_get_int32 (dict, "type", &snap_command);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "unable to get the type of "
+ "the snapshot command");
+ goto out;
+ }
+
+ switch (snap_command) {
+ case (GF_SNAP_OPTION_TYPE_CREATE):
+ {
+ ret = dict_get_int64 (dict, "volcount", &volume_count);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "failed to "
+ "get the volume count");
+ goto out;
+ }
+
+ //snap-name should not be set if volume_count > 1
+ ret = dict_get_str (dict, "snap-name", &name);
+ if (volume_count > 1 && !ret)
+ GF_ASSERT (0);
+
+ if (volume_count > 1) {
+ is_cg = _gf_true;
+ ret = dict_get_str (dict, "cg-name", &name);
+ uuid_generate (cg_id);
+ } else if (volume_count == 1) {
+ ret = dict_get_str (dict, "snap-name", &name);
+ }
+
+ if (!name) {
+ name = generate_snapname (volname, NULL, is_cg);
+ if (!name) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "strdup of internal snapname"
+ " ((%s) failed for the "
+ "volume %s", name,
+ volname);
+ goto out;
+ }
+ }
+
+ for (i = 1; i < volume_count + 1; i++) {
+ snprintf (volname_buf, sizeof (volname_buf),
+ "volname%d", i);
+ ret = dict_get_str (dict, volname_buf,
+ &volname);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "failed to get volume name");
+ goto out;
+ }
+
+ ret = glusterd_volinfo_find (volname, &volinfo);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "failed to get the volinfo for "
+ "the volume %s", volname);
+ goto out;
+ }
+
+ tmp = generate_snapname (volname, name, is_cg);
+ if (!tmp) {
+ gf_log (this->name,
+ GF_LOG_ERROR, "strdup "
+ "failed (%s)", name);
+ goto out;
+ }
+
+ /* TODO: Create a stub where the bricks are
+ added parallely by worker threads so that
+ the snap creating happens parallely.
+ */
+ ret = glusterd_do_snap (volinfo, tmp, dict,
+ is_cg, cg_id);
+ if (ret) {
+ gf_log (this->name, GF_LOG_WARNING, "taking the "
+ "snapshot of the volume %s failed",
+ volname);
+ goto out;
+ }
+ }
+ break;
+ }
+ default:
+ gf_log (this->name, GF_LOG_WARNING, "invalid snap command");
+ goto out;
+ break;
+ }
+
+ if (volume_count > 1) {
+ cg = glusterd_new_snap_cg_object (volume_count);
+ if (!cg) {
+ gf_log (this->name, GF_LOG_ERROR, "cannot create the "
+ "consistency group %s", name);
+ goto out;
+ }
+
+ uuid_copy (cg->cg_id, cg_id);
+ ret = glusterd_add_snap_cg (priv, cg);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "could not add the"
+ " consistency group %s to the glusterd list ",
+ name);
+ cg = glusterd_remove_snap_cg_by_name (priv,
+ name);
+ if (!cg)
+ gf_log (this->name, GF_LOG_WARNING, "cannot "
+ "find the consistency group %s", name);
+ goto out;
+ }
+ }
+
+ ret = 0;
+
+out:
+ return ret;
}