summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libglusterfs/src/store.c2
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-mgmt.c40
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-replace-brick.c2
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-snapshot.c1015
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-store.c32
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-store.h6
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-utils.c290
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-utils.h19
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volgen.c144
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volgen.h6
-rw-r--r--xlators/mgmt/glusterd/src/glusterd.c42
-rw-r--r--xlators/mgmt/glusterd/src/glusterd.h13
12 files changed, 1513 insertions, 98 deletions
diff --git a/libglusterfs/src/store.c b/libglusterfs/src/store.c
index 48c79ee..55027fa 100644
--- a/libglusterfs/src/store.c
+++ b/libglusterfs/src/store.c
@@ -596,7 +596,9 @@ gf_store_iter_get_matching (gf_store_iter_t *iter, char *key, char **value)
goto out;
}
GF_FREE (tmp_key);
+ tmp_key = NULL;
GF_FREE (tmp_value);
+ tmp_value = NULL;
ret = gf_store_iter_get_next (iter, &tmp_key, &tmp_value,
NULL);
}
diff --git a/xlators/mgmt/glusterd/src/glusterd-mgmt.c b/xlators/mgmt/glusterd/src/glusterd-mgmt.c
index 268a834..764838b 100644
--- a/xlators/mgmt/glusterd/src/glusterd-mgmt.c
+++ b/xlators/mgmt/glusterd/src/glusterd-mgmt.c
@@ -119,7 +119,17 @@ gd_mgmt_v3_pre_validate_fn (glusterd_op_t op, dict_t *dict,
int ret = -1;
xlator_t *this = THIS;
- ret = 0;
+ switch (op) {
+ case GD_OP_SNAP:
+ {
+ ret = glusterd_snapshot_prevalidate (dict, op_errstr,
+ rsp_dict);
+ break;
+ }
+ default:
+ break;
+ }
+
gf_log (this->name, GF_LOG_DEBUG, "OP = %d. Returning %d", op, ret);
return ret;
}
@@ -143,7 +153,20 @@ gd_mgmt_v3_commit_fn (glusterd_op_t op, dict_t *dict,
int ret = -1;
xlator_t *this = THIS;
+ switch (op) {
+ case GD_OP_SNAP:
+ {
+ ret = glusterd_snapshot (dict, op_errstr, rsp_dict);
+ if (ret)
+ goto out;
+ break;
+ }
+ default:
+ break;
+ }
ret = 0;
+
+out:
gf_log (this->name, GF_LOG_DEBUG, "OP = %d. Returning %d", op, ret);
return ret;
}
@@ -499,11 +522,11 @@ out:
}
int
-glusterd_mgmt_v3_build_payload (dict_t **req, char **op_errstr, dict_t *dict)
+glusterd_mgmt_v3_build_payload (dict_t **req, char **op_errstr, dict_t *dict,
+ glusterd_op_t op)
{
int ret = -1;
dict_t *req_dict = NULL;
- glusterd_op_t op = GD_OP_NONE;
xlator_t *this = NULL;
GF_ASSERT (req);
@@ -515,11 +538,14 @@ glusterd_mgmt_v3_build_payload (dict_t **req, char **op_errstr, dict_t *dict)
if (!req_dict)
goto out;
-/* OPS NEED TO COPY DICT TO REQ_DICT THEMSELVES
- switch (op) {
+ switch (op) {
+ case GD_OP_SNAP:
+ dict_copy (dict, req_dict);
+ break;
+ default:
+ break;
}
-*/
*req = req_dict;
ret = 0;
@@ -1236,7 +1262,7 @@ glusterd_mgmt_v3_initiate_all_phases (rpcsvc_request_t *req, glusterd_op_t op,
}
/* BUILD PAYLOAD */
- ret = glusterd_mgmt_v3_build_payload (&req_dict, &op_errstr, dict);
+ ret = glusterd_mgmt_v3_build_payload (&req_dict, &op_errstr, dict, op);
if (ret) {
gf_log (this->name, GF_LOG_ERROR, LOGSTR_BUILD_PAYLOAD,
gd_op_list[op]);
diff --git a/xlators/mgmt/glusterd/src/glusterd-replace-brick.c b/xlators/mgmt/glusterd/src/glusterd-replace-brick.c
index d1e0962..54b8308 100644
--- a/xlators/mgmt/glusterd/src/glusterd-replace-brick.c
+++ b/xlators/mgmt/glusterd/src/glusterd-replace-brick.c
@@ -688,7 +688,7 @@ rb_src_brick_restart (glusterd_volinfo_t *volinfo,
sleep (2);
ret = glusterd_volume_start_glusterfs (volinfo, src_brickinfo,
- _gf_false);
+ _gf_false);
if (ret) {
gf_log ("", GF_LOG_ERROR, "Unable to start "
"glusterfs, ret: %d", ret);
diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot.c b/xlators/mgmt/glusterd/src/glusterd-snapshot.c
index 1c1e28a..f3428ff 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;
}
diff --git a/xlators/mgmt/glusterd/src/glusterd-store.c b/xlators/mgmt/glusterd/src/glusterd-store.c
index 97c8a5d..50e6800 100644
--- a/xlators/mgmt/glusterd/src/glusterd-store.c
+++ b/xlators/mgmt/glusterd/src/glusterd-store.c
@@ -46,7 +46,7 @@
#include <dirent.h>
void
-glusterd_replace_slash_with_hipen (char *str)
+glusterd_replace_slash_with_hyphen (char *str)
{
char *ptr = NULL;
@@ -105,7 +105,7 @@ glusterd_store_key_vol_brick_set (glusterd_brickinfo_t *brickinfo,
GF_ASSERT (len >= PATH_MAX);
snprintf (key_vol_brick, len, "%s", brickinfo->path);
- glusterd_replace_slash_with_hipen (key_vol_brick);
+ glusterd_replace_slash_with_hyphen (key_vol_brick);
}
static void
@@ -400,6 +400,10 @@ glusterd_store_snap_brickinfo (glusterd_volinfo_t *volinfo,
goto out;
ret = glusterd_store_perform_brick_store (brickinfo);
+ if (ret)
+ goto out;
+
+ ret = gf_store_rename_tmppath (brickinfo->shandle);
out:
gf_log (THIS->name, GF_LOG_DEBUG, "Returning with %d", ret);
return ret;
@@ -749,14 +753,15 @@ glusterd_store_snap_vol_dirpath_set (glusterd_volinfo_t *volinfo,
{
glusterd_conf_t *priv = NULL;
size_t strlen = 0;
+ char path[PATH_MAX] = {0,};
GF_ASSERT (volinfo);
priv = THIS->private;
GF_ASSERT (priv);
- glusterd_store_vol_snaps_dirpath_set (volinfo, snapdirpath, len);
- strlen = sizeof (snapdirpath) + sizeof (*snap_name);
- snprintf (snapdirpath, strlen, "%s/%s", snapdirpath, snap_name);
+ glusterd_store_vol_snaps_dirpath_set (volinfo, path, sizeof (path));
+ strlen = sizeof (path) + sizeof (*snap_name);
+ snprintf (snapdirpath, strlen, "%s/%s", path, snap_name);
}
/* creates GLUSTERD_VOLUME_DIR_PREFIX/<volname>/snaps directory */
static int32_t
@@ -999,7 +1004,7 @@ glusterd_store_snap_brickinfos (glusterd_volinfo_t *volinfo,
GF_ASSERT (volinfo);
- list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) {
+ list_for_each_entry (brickinfo, &snapinfo->bricks, brick_list) {
ret = glusterd_store_snap_brickinfo (volinfo, snapinfo,
brickinfo, brick_count,
vol_fd);
@@ -1198,9 +1203,14 @@ glusterd_store_perform_snap_volume_store (glusterd_volinfo_t *volinfo,
ret = glusterd_store_volinfo_write (fd, snap_volinfo);
if (ret)
goto out;
+
ret = glusterd_store_snap_brickinfos (volinfo, snap_volinfo, fd);
if (ret)
goto out;
+
+ ret = gf_store_rename_tmppath (snap_volinfo->shandle);
+ if (ret)
+ goto out;
out:
if (ret && (fd > 0))
gf_store_unlink_tmppath (volinfo->shandle);
@@ -1413,6 +1423,8 @@ glusterd_store_volume_cleanup_tmp (glusterd_volinfo_t *volinfo)
gf_store_unlink_tmppath (volinfo->rb_shandle);
gf_store_unlink_tmppath (volinfo->node_state_shandle);
+
+ gf_store_unlink_tmppath (volinfo->snap_list_shandle);
}
int32_t
@@ -2415,7 +2427,10 @@ glusterd_store_retrieve_volume (char *volname, glusterd_snap_t *snap)
if (ret)
goto out;
- ret = glusterd_store_retrieve_bricks (volinfo, snap->snap_name);
+ if (snap)
+ ret = glusterd_store_retrieve_bricks (volinfo, snap->snap_name);
+ else
+ ret = glusterd_store_retrieve_bricks (volinfo, NULL);
if (ret)
goto out;
@@ -2720,7 +2735,8 @@ glusterd_store_retrieve_volumes (xlator_t *this)
ret = glusterd_volinfo_find (entry->d_name, &volinfo);
ret =
glusterd_store_create_snap_list_sh_on_absence (volinfo);
- ret = glusterd_store_perform_snap_list_store (volinfo);
+ ret = glusterd_store_perform_snap_store (volinfo);
+ //glusterd_store_perform_snap_list_store (volinfo);
}
glusterd_for_each_entry (entry, dir);
diff --git a/xlators/mgmt/glusterd/src/glusterd-store.h b/xlators/mgmt/glusterd/src/glusterd-store.h
index 2bf14a7..ae76739 100644
--- a/xlators/mgmt/glusterd/src/glusterd-store.h
+++ b/xlators/mgmt/glusterd/src/glusterd-store.h
@@ -138,6 +138,10 @@ glusterd_store_retrieve_options (xlator_t *this);
int32_t
glusterd_store_options (xlator_t *this, dict_t *opts);
+void
+glusterd_replace_slash_with_hyphen (char *str);
+int32_t
+glusterd_store_perform_volume_store (glusterd_volinfo_t *volinfo);
int32_t
-glusterd_store_perform_snap_list_store (glusterd_volinfo_t *volinfo);
+glusterd_store_perform_snap_store (glusterd_volinfo_t *volinfo);
#endif
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c
index 177b657..9b6d7f2 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
@@ -466,6 +466,47 @@ out:
return ret;
}
+int32_t
+glusterd_volinfo_dup (glusterd_volinfo_t *volinfo,
+ glusterd_volinfo_t **dup_volinfo)
+{
+ int32_t ret = -1;
+ glusterd_volinfo_t *new_volinfo = NULL;
+ xlator_t *this = NULL;
+
+ this = THIS;
+ GF_ASSERT (this);
+
+ ret = glusterd_volinfo_new (&new_volinfo);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "not able to create the "
+ "duplicate volinfo for the volume %s",
+ volinfo->volname);
+ goto out;
+ }
+
+ new_volinfo->type = volinfo->type;
+ new_volinfo->replica_count = volinfo->replica_count;
+ new_volinfo->stripe_count = volinfo->stripe_count;
+ new_volinfo->dist_leaf_count = volinfo->dist_leaf_count;
+ new_volinfo->sub_count = volinfo->sub_count;
+ new_volinfo->transport_type = volinfo->transport_type;
+ new_volinfo->nfs_transport_type = volinfo->nfs_transport_type;
+ new_volinfo->brick_count = volinfo->brick_count;
+
+ /* For now, actual volume's username and password itself is used
+ for authentication of trusted clients. If its not working,
+ generate new username and passowd (uuid-generate) and use.
+ */
+ glusterd_auth_set_username (new_volinfo, volinfo->auth.username);
+ glusterd_auth_set_password (new_volinfo, volinfo->auth.password);
+
+ *dup_volinfo = new_volinfo;
+
+out:
+ return ret;
+}
+
void
glusterd_auth_cleanup (glusterd_volinfo_t *volinfo) {
@@ -1255,7 +1296,7 @@ _mk_rundir_p (glusterd_volinfo_t *volinfo)
return ret;
}
-int32_t
+ int32_t
glusterd_volume_start_glusterfs (glusterd_volinfo_t *volinfo,
glusterd_brickinfo_t *brickinfo,
gf_boolean_t wait)
@@ -1394,6 +1435,163 @@ out:
}
int32_t
+glusterd_snap_volume_start_glusterfs (glusterd_volinfo_t *volinfo,
+ glusterd_volinfo_t *snap_volinfo,
+ glusterd_brickinfo_t *brickinfo,
+ gf_boolean_t wait)
+{
+ int32_t ret = -1;
+ xlator_t *this = NULL;
+ glusterd_conf_t *priv = NULL;
+ char pidfile[PATH_MAX+1] = {0,};
+ char volfile[PATH_MAX] = {0,};
+ runner_t runner = {0,};
+ char exp_path[PATH_MAX] = {0,};
+ char logfile[PATH_MAX] = {0,};
+ int port = 0;
+ int rdma_port = 0;
+ char socketpath[PATH_MAX] = {0};
+ char glusterd_uuid[1024] = {0,};
+ char valgrind_logfile[PATH_MAX] = {0};
+ char export_path[PATH_MAX] = {0,};
+ char sock_filepath[PATH_MAX] = {0,};
+ char snap_dir[PATH_MAX] = {0,};
+ int expected_file_len = 0;
+ char snap_volfile[PATH_MAX] = {0, };
+
+ GF_ASSERT (volinfo);
+ GF_ASSERT (brickinfo);
+
+ this = THIS;
+ GF_ASSERT (this);
+
+ priv = this->private;
+ GF_ASSERT (priv);
+
+ ret = _mk_rundir_p (volinfo);
+ if (ret)
+ goto out;
+ GLUSTERD_GET_BRICK_PIDFILE (pidfile, volinfo, brickinfo, priv);
+ if (glusterd_is_service_running (pidfile, NULL))
+ goto connect;
+
+ _reap_brick_process (pidfile, brickinfo->path);
+
+ port = brickinfo->port;
+ if (!port)
+ port = pmap_registry_alloc (THIS);
+
+ /* Build the exp_path, before starting the glusterfsd even in
+ valgrind mode. Otherwise all the glusterfsd processes start
+ writing the valgrind log to the same file.
+ */
+ GLUSTERD_REMOVE_SLASH_FROM_PATH (brickinfo->path, exp_path);
+ runinit (&runner);
+
+ if (priv->valgrind) {
+ /* Run bricks with valgrind */
+ if (volinfo->logdir) {
+ snprintf (valgrind_logfile, PATH_MAX,
+ "%s/valgrind-%s-%s.log",
+ volinfo->logdir,
+ volinfo->volname, exp_path);
+ } else {
+ snprintf (valgrind_logfile, PATH_MAX,
+ "%s/bricks/valgrind-%s-%s.log",
+ DEFAULT_LOG_FILE_DIRECTORY,
+ volinfo->volname, exp_path);
+ }
+
+ runner_add_args (&runner, "valgrind", "--leak-check=full",
+ "--trace-children=yes", "--track-origins=yes",
+ NULL);
+ runner_argprintf (&runner, "--log-file=%s", valgrind_logfile);
+ }
+
+ snprintf (volfile, PATH_MAX, "%s.%s.%s", snap_volinfo->volname,
+ brickinfo->hostname, exp_path);
+
+ if (volinfo->logdir) {
+ snprintf (logfile, PATH_MAX, "%s/%s.log",
+ volinfo->logdir, exp_path);
+ } else {
+ snprintf (logfile, PATH_MAX, "%s/bricks/%s.log",
+ DEFAULT_LOG_FILE_DIRECTORY, exp_path);
+ }
+ if (!brickinfo->logfile)
+ brickinfo->logfile = gf_strdup (logfile);
+
+
+ expected_file_len = strlen (GLUSTERD_SOCK_DIR) + strlen ("/") +
+ MD5_DIGEST_LENGTH*2 + strlen (".socket") + 1;
+ GF_ASSERT (sizeof (socketpath) >= expected_file_len);
+
+ GLUSTERD_GET_SNAP_DIR (snap_dir, volinfo, snap_volinfo->volname, priv);
+ GLUSTERD_REMOVE_SLASH_FROM_PATH (brickinfo->path, export_path);
+ snprintf (sock_filepath, PATH_MAX, "%s/run/%s-%s",
+ snap_dir, brickinfo->hostname, export_path);
+
+ glusterd_set_socket_filepath (sock_filepath, socketpath, sizeof (socketpath));
+
+ snprintf (snap_volfile, sizeof (snap_volfile), "%s/vols/%s/snaps/%s/%s",
+ priv->workdir, volinfo->volname, snap_volinfo->volname,
+ volfile);
+
+ (void) snprintf (glusterd_uuid, 1024, "*-posix.glusterd-uuid=%s",
+ uuid_utoa (MY_UUID));
+ runner_add_args (&runner, SBIN_DIR"/glusterfsd",
+ "-s", brickinfo->hostname, "--volfile-id", volfile,
+ "-p", pidfile, "-S", socketpath,
+ "--brick-name", brickinfo->path,
+ "-l", brickinfo->logfile,
+ "--xlator-option", glusterd_uuid,
+ NULL);
+
+ runner_add_arg (&runner, "--brick-port");
+ if (volinfo->transport_type != GF_TRANSPORT_BOTH_TCP_RDMA) {
+ runner_argprintf (&runner, "%d", port);
+ } else {
+ rdma_port = brickinfo->rdma_port;
+ if (!rdma_port)
+ rdma_port = pmap_registry_alloc (THIS);
+ runner_argprintf (&runner, "%d,%d", port, rdma_port);
+ runner_add_arg (&runner, "--xlator-option");
+ runner_argprintf (&runner, "%s-server.transport.rdma.listen-port=%d",
+ volinfo->volname, rdma_port);
+ }
+
+ runner_add_arg (&runner, "--xlator-option");
+ runner_argprintf (&runner, "%s-server.listen-port=%d",
+ volinfo->volname, port);
+
+ if (volinfo->memory_accounting)
+ runner_add_arg (&runner, "--mem-accounting");
+
+ runner_log (&runner, "", GF_LOG_DEBUG, "Starting GlusterFS");
+ if (wait) {
+ synclock_unlock (&priv->big_lock);
+ ret = runner_run (&runner);
+ synclock_lock (&priv->big_lock);
+
+ } else {
+ ret = runner_run_nowait (&runner);
+ }
+
+ if (ret)
+ goto out;
+
+ brickinfo->port = port;
+ brickinfo->rdma_port = rdma_port;
+
+connect:
+ ret = glusterd_brick_connect (volinfo, brickinfo);
+ if (ret)
+ goto out;
+out:
+ return ret;
+}
+
+int32_t
glusterd_brick_unlink_socket_file (glusterd_volinfo_t *volinfo,
glusterd_brickinfo_t *brickinfo)
{
@@ -4105,6 +4303,50 @@ out:
}
int
+glusterd_snap_brick_start (glusterd_volinfo_t *volinfo,
+ glusterd_volinfo_t *snap_volinfo,
+ glusterd_brickinfo_t *brickinfo,
+ gf_boolean_t wait)
+{
+ int ret = -1;
+ xlator_t *this = NULL;
+ glusterd_conf_t *conf = NULL;
+
+ if ((!brickinfo) || (!volinfo))
+ goto out;
+
+ this = THIS;
+ GF_ASSERT (this);
+ conf = this->private;
+ GF_ASSERT (conf);
+
+ if (uuid_is_null (brickinfo->uuid)) {
+ ret = glusterd_resolve_brick (brickinfo);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, FMTSTR_RESOLVE_BRICK,
+ brickinfo->hostname, brickinfo->path);
+ goto out;
+ }
+ }
+
+ if (uuid_compare (brickinfo->uuid, MY_UUID)) {
+ ret = 0;
+ goto out;
+ }
+ ret = glusterd_snap_volume_start_glusterfs (volinfo, snap_volinfo,
+ brickinfo, wait);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Unable to start brick %s:%s",
+ brickinfo->hostname, brickinfo->path);
+ goto out;
+ }
+
+out:
+ gf_log (this->name, GF_LOG_DEBUG, "returning %d ", ret);
+ return ret;
+}
+
+int
glusterd_restart_bricks (glusterd_conf_t *conf)
{
glusterd_volinfo_t *volinfo = NULL;
@@ -4286,7 +4528,7 @@ out:
}
#ifdef GF_LINUX_HOST_OS
-static int
+int
glusterd_get_brick_root (char *path, char **mount_point)
{
char *ptr = NULL;
@@ -4454,6 +4696,31 @@ glusterd_add_inode_size_to_dict (dict_t *dict, int count)
return ret;
}
+struct mntent *
+glusterd_get_mnt_entry_info (char *mnt_pt, FILE *mtab)
+{
+ struct mntent *entry = NULL;
+
+ mtab = setmntent (_PATH_MOUNTED, "r");
+ if (!mtab)
+ goto out;
+
+ entry = getmntent (mtab);
+
+ while (1) {
+ if (!entry)
+ goto out;
+
+ if (!strcmp (entry->mnt_dir, mnt_pt) &&
+ strcmp (entry->mnt_type, "rootfs"))
+ break;
+ entry = getmntent (mtab);
+ }
+
+out:
+ return entry;
+}
+
static int
glusterd_add_brick_mount_details (glusterd_brickinfo_t *brickinfo,
dict_t *dict, int count)
@@ -4465,8 +4732,8 @@ glusterd_add_brick_mount_details (glusterd_brickinfo_t *brickinfo,
char *fs_name = NULL;
char *mnt_options = NULL;
char *device = NULL;
- FILE *mtab = NULL;
struct mntent *entry = NULL;
+ FILE *mtab = NULL;
snprintf (base_key, sizeof (base_key), "brick%d", count);
@@ -4474,25 +4741,12 @@ glusterd_add_brick_mount_details (glusterd_brickinfo_t *brickinfo,
if (ret)
goto out;
- mtab = setmntent (_PATH_MOUNTED, "r");
- if (!mtab) {
+ entry = glusterd_get_mnt_entry_info (mnt_pt, mtab);
+ if (!entry) {
ret = -1;
goto out;
}
- entry = getmntent (mtab);
-
- while (1) {
- if (!entry) {
- ret = -1;
- goto out;
- }
- if (!strcmp (entry->mnt_dir, mnt_pt) &&
- strcmp (entry->mnt_type, "rootfs"))
- break;
- entry = getmntent (mtab);
- }
-
/* get device file */
memset (key, 0, sizeof (key));
snprintf (key, sizeof (key), "%s.device", base_key);
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h
index bdd2eef..4c95215 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.h
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.h
@@ -81,6 +81,10 @@ glusterd_submit_request (struct rpc_clnt *rpc, void *req,
int32_t
glusterd_volinfo_new (glusterd_volinfo_t **volinfo);
+int32_t
+glusterd_volinfo_dup (glusterd_volinfo_t *volinfo,
+ glusterd_volinfo_t **dup_volinfo);
+
char *
glusterd_auth_get_username (glusterd_volinfo_t *volinfo);
@@ -131,6 +135,11 @@ int32_t
glusterd_volume_start_glusterfs (glusterd_volinfo_t *volinfo,
glusterd_brickinfo_t *brickinfo,
gf_boolean_t wait);
+int32_t
+glusterd_snap_volume_start_glusterfs (glusterd_volinfo_t *volinfo,
+ glusterd_volinfo_t *snap_volinfo,
+ glusterd_brickinfo_t *brickinfo,
+ gf_boolean_t wait);
int32_t
glusterd_volume_stop_glusterfs (glusterd_volinfo_t *volinfo,
@@ -276,7 +285,11 @@ int
glusterd_brick_stop (glusterd_volinfo_t *volinfo,
glusterd_brickinfo_t *brickinfo,
gf_boolean_t del_brick);
-
+int
+glusterd_snap_brick_start (glusterd_volinfo_t *volinfo,
+ glusterd_volinfo_t *snap_volinfo,
+ glusterd_brickinfo_t *brickinfo,
+ gf_boolean_t wait);
int
glusterd_is_defrag_on (glusterd_volinfo_t *volinfo);
@@ -577,6 +590,10 @@ glusterd_is_status_tasks_op (glusterd_op_t op, dict_t *dict);
#ifdef GF_LINUX_HOST_OS
char*
glusterd_get_brick_mount_details (glusterd_brickinfo_t *brickinfo);
+struct mntent *
+glusterd_get_mnt_entry_info (char *mnt_pt, FILE *mtab);
+int
+glusterd_get_brick_root (char *path, char **mount_point);
#endif //LINUX_HOST
#endif
diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c
index 0de71a4..fc32675 100644
--- a/xlators/mgmt/glusterd/src/glusterd-volgen.c
+++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c
@@ -3172,6 +3172,38 @@ glusterd_generate_brick_volfile (glusterd_volinfo_t *volinfo,
return ret;
}
+static int
+glusterd_generate_snap_brick_volfile (glusterd_volinfo_t *volinfo,
+ glusterd_brickinfo_t *brickinfo,
+ glusterd_volinfo_t *snap_volinfo)
+{
+ volgen_graph_t graph = {0,};
+ char filename[PATH_MAX] = {0,};
+ int ret = -1;
+ char path[PATH_MAX] = {0,};
+ char brick[PATH_MAX] = {0,};
+ glusterd_conf_t *priv = NULL;
+
+ priv = THIS->private;
+ GF_ASSERT (volinfo);
+ GF_ASSERT (brickinfo);
+
+ GLUSTERD_REMOVE_SLASH_FROM_PATH (brickinfo->path, brick);
+ GLUSTERD_GET_SNAP_DIR (path, volinfo, snap_volinfo->volname, priv);
+
+ snprintf (filename, PATH_MAX, "%s/%s.%s.%s.vol",
+ path, snap_volinfo->volname,
+ brickinfo->hostname,
+ brick);
+
+ ret = build_server_graph (&graph, snap_volinfo, NULL, brickinfo);
+ if (!ret)
+ ret = volgen_write_volfile (&graph, filename);
+
+ volgen_graph_free (&graph);
+
+ return ret;
+}
static void
@@ -3241,6 +3273,31 @@ out:
return ret;
}
+int
+generate_snap_brick_volfiles (glusterd_volinfo_t *volinfo,
+ glusterd_volinfo_t *snap_volinfo)
+{
+ glusterd_brickinfo_t *brickinfo = NULL;
+ int ret = -1;
+
+ list_for_each_entry (brickinfo, &snap_volinfo->bricks, brick_list) {
+ gf_log ("", GF_LOG_DEBUG,
+ "Found a brick - %s:%s", brickinfo->hostname,
+ brickinfo->path);
+
+ ret = glusterd_generate_snap_brick_volfile (volinfo, brickinfo,
+ snap_volinfo);
+ if (ret)
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
+ return ret;
+}
+
static int
generate_single_transport_client_volfile (glusterd_volinfo_t *volinfo,
char *filepath, dict_t *dict)
@@ -3323,6 +3380,93 @@ out:
}
int
+generate_snap_client_volfiles (glusterd_volinfo_t *actual_volinfo,
+ glusterd_volinfo_t *snap_volinfo,
+ glusterd_client_type_t client_type)
+{
+ char filepath[PATH_MAX] = {0,};
+ int ret = -1;
+ char *types[] = {NULL, NULL, NULL};
+ int i = 0;
+ dict_t *dict = NULL;
+ gf_transport_type type = GF_TRANSPORT_TCP;
+ char path[PATH_MAX] = {0, };
+ xlator_t *this = NULL;
+ glusterd_conf_t *conf = NULL;
+
+ this = THIS;
+ GF_ASSERT (this);
+ conf = this->private;
+ GF_ASSERT (conf);
+
+ if (!actual_volinfo) {
+ gf_log (this->name, GF_LOG_ERROR, "actual volinfo is NULL."
+ "Unable to generate the client volfiles for snap");
+ goto out;
+ }
+
+ if (!snap_volinfo) {
+ gf_log (this->name, GF_LOG_ERROR, "snap volinfo is NULL. Unable"
+ "to generate the client volfiles for snap (volume: %s)",
+ actual_volinfo->volname);
+ goto out;
+ }
+
+ enumerate_transport_reqs (actual_volinfo->transport_type, types);
+ dict = dict_new ();
+ if (!dict)
+ goto out;
+ for (i = 0; types[i]; i++) {
+ memset (filepath, 0, sizeof (filepath));
+ ret = dict_set_str (dict, "client-transport-type", types[i]);
+ if (ret)
+ goto out;
+ type = transport_str_to_type (types[i]);
+
+ ret = dict_set_uint32 (dict, "trusted-client", client_type);
+ if (ret)
+ goto out;
+
+ GLUSTERD_GET_SNAP_DIR (path, actual_volinfo,
+ snap_volinfo->volname,conf);
+ if (client_type == GF_CLIENT_TRUSTED) {
+ if ((actual_volinfo->transport_type ==
+ GF_TRANSPORT_BOTH_TCP_RDMA) &&
+ type == GF_TRANSPORT_RDMA) {
+ snprintf (filepath, PATH_MAX,
+ "%s/trusted-%s.rdma-fuse.vol",
+ path, snap_volinfo->volname);
+ } else {
+ snprintf (filepath, PATH_MAX,
+ "%s/trusted-%s-fuse.vol",
+ path, snap_volinfo->volname);
+ }
+ } else {
+ if ((actual_volinfo->transport_type ==
+ GF_TRANSPORT_BOTH_TCP_RDMA) &&
+ (type == GF_TRANSPORT_RDMA)) {
+ snprintf (filepath, PATH_MAX, "%s/%s.rdma-fuse.vol",
+ path, snap_volinfo->volname);
+ } else {
+ snprintf (filepath, PATH_MAX, "%s/%s-fuse.vol",
+ path, snap_volinfo->volname);
+ }
+ }
+
+ ret = generate_single_transport_client_volfile (snap_volinfo,
+ filepath,
+ dict);
+ if (ret)
+ goto out;
+ }
+
+out:
+ if (dict)
+ dict_unref (dict);
+ return ret;
+}
+
+int
glusterd_create_rb_volfiles (glusterd_volinfo_t *volinfo,
glusterd_brickinfo_t *brickinfo)
{
diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.h b/xlators/mgmt/glusterd/src/glusterd-volgen.h
index 2d31c40..dc334ca 100644
--- a/xlators/mgmt/glusterd/src/glusterd-volgen.h
+++ b/xlators/mgmt/glusterd/src/glusterd-volgen.h
@@ -137,8 +137,14 @@ glusterd_check_voloption_flags (char *key, int32_t flags);
gf_boolean_t
glusterd_is_valid_volfpath (char *volname, char *brick);
int generate_brick_volfiles (glusterd_volinfo_t *volinfo);
+int generate_snap_brick_volfiles (glusterd_volinfo_t *volinfo,
+ glusterd_volinfo_t *snap_volinfo);
int generate_client_volfiles (glusterd_volinfo_t *volinfo,
glusterd_client_type_t client_type);
+int
+generate_snap_client_volfiles (glusterd_volinfo_t *actual_volinfo,
+ glusterd_volinfo_t *snap_volinfo,
+ glusterd_client_type_t client_type);
int glusterd_get_volopt_content (dict_t *dict, gf_boolean_t xml_out);
char*
glusterd_get_trans_type_rb (gf_transport_type ttype);
diff --git a/xlators/mgmt/glusterd/src/glusterd.c b/xlators/mgmt/glusterd/src/glusterd.c
index c932800..acefc8e 100644
--- a/xlators/mgmt/glusterd/src/glusterd.c
+++ b/xlators/mgmt/glusterd/src/glusterd.c
@@ -1084,6 +1084,7 @@ init (xlator_t *this)
struct stat buf = {0,};
char storedir [PATH_MAX] = {0,};
char workdir [PATH_MAX] = {0,};
+ char snap_brick_dir[PATH_MAX] = {0, };
char hooks_dir [PATH_MAX] = {0,};
char cmd_log_filename [PATH_MAX] = {0,};
int first_time = 0;
@@ -1133,6 +1134,43 @@ init (xlator_t *this)
gf_log (this->name, GF_LOG_INFO, "Using %s as working directory",
workdir);
+ dir_data = dict_get (this->options, "snap-bricks-path");
+ if (!dir_data) {
+ //Use default working dir
+ strncpy (snap_brick_dir, GLUSTERD_DEFAULT_SNAPS_BRICK_DIR, PATH_MAX);
+ } else {
+ strncpy (snap_brick_dir, dir_data->data, PATH_MAX);
+ }
+
+ ret = stat (snap_brick_dir, &buf);
+ if ((ret != 0) && (ENOENT != errno)) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "stat fails on %s, exiting. (errno = %d)",
+ workdir, errno);
+ exit (1);
+ }
+
+ if ((!ret) && (!S_ISDIR(buf.st_mode))) {
+ gf_log (this->name, GF_LOG_CRITICAL,
+ "Provided working area %s is not a directory,"
+ "exiting", workdir);
+ exit (1);
+ }
+
+
+ if ((-1 == ret) && (ENOENT == errno)) {
+ ret = mkdir (snap_brick_dir, 0777);
+
+ if (-1 == ret) {
+ gf_log (this->name, GF_LOG_CRITICAL,
+ "Unable to create directory %s"
+ " ,errno = %d", snap_brick_dir, errno);
+ exit (1);
+ }
+
+ first_time = 1;
+ }
+
snprintf (cmd_log_filename, PATH_MAX,"%s/.cmd_log_history",
DEFAULT_LOG_FILE_DIRECTORY);
ret = gf_cmd_log_init (cmd_log_filename);
@@ -1514,5 +1552,9 @@ struct volume_options options[] = {
.type = GF_OPTION_TYPE_INT,
.description = "Sets the base port for portmap query"
},
+ { .key = {"snap-brick-path"},
+ .type = GF_OPTION_TYPE_STR,
+ .description = "directory where the bricks for the snapshots will be created"
+ },
{ .key = {NULL} },
};
diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h
index d51f8d2..48da712 100644
--- a/xlators/mgmt/glusterd/src/glusterd.h
+++ b/xlators/mgmt/glusterd/src/glusterd.h
@@ -157,6 +157,7 @@ typedef struct {
rpcsvc_t *uds_rpc; /* RPCSVC for the unix domain socket */
uint32_t base_port;
struct list_head snap_cg;
+ char *snap_bricks_directory;
} glusterd_conf_t;
@@ -406,6 +407,8 @@ enum glusterd_vol_comp_status_ {
#define GLUSTERD_VOL_SNAP_FILE "snap_list.info"
#define GLUSTERD_VOL_SNAP_DIR_PREFIX "snaps"
+#define GLUSTERD_DEFAULT_SNAPS_BRICK_DIR "/var/run/gluster/snaps"
+
/* definitions related to replace brick */
#define RB_CLIENT_MOUNTPOINT "rb_mount"
#define RB_CLIENTVOL_FILENAME "rb_client.vol"
@@ -453,7 +456,7 @@ typedef ssize_t (*gd_serialize_t) (struct iovec outmsg, void *args);
GLUSTERD_GET_VOLUME_DIR (volpath, volinfo, priv); \
GLUSTERD_REMOVE_SLASH_FROM_PATH (brickinfo->path, exp_path); \
snprintf (pidfile, PATH_MAX, "%s/run/%s-%s.pid", \
- volpath, brickinfo->hostname, exp_path); \
+ volpath, brickinfo->hostname, exp_path); \
} while (0)
#define GLUSTERD_GET_NFS_PIDFILE(pidfile,nfspath) { \
@@ -486,7 +489,6 @@ typedef ssize_t (*gd_serialize_t) (struct iovec outmsg, void *args);
uuid_utoa(MY_UUID)); \
} while (0)
-
int glusterd_uuid_init();
int glusterd_uuid_generate_save ();
@@ -874,4 +876,11 @@ glusterd_find_snap_cg_by_id (glusterd_conf_t *conf, uuid_t cg_id);
glusterd_snap_cg_t*
glusterd_find_snap_cg_by_name (glusterd_conf_t *conf, char *cg_name);
+int
+glusterd_snapshot_prevalidate (dict_t *dict, char **op_errstr,
+ dict_t *rsp_dict);
+int
+glusterd_snapshot (dict_t *dict, char **op_errstr, dict_t *rsp_dict);
+char *
+glusterd_build_snap_device_path (char *device, char *snapname);
#endif