From cc4fa72926f9ac517365d91ae6144530dc67c001 Mon Sep 17 00:00:00 2001 From: Raghavendra Bhat Date: Wed, 16 Oct 2013 18:18:04 +0530 Subject: mgmt/glusterd: snapshot create command This is still a work in progress. As of now, these things are done: * Take the snapshot of the backend brick * Create the new volume for the snapshot * Create the brick and the client volfiles * Store the snapshot related info in /var/lib/glusterd * Create the snap object representing the snapshot TODO: Start the brick processes for the snapshot Change-Id: I26fbb0f8e5cf004d4c1dbca51819bab1cd1bac15 Signed-off-by: Raghavendra Bhat --- libglusterfs/src/store.c | 2 + xlators/mgmt/glusterd/src/glusterd-mgmt.c | 40 +- xlators/mgmt/glusterd/src/glusterd-replace-brick.c | 2 +- xlators/mgmt/glusterd/src/glusterd-snapshot.c | 1015 ++++++++++++++++++-- xlators/mgmt/glusterd/src/glusterd-store.c | 32 +- xlators/mgmt/glusterd/src/glusterd-store.h | 6 +- xlators/mgmt/glusterd/src/glusterd-utils.c | 290 +++++- xlators/mgmt/glusterd/src/glusterd-utils.h | 19 +- xlators/mgmt/glusterd/src/glusterd-volgen.c | 144 +++ xlators/mgmt/glusterd/src/glusterd-volgen.h | 6 + xlators/mgmt/glusterd/src/glusterd.c | 42 + xlators/mgmt/glusterd/src/glusterd.h | 13 +- 12 files changed, 1513 insertions(+), 98 deletions(-) diff --git a/libglusterfs/src/store.c b/libglusterfs/src/store.c index 48c79ee02..55027fa9b 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 268a834d8..764838b76 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 d1e0962ba..54b830870 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 1c1e28a86..f3428ff03 100644 --- a/xlators/mgmt/glusterd/src/glusterd-snapshot.c +++ b/xlators/mgmt/glusterd/src/glusterd-snapshot.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "globals.h" #include "compat.h" @@ -38,6 +39,184 @@ #include "cli1-xdr.h" #include "xdr-generic.h" +#ifdef GF_LINUX_HOST_OS +#include +#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//- is the device for the lvm, + then the snap device will be /dev//-. + 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//@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 97c8a5d4f..50e680064 100644 --- a/xlators/mgmt/glusterd/src/glusterd-store.c +++ b/xlators/mgmt/glusterd/src/glusterd-store.c @@ -46,7 +46,7 @@ #include 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//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 2bf14a743..ae767398a 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 177b65710..9b6d7f250 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) @@ -1393,6 +1434,163 @@ out: return ret; } +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) @@ -4104,6 +4302,50 @@ out: return ret; } +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) { @@ -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 bdd2eef1e..4c952153e 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 0de71a49a..fc326757d 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) @@ -3322,6 +3379,93 @@ out: return ret; } +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 2d31c4040..dc334ca8d 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 c932800c3..acefc8e42 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 d51f8d2ce..48da712f8 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 -- cgit