diff options
Diffstat (limited to 'xlators/mgmt/glusterd/src/glusterd-op-sm.c')
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-op-sm.c | 3270 |
1 files changed, 2351 insertions, 919 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c index 8f70472f5..1666f5e4d 100644 --- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c +++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c @@ -1,22 +1,12 @@ /* - Copyright (c) 2006-2011 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ #ifndef _CONFIG_H #define _CONFIG_H @@ -47,6 +37,7 @@ #include "glusterd-store.h" #include "glusterd-hooks.h" #include "glusterd-volgen.h" +#include "glusterd-locks.h" #include "syscall.h" #include "cli1-xdr.h" #include "common-utils.h" @@ -56,9 +47,186 @@ #include <signal.h> #include <sys/wait.h> +#define ALL_VOLUME_OPTION_CHECK(volname, key, ret, op_errstr, label) \ + do { \ + gf_boolean_t _all = !strcmp ("all", volname); \ + gf_boolean_t _ratio = !strcmp (key, \ + GLUSTERD_QUORUM_RATIO_KEY); \ + if (_all && !_ratio) { \ + ret = -1; \ + *op_errstr = gf_strdup ("Not a valid option for all " \ + "volumes"); \ + goto label; \ + } else if (!_all && _ratio) { \ + ret = -1; \ + *op_errstr = gf_strdup ("Not a valid option for " \ + "single volume"); \ + goto label; \ + } \ + } while (0) + static struct list_head gd_op_sm_queue; pthread_mutex_t gd_op_sm_lock; glusterd_op_info_t opinfo = {{0},}; +uuid_t global_txn_id = {"\0"}; /* To be used in + * heterogeneous + * cluster with no + * transaction ids */ + +static dict_t *txn_opinfo; + +struct txn_opinfo_object_ { + glusterd_op_info_t opinfo; +}; +typedef struct txn_opinfo_object_ txn_opinfo_obj; + +int32_t +glusterd_txn_opinfo_dict_init () +{ + int32_t ret = -1; + + txn_opinfo = dict_new (); + if (!txn_opinfo) { + ret = -1; + goto out; + } + + ret = 0; +out: + return ret; +} + +void +glusterd_txn_opinfo_dict_fini () +{ + if (txn_opinfo) + dict_destroy (txn_opinfo); +} + +void +glusterd_txn_opinfo_init (glusterd_op_info_t *opinfo, + glusterd_op_sm_state_info_t *state, + glusterd_op_t *op, + dict_t *op_ctx, + rpcsvc_request_t *req) +{ + GF_ASSERT (opinfo); + + if (state) + opinfo->state = *state; + + if (op) + opinfo->op = *op; + + opinfo->op_ctx = dict_ref(op_ctx); + + if (req) + opinfo->req = req; + + return; +} + +int32_t +glusterd_get_txn_opinfo (uuid_t *txn_id, glusterd_op_info_t *opinfo) +{ + int32_t ret = -1; + txn_opinfo_obj *opinfo_obj = NULL; + + if (!txn_id || !opinfo) { + gf_log ("", GF_LOG_ERROR, + "Empty transaction id or opinfo received."); + ret = -1; + goto out; + } + + ret = dict_get_bin(txn_opinfo, uuid_utoa (*txn_id), + (void **) &opinfo_obj); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to get transaction opinfo"); + goto out; + } + + (*opinfo) = opinfo_obj->opinfo; + + ret = 0; +out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int32_t +glusterd_set_txn_opinfo (uuid_t *txn_id, glusterd_op_info_t *opinfo) +{ + int32_t ret = -1; + txn_opinfo_obj *opinfo_obj = NULL; + + if (!txn_id) { + gf_log ("", GF_LOG_ERROR, "Empty transaction id received."); + ret = -1; + goto out; + } + + ret = dict_get_bin(txn_opinfo, uuid_utoa (*txn_id), + (void **) &opinfo_obj); + if (ret) { + opinfo_obj = GF_CALLOC (1, sizeof(txn_opinfo_obj), + gf_common_mt_txn_opinfo_obj_t); + if (!opinfo_obj) { + ret = -1; + goto out; + } + + ret = dict_set_bin(txn_opinfo, uuid_utoa (*txn_id), opinfo_obj, + sizeof(txn_opinfo_obj)); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to set opinfo for transaction ID : %s", + uuid_utoa (*txn_id)); + goto out; + } + } + + opinfo_obj->opinfo = (*opinfo); + + ret = 0; +out: + if (ret) + if (opinfo_obj) + GF_FREE (opinfo_obj); + + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int32_t +glusterd_clear_txn_opinfo (uuid_t *txn_id) +{ + int32_t ret = -1; + glusterd_op_info_t txn_op_info = {{0},}; + + if (!txn_id) { + gf_log ("", GF_LOG_ERROR, "Empty transaction id received."); + ret = -1; + goto out; + } + + ret = glusterd_get_txn_opinfo (txn_id, &txn_op_info); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Transaction opinfo not found"); + goto out; + } + + dict_unref (txn_op_info.op_ctx); + + dict_del(txn_opinfo, uuid_utoa (*txn_id)); + + ret = 0; +out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + static int glusterfs_port = GLUSTERD_DEFAULT_PORT; static char *glusterd_op_sm_state_names[] = { "Default", @@ -97,6 +265,8 @@ static char *glusterd_op_sm_event_names[] = { "GD_OP_EVENT_INVALID" }; +extern struct volopt_map_entry glusterd_volopt_map[]; + char* glusterd_op_sm_state_name_get (int state) { @@ -137,10 +307,10 @@ glusterd_is_volume_started (glusterd_volinfo_t *volinfo) } static int -glusterd_op_sm_inject_all_acc () +glusterd_op_sm_inject_all_acc (uuid_t *txn_id) { int32_t ret = -1; - ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACC, NULL); + ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACC, txn_id, NULL); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } @@ -154,6 +324,10 @@ glusterd_brick_op_build_payload (glusterd_op_t op, glusterd_brickinfo_t *brickin char *volname = NULL; char name[1024] = {0,}; gf_xl_afr_op_t heal_op = GF_AFR_OP_INVALID; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); GF_ASSERT (op < GD_OP_MAX); GF_ASSERT (op > GD_OP_NONE); @@ -165,10 +339,8 @@ glusterd_brick_op_build_payload (glusterd_op_t op, glusterd_brickinfo_t *brickin case GD_OP_STOP_VOLUME: brick_req = GF_CALLOC (1, sizeof (*brick_req), gf_gld_mt_mop_brick_req_t); - if (!brick_req) { - gf_log ("", GF_LOG_ERROR, "Out of Memory"); + if (!brick_req) goto out; - } brick_req->op = GLUSTERD_BRICK_TERMINATE; brick_req->name = ""; break; @@ -176,10 +348,8 @@ glusterd_brick_op_build_payload (glusterd_op_t op, glusterd_brickinfo_t *brickin brick_req = GF_CALLOC (1, sizeof (*brick_req), gf_gld_mt_mop_brick_req_t); - if (!brick_req) { - gf_log ("", GF_LOG_ERROR, "Out of Memory"); + if (!brick_req) goto out; - } brick_req->op = GLUSTERD_BRICK_XLATOR_INFO; brick_req->name = brickinfo->path; @@ -204,10 +374,8 @@ glusterd_brick_op_build_payload (glusterd_op_t op, glusterd_brickinfo_t *brickin { brick_req = GF_CALLOC (1, sizeof (*brick_req), gf_gld_mt_mop_brick_req_t); - if (!brick_req) { - gf_log (THIS->name, GF_LOG_ERROR, "Out of memory"); + if (!brick_req) goto out; - } brick_req->op = GLUSTERD_BRICK_STATUS; brick_req->name = ""; } @@ -227,13 +395,27 @@ glusterd_brick_op_build_payload (glusterd_op_t op, glusterd_brickinfo_t *brickin brick_req->name = gf_strdup (name); break; + case GD_OP_SNAP: + brick_req = GF_CALLOC (1, sizeof (*brick_req), + gf_gld_mt_mop_brick_req_t); + if (!brick_req) + goto out; + + brick_req->op = GLUSTERD_VOLUME_BARRIER_OP; + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + snprintf (name, 1024, "%s-server",volname); + brick_req->name = gf_strdup (name); + + break; default: goto out; break; } ret = dict_allocate_and_serialize (dict, &brick_req->input.input_val, - (size_t*)&brick_req->input.input_len); + &brick_req->input.input_len); if (ret) goto out; *req = brick_req; @@ -242,7 +424,7 @@ glusterd_brick_op_build_payload (glusterd_op_t op, glusterd_brickinfo_t *brickin out: if (ret && brick_req) GF_FREE (brick_req); - gf_log ("glusterd", GF_LOG_DEBUG, "Returning %d", ret); + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } @@ -285,7 +467,7 @@ glusterd_node_op_build_payload (glusterd_op_t op, gd1_mgmt_brick_op_req **req, } ret = dict_allocate_and_serialize (dict, &brick_req->input.input_val, - (size_t*)&brick_req->input.input_len); + &brick_req->input.input_len); if (ret) goto out; @@ -301,24 +483,88 @@ out: } static int +glusterd_validate_quorum_options (xlator_t *this, char *fullkey, char *value, + char **op_errstr) +{ + int ret = 0; + char *key = NULL; + volume_option_t *opt = NULL; + + if (!glusterd_is_quorum_option (fullkey)) + goto out; + key = strchr (fullkey, '.'); + key++; + opt = xlator_volume_option_get (this, key); + ret = xlator_option_validate (this, key, value, opt, op_errstr); +out: + return ret; +} + +static int +glusterd_check_client_op_version_support (char *volname, uint32_t op_version, + char **op_errstr) +{ + int ret = 0; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + rpc_transport_t *xprt = NULL; + + this = THIS; + GF_ASSERT(this); + priv = this->private; + GF_ASSERT(priv); + + pthread_mutex_lock (&priv->xprt_lock); + list_for_each_entry (xprt, &priv->xprt_list, list) { + if ((!strcmp(volname, xprt->peerinfo.volname)) && + ((op_version > xprt->peerinfo.max_op_version) || + (op_version < xprt->peerinfo.min_op_version))) { + ret = -1; + break; + } + } + pthread_mutex_unlock (&priv->xprt_lock); + + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "One or more clients " + "don't support the required op-version"); + ret = gf_asprintf (op_errstr, "One or more connected clients " + "cannot support the feature being set. " + "These clients need to be upgraded or " + "disconnected before running this command" + " again"); + return -1; + } + return 0; +} + +static int glusterd_op_stage_set_volume (dict_t *dict, char **op_errstr) { - int ret = 0; - char *volname = NULL; - int exists = 0; - char *key = NULL; - char *key_fixed = NULL; - char *value = NULL; - char str[100] = {0, }; - int count = 0; - int dict_count = 0; - char errstr[2048] = {0, }; - glusterd_volinfo_t *volinfo = NULL; - dict_t *val_dict = NULL; - gf_boolean_t global_opt = _gf_false; - glusterd_volinfo_t *voliter = NULL; - glusterd_conf_t *priv = NULL; - xlator_t *this = NULL; + int ret = -1; + char *volname = NULL; + int exists = 0; + char *key = NULL; + char *key_fixed = NULL; + char *value = NULL; + char str[100] = {0, }; + int count = 0; + int dict_count = 0; + char errstr[2048] = {0, }; + glusterd_volinfo_t *volinfo = NULL; + dict_t *val_dict = NULL; + gf_boolean_t global_opt = _gf_false; + glusterd_volinfo_t *voliter = NULL; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + uint32_t new_op_version = 0; + uint32_t local_new_op_version = 0; + uint32_t key_op_version = 0; + uint32_t local_key_op_version = 0; + gf_boolean_t origin_glusterd = _gf_true; + gf_boolean_t check_op_version = _gf_true; + gf_boolean_t all_vol = _gf_false; + struct volopt_map_entry *vme = NULL; GF_ASSERT (dict); this = THIS; @@ -330,23 +576,60 @@ glusterd_op_stage_set_volume (dict_t *dict, char **op_errstr) if (!val_dict) goto out; - ret = dict_get_int32 (dict, "count", &dict_count); + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to get volume name"); + goto out; + } + /* Check if we can support the required op-version + * This check is not done on the originator glusterd. The originator + * glusterd sets this value. + */ + origin_glusterd = is_origin_glusterd (dict); + + if (!origin_glusterd) { + /* Check for v3.3.x origin glusterd */ + check_op_version = dict_get_str_boolean (dict, + "check-op-version", + _gf_false); + + if (check_op_version) { + ret = dict_get_uint32 (dict, "new-op-version", + &new_op_version); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to get new_op_version"); + goto out; + } + + if ((new_op_version > GD_OP_VERSION_MAX) || + (new_op_version < GD_OP_VERSION_MIN)) { + ret = -1; + snprintf (errstr, sizeof (errstr), + "Required op_version (%d) is not " + "supported", new_op_version); + gf_log (this->name, GF_LOG_ERROR, "%s", errstr); + goto out; + } + } + } + + ret = dict_get_int32 (dict, "count", &dict_count); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Count(dict),not set in Volume-Set"); goto out; } - if ( dict_count == 0 ) { - /*No options would be specified of volume set help */ + if (dict_count == 0) { + /*No options would be specified of volume set help */ if (dict_get (dict, "help" )) { ret = 0; goto out; } if (dict_get (dict, "help-xml" )) { - #if (HAVE_LIB_XML) ret = 0; goto out; @@ -371,26 +654,31 @@ glusterd_op_stage_set_volume (dict_t *dict, char **op_errstr) goto out; } - exists = glusterd_check_volume_exists (volname); - if (!exists) { - snprintf (errstr, sizeof (errstr), "Volume %s does not exist", - volname); - gf_log (this->name, GF_LOG_ERROR, "%s", errstr); - *op_errstr = gf_strdup (errstr); - ret = -1; - goto out; - } + if (strcasecmp (volname, "all") != 0) { + exists = glusterd_check_volume_exists (volname); + if (!exists) { + snprintf (errstr, sizeof (errstr), + FMTSTR_CHECK_VOL_EXISTS, volname); + gf_log (this->name, GF_LOG_ERROR, "%s", errstr); + ret = -1; + goto out; + } - ret = glusterd_volinfo_find (volname, &volinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to allocate memory"); - goto out; + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + FMTSTR_CHECK_VOL_EXISTS, volname); + goto out; + } + + ret = glusterd_validate_volume_id (dict, volinfo); + if (ret) + goto out; + } else { + all_vol = _gf_true; } - ret = glusterd_validate_volume_id (dict, volinfo); - if (ret) - goto out; + local_new_op_version = priv->op_version; for ( count = 1; ret != 1 ; count++ ) { global_opt = _gf_false; @@ -408,38 +696,110 @@ glusterd_op_stage_set_volume (dict_t *dict, char **op_errstr) goto out; } - if (strcmp (key, "memory-accounting") == 0) { - gf_log (this->name, GF_LOG_INFO, + if (strcmp (key, "config.memory-accounting") == 0) { + gf_log (this->name, GF_LOG_DEBUG, "enabling memory accounting for volume %s", volname); ret = 0; - goto out; } + + if (strcmp (key, "config.transport") == 0) { + gf_log (this->name, GF_LOG_DEBUG, + "changing transport-type for volume %s", + volname); + ret = 0; + /* if value is none of 'tcp/rdma/tcp,rdma' error out */ + if (!((strcasecmp (value, "rdma") == 0) || + (strcasecmp (value, "tcp") == 0) || + (strcasecmp (value, "tcp,rdma") == 0) || + (strcasecmp (value, "rdma,tcp") == 0))) { + ret = snprintf (errstr, sizeof (errstr), + "transport-type %s does " + "not exist", value); + /* lets not bother about above return value, + its a failure anyways */ + ret = -1; + goto out; + } + } + + if (is_key_glusterd_hooks_friendly (key)) + continue; + + for (vme = &glusterd_volopt_map[0]; vme->key; vme++) { + if ((vme->validate_fn) && + ((!strcmp (key, vme->key)) || + (!strcmp (key, strchr (vme->key, '.') + 1)))) { + ret = vme->validate_fn (dict, key, value, + op_errstr); + if (ret) + goto out; + break; + } + } + exists = glusterd_check_option_exists (key, &key_fixed); if (exists == -1) { ret = -1; goto out; } + if (!exists) { gf_log (this->name, GF_LOG_ERROR, - "Option with name: %s " - "does not exist", key); - ret = snprintf (errstr, 2048, + "Option with name: %s does not exist", key); + ret = snprintf (errstr, sizeof (errstr), "option : %s does not exist", key); if (key_fixed) - snprintf (errstr + ret, 2048 - ret, + snprintf (errstr + ret, sizeof (errstr) - ret, "\nDid you mean %s?", key_fixed); - *op_errstr = gf_strdup (errstr); ret = -1; goto out; } if (key_fixed) key = key_fixed; - - ret = glusterd_check_globaloption (key); + ALL_VOLUME_OPTION_CHECK (volname, key, ret, op_errstr, out); + ret = glusterd_validate_quorum_options (this, key, value, + op_errstr); if (ret) + goto out; + + local_key_op_version = glusterd_get_op_version_for_key (key); + if (local_key_op_version > local_new_op_version) + local_new_op_version = local_key_op_version; + + sprintf (str, "op-version%d", count); + if (origin_glusterd) { + ret = dict_set_uint32 (dict, str, local_key_op_version); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set key-op-version in dict"); + goto out; + } + } else if (check_op_version) { + ret = dict_get_uint32 (dict, str, &key_op_version); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to get key-op-version from" + " dict"); + goto out; + } + if (local_key_op_version != key_op_version) { + ret = -1; + snprintf (errstr, sizeof (errstr), + "option: %s op-version mismatch", + key); + gf_log (this->name, GF_LOG_ERROR, + "%s, required op-version = %"PRIu32", " + "available op-version = %"PRIu32, + errstr, key_op_version, + local_key_op_version); + goto out; + } + } + + if (glusterd_check_globaloption (key)) global_opt = _gf_true; ret = dict_set_str (val_dict, key, value); @@ -452,9 +812,9 @@ glusterd_op_stage_set_volume (dict_t *dict, char **op_errstr) } *op_errstr = NULL; - if (!global_opt) + if (!global_opt && !all_vol) ret = glusterd_validate_reconfopts (volinfo, val_dict, op_errstr); - else { + else if (!all_vol) { voliter = NULL; list_for_each_entry (voliter, &priv->volumes, vol_list) { ret = glusterd_validate_globalopts (voliter, val_dict, op_errstr); @@ -464,8 +824,9 @@ glusterd_op_stage_set_volume (dict_t *dict, char **op_errstr) } if (ret) { - gf_log (this->name, GF_LOG_DEBUG, "Could not create temp " - "volfile, some option failed: %s", *op_errstr); + gf_log (this->name, GF_LOG_ERROR, "Could not create " + "temp volfile, some option failed: %s", + *op_errstr); goto out; } dict_del (val_dict, key); @@ -476,6 +837,35 @@ glusterd_op_stage_set_volume (dict_t *dict, char **op_errstr) } } + // Check if all the connected clients support the new op-version + ret = glusterd_check_client_op_version_support (volname, + local_new_op_version, + op_errstr); + if (ret) + goto out; + + if (origin_glusterd) { + ret = dict_set_uint32 (dict, "new-op-version", + local_new_op_version); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set new-op-version in dict"); + goto out; + } + /* Set this value in dict so other peers know to check for + * op-version. This is a hack for 3.3.x compatibility + * + * TODO: Remove this and the other places this is referred once + * 3.3.x compatibility is not required + */ + ret = dict_set_uint32 (dict, "check-op-version", + _gf_true); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set check-op-version in dict"); + goto out; + } + } ret = 0; @@ -483,8 +873,9 @@ out: if (val_dict) dict_unref (val_dict); - if (key_fixed) - GF_FREE (key_fixed); + GF_FREE (key_fixed); + if (errstr[0] != '\0') + *op_errstr = gf_strdup (errstr); if (ret) { if (!(*op_errstr)) { @@ -510,35 +901,41 @@ glusterd_op_stage_reset_volume (dict_t *dict, char **op_errstr) char *key = NULL; char *key_fixed = NULL; glusterd_volinfo_t *volinfo = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); ret = dict_get_str (dict, "volname", &volname); if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); + gf_log (this->name, GF_LOG_ERROR, "Unable to get volume name"); goto out; } - exists = glusterd_check_volume_exists (volname); + if (strcasecmp (volname, "all") != 0) { + exists = glusterd_check_volume_exists (volname); + if (!exists) { + snprintf (msg, sizeof (msg), FMTSTR_CHECK_VOL_EXISTS, + volname); + ret = -1; + goto out; + } + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + snprintf (msg, sizeof (msg), FMTSTR_CHECK_VOL_EXISTS, + volname); + goto out; + } - if (!exists) { - snprintf (msg, sizeof (msg), "Volume %s does not " - "exist", volname); - gf_log ("", GF_LOG_ERROR, "%s", msg); - *op_errstr = gf_strdup (msg); - ret = -1; - goto out; + ret = glusterd_validate_volume_id (dict, volinfo); + if (ret) + goto out; } - ret = glusterd_volinfo_find (volname, &volinfo); - if (ret) - goto out; - - ret = glusterd_validate_volume_id (dict, volinfo); - if (ret) - goto out; ret = dict_get_str (dict, "key", &key); if (ret) { - gf_log ("glusterd", GF_LOG_ERROR, "Unable to get option key"); + gf_log (this->name, GF_LOG_ERROR, "Unable to get option key"); goto out; } if (strcmp(key, "all")) { @@ -548,24 +945,30 @@ glusterd_op_stage_reset_volume (dict_t *dict, char **op_errstr) goto out; } if (!exists) { - gf_log ("glusterd", GF_LOG_ERROR, - "Option %s does not exist", key); - ret = snprintf (msg, 2048, + ret = snprintf (msg, sizeof (msg), "Option %s does not exist", key); if (key_fixed) - snprintf (msg + ret, 2048 - ret, + snprintf (msg + ret, sizeof (msg) - ret, "\nDid you mean %s?", key_fixed); - *op_errstr = gf_strdup (msg); ret = -1; goto out; + } else if (exists > 0) { + if (key_fixed) + key = key_fixed; + ALL_VOLUME_OPTION_CHECK (volname, key, ret, + op_errstr, out); } } out: - if (key_fixed) - GF_FREE (key_fixed); + GF_FREE (key_fixed); - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + if (msg[0] != '\0') { + gf_log (this->name, GF_LOG_ERROR, "%s", msg); + *op_errstr = gf_strdup (msg); + } + + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } @@ -591,25 +994,7 @@ glusterd_op_stage_sync_volume (dict_t *dict, char **op_errstr) goto out; } - ret = glusterd_is_local_addr (hostname); - if (ret) { - ret = glusterd_friend_find (NULL, hostname, &peerinfo); - if (ret) { - snprintf (msg, sizeof (msg), "%s, is not a friend", - hostname); - *op_errstr = gf_strdup (msg); - goto out; - } - - if (!peerinfo->connected) { - snprintf (msg, sizeof (msg), "%s, is not connected at " - "the moment", hostname); - *op_errstr = gf_strdup (msg); - ret = -1; - goto out; - } - } else { - + if (gf_is_local_addr (hostname)) { //volname is not present in case of sync all ret = dict_get_str (dict, "volname", &volname); if (!ret) { @@ -625,12 +1010,26 @@ glusterd_op_stage_sync_volume (dict_t *dict, char **op_errstr) if (ret) goto out; - ret = glusterd_validate_volume_id (dict, volinfo); - if (ret) - goto out; } else { ret = 0; } + } else { + ret = glusterd_friend_find (NULL, hostname, &peerinfo); + if (ret) { + snprintf (msg, sizeof (msg), "%s, is not a friend", + hostname); + *op_errstr = gf_strdup (msg); + goto out; + } + + if (!peerinfo->connected) { + snprintf (msg, sizeof (msg), "%s, is not connected at " + "the moment", hostname); + *op_errstr = gf_strdup (msg); + ret = -1; + goto out; + } + } out: @@ -650,7 +1049,6 @@ glusterd_op_stage_status_volume (dict_t *dict, char **op_errstr) xlator_t *this = NULL; glusterd_conf_t *priv = NULL; glusterd_brickinfo_t *brickinfo = NULL; - glusterd_brickinfo_t *tmpbrickinfo = NULL; glusterd_volinfo_t *volinfo = NULL; dict_t *vol_opts = NULL; gf_boolean_t nfs_disabled = _gf_false; @@ -738,21 +1136,8 @@ glusterd_op_stage_status_volume (dict_t *dict, char **op_errstr) if (ret) goto out; - ret = glusterd_brickinfo_from_brick (brick, &brickinfo); - if (ret) { - snprintf (msg, sizeof (msg), "%s is not a brick", - brick); - gf_log (THIS->name, GF_LOG_ERROR, "%s", msg); - goto out; - } - - ret = glusterd_volume_brickinfo_get (NULL, - brickinfo->hostname, - brickinfo->path, - volinfo, - &tmpbrickinfo, - GF_PATH_COMPLETE); - + ret = glusterd_volume_brickinfo_get_by_brick (brick, volinfo, + &brickinfo); if (ret) { snprintf (msg, sizeof(msg), "No brick %s in" " volume %s", brick, volname); @@ -874,60 +1259,82 @@ out: } -void +static int _delete_reconfig_opt (dict_t *this, char *key, data_t *value, void *data) { - int exists = 0; - int32_t is_force = 0; + int32_t *is_force = 0; GF_ASSERT (data); - is_force = *((int32_t*)data); - exists = glusterd_check_option_exists(key, NULL); + is_force = (int32_t*)data; - if (exists != 1) - goto out; - - if ((!is_force) && - (_gf_true == glusterd_check_voloption_flags (key, - OPT_FLAG_FORCE))) - goto out; + if (*is_force != 1) { + if (_gf_true == glusterd_check_voloption_flags (key, + OPT_FLAG_FORCE)) { + /* indicate to caller that we don't set the option + * due to being protected + */ + *is_force = *is_force | GD_OP_PROTECTED; + goto out; + } else { + *is_force = *is_force | GD_OP_UNPROTECTED; + } + } gf_log ("", GF_LOG_DEBUG, "deleting dict with key=%s,value=%s", key, value->data); dict_del (this, key); out: - return; + return 0; } -int +static int +_delete_reconfig_global_opt (dict_t *this, char *key, data_t *value, void *data) +{ + int32_t *is_force = 0; + + GF_ASSERT (data); + is_force = (int32_t*)data; + + if (strcmp (GLUSTERD_GLOBAL_OPT_VERSION, key) == 0) + goto out; + + _delete_reconfig_opt (this, key, value, data); +out: + return 0; +} + +static int glusterd_options_reset (glusterd_volinfo_t *volinfo, char *key, - int32_t is_force) + int32_t *is_force) { int ret = 0; data_t *value = NULL; + char *key_fixed = NULL; + xlator_t *this = NULL; - gf_log ("", GF_LOG_DEBUG, "Received volume set reset command"); - + this = THIS; + GF_ASSERT (this); GF_ASSERT (volinfo->dict); GF_ASSERT (key); if (!strncmp(key, "all", 3)) - dict_foreach (volinfo->dict, _delete_reconfig_opt, &is_force); + dict_foreach (volinfo->dict, _delete_reconfig_opt, is_force); else { value = dict_get (volinfo->dict, key); if (!value) { - gf_log ("glusterd", GF_LOG_ERROR, - "Could not get value"); + gf_log (this->name, GF_LOG_DEBUG, + "no value set for option %s", key); goto out; } - _delete_reconfig_opt (volinfo->dict, key, value, &is_force); + _delete_reconfig_opt (volinfo->dict, key, value, is_force); } - ret = glusterd_create_volfiles_and_notify_services (volinfo); + gd_update_volume_op_versions (volinfo); + ret = glusterd_create_volfiles_and_notify_services (volinfo); if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to create volfile for" - " 'volume set'"); + gf_log (this->name, GF_LOG_ERROR, "Unable to create volfile for" + " 'volume reset'"); ret = -1; goto out; } @@ -945,23 +1352,120 @@ glusterd_options_reset (glusterd_volinfo_t *volinfo, char *key, ret = 0; out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + GF_FREE (key_fixed); + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } +static int +glusterd_op_reset_all_volume_options (xlator_t *this, dict_t *dict) +{ + char *key = NULL; + char *key_fixed = NULL; + int ret = -1; + int32_t is_force = 0; + glusterd_conf_t *conf = NULL; + dict_t *dup_opt = NULL; + gf_boolean_t all = _gf_false; + char *next_version = NULL; + gf_boolean_t quorum_action = _gf_false; + + conf = this->private; + ret = dict_get_str (dict, "key", &key); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get key"); + goto out; + } + + ret = dict_get_int32 (dict, "force", &is_force); + if (ret) + is_force = 0; + + if (strcmp (key, "all")) { + ret = glusterd_check_option_exists (key, &key_fixed); + if (ret <= 0) { + gf_log (this->name, GF_LOG_ERROR, "Option %s does not " + "exist", key); + ret = -1; + goto out; + } + } else { + all = _gf_true; + } + + if (key_fixed) + key = key_fixed; + + ret = -1; + dup_opt = dict_new (); + if (!dup_opt) + goto out; + if (!all) { + dict_copy (conf->opts, dup_opt); + dict_del (dup_opt, key); + } + ret = glusterd_get_next_global_opt_version_str (conf->opts, + &next_version); + if (ret) + goto out; + + ret = dict_set_str (dup_opt, GLUSTERD_GLOBAL_OPT_VERSION, next_version); + if (ret) + goto out; + + ret = glusterd_store_options (this, dup_opt); + if (ret) + goto out; + + if (glusterd_is_quorum_changed (conf->opts, key, NULL)) + quorum_action = _gf_true; + + ret = dict_set_dynstr (conf->opts, GLUSTERD_GLOBAL_OPT_VERSION, + next_version); + if (ret) + goto out; + else + next_version = NULL; + + if (!all) { + dict_del (conf->opts, key); + } else { + dict_foreach (conf->opts, _delete_reconfig_global_opt, + &is_force); + } +out: + GF_FREE (key_fixed); + if (dup_opt) + dict_unref (dup_opt); + + gf_log (this->name, GF_LOG_DEBUG, "returning %d", ret); + if (quorum_action) + glusterd_do_quorum_action (); + GF_FREE (next_version); + return ret; +} static int -glusterd_op_reset_volume (dict_t *dict) +glusterd_op_reset_volume (dict_t *dict, char **op_rspstr) { glusterd_volinfo_t *volinfo = NULL; int ret = -1; char *volname = NULL; char *key = NULL; + char *key_fixed = NULL; int32_t is_force = 0; + gf_boolean_t quorum_action = _gf_false; + xlator_t *this = NULL; + this = THIS; ret = dict_get_str (dict, "volname", &volname); if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to get volume name " ); + gf_log (this->name, GF_LOG_ERROR, "Unable to get volume name" ); + goto out; + } + + if (strcasecmp (volname, "all") == 0) { + ret = glusterd_op_reset_all_volume_options (this, dict); goto out; } @@ -971,32 +1475,64 @@ glusterd_op_reset_volume (dict_t *dict) ret = dict_get_str (dict, "key", &key); if (ret) { - gf_log ("glusterd", GF_LOG_ERROR, "Unable to get option key"); + gf_log (this->name, GF_LOG_ERROR, "Unable to get option key"); goto out; } ret = glusterd_volinfo_find (volname, &volinfo); if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to allocate memory"); + gf_log (this->name, GF_LOG_ERROR, FMTSTR_CHECK_VOL_EXISTS, + volname); goto out; } - ret = glusterd_options_reset (volinfo, key, is_force); + if (strcmp (key, "all") && + glusterd_check_option_exists (key, &key_fixed) != 1) { + gf_log (this->name, GF_LOG_ERROR, + "volinfo dict inconsistency: option %s not found", + key); + ret = -1; + goto out; + } + if (key_fixed) + key = key_fixed; + + if (glusterd_is_quorum_changed (volinfo->dict, key, NULL)) + quorum_action = _gf_true; + + ret = glusterd_options_reset (volinfo, key, &is_force); + if (ret == -1) { + gf_asprintf(op_rspstr, "Volume reset : failed"); + } else if (is_force & GD_OP_PROTECTED) { + if (is_force & GD_OP_UNPROTECTED) { + gf_asprintf (op_rspstr, "All unprotected fields were" + " reset. To reset the protected fields," + " use 'force'."); + } else { + ret = -1; + gf_asprintf (op_rspstr, "'%s' is protected. To reset" + " use 'force'.", key); + } + } out: - gf_log ("", GF_LOG_DEBUG, "'volume reset' returning %d", ret); - return ret; + GF_FREE (key_fixed); + if (quorum_action) + glusterd_do_quorum_action (); + gf_log (this->name, GF_LOG_DEBUG, "'volume reset' returning %d", ret); + return ret; } - int glusterd_stop_bricks (glusterd_volinfo_t *volinfo) { glusterd_brickinfo_t *brickinfo = NULL; list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { - if (glusterd_brick_stop (volinfo, brickinfo)) + /*TODO: Need to change @del_brick in brick_stop to _gf_true + * once we enable synctask in peer rpc prog */ + if (glusterd_brick_stop (volinfo, brickinfo, _gf_false)) return -1; } @@ -1006,32 +1542,109 @@ glusterd_stop_bricks (glusterd_volinfo_t *volinfo) int glusterd_start_bricks (glusterd_volinfo_t *volinfo) { - glusterd_brickinfo_t *brickinfo = NULL; + int ret = -1; + glusterd_brickinfo_t *brickinfo = NULL; + + GF_ASSERT (volinfo); list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { - if (glusterd_brick_start (volinfo, brickinfo)) - return -1; + ret = glusterd_brick_start (volinfo, brickinfo, _gf_false); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, + "Failed to start %s:%s for %s", + brickinfo->hostname, brickinfo->path, + volinfo->volname); + goto out; + } } - return 0; + ret = 0; +out: + return ret; } static int -glusterd_volset_help (dict_t *dict) +glusterd_op_set_all_volume_options (xlator_t *this, dict_t *dict) { - int ret = -1; - gf_boolean_t xml_out = _gf_false; + char *key = NULL; + char *key_fixed = NULL; + char *value = NULL; + char *dup_value = NULL; + int ret = -1; + glusterd_conf_t *conf = NULL; + dict_t *dup_opt = NULL; + char *next_version = NULL; + gf_boolean_t quorum_action = _gf_false; + + conf = this->private; + ret = dict_get_str (dict, "key1", &key); + if (ret) + goto out; + + ret = dict_get_str (dict, "value1", &value); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "invalid key,value pair in 'volume set'"); + goto out; + } + ret = glusterd_check_option_exists (key, &key_fixed); + if (ret <= 0) { + gf_log (this->name, GF_LOG_ERROR, "Invalid key %s", key); + ret = -1; + goto out; + } + + if (key_fixed) + key = key_fixed; + + ret = -1; + dup_opt = dict_new (); + if (!dup_opt) + goto out; + dict_copy (conf->opts, dup_opt); + ret = dict_set_str (dup_opt, key, value); + if (ret) + goto out; + + ret = glusterd_get_next_global_opt_version_str (conf->opts, + &next_version); + if (ret) + goto out; + + ret = dict_set_str (dup_opt, GLUSTERD_GLOBAL_OPT_VERSION, next_version); + if (ret) + goto out; + + dup_value = gf_strdup (value); + if (!dup_value) + goto out; + + ret = glusterd_store_options (this, dup_opt); + if (ret) + goto out; - if (dict_get (dict, "help" )) - xml_out = _gf_false; - else if (dict_get (dict, "help-xml" )) - xml_out = _gf_true; + if (glusterd_is_quorum_changed (conf->opts, key, value)) + quorum_action = _gf_true; + + ret = dict_set_dynstr (conf->opts, GLUSTERD_GLOBAL_OPT_VERSION, + next_version); + if (ret) + goto out; else + next_version = NULL; + + ret = dict_set_dynstr (conf->opts, key, dup_value); + if (ret) goto out; +out: + GF_FREE (key_fixed); + if (dup_opt) + dict_unref (dup_opt); - ret = glusterd_get_volopt_content (xml_out); - out: - gf_log ("glusterd", GF_LOG_DEBUG, "Returning %d", ret); + gf_log (this->name, GF_LOG_DEBUG, "returning %d", ret); + if (quorum_action) + glusterd_do_quorum_action (); + GF_FREE (next_version); return ret; } @@ -1048,9 +1661,14 @@ glusterd_op_set_volume (dict_t *dict) char *key_fixed = NULL; char *value = NULL; char str[50] = {0, }; + char *op_errstr = NULL; gf_boolean_t global_opt = _gf_false; + gf_boolean_t global_opts_set = _gf_false; glusterd_volinfo_t *voliter = NULL; int32_t dict_count = 0; + gf_boolean_t check_op_version = _gf_false; + uint32_t new_op_version = 0; + gf_boolean_t quorum_action = _gf_false; this = THIS; GF_ASSERT (this); @@ -1065,12 +1683,14 @@ glusterd_op_set_volume (dict_t *dict) } if (dict_count == 0) { - ret = glusterd_volset_help (dict); - if (ret) - gf_log (this->name, GF_LOG_ERROR, "Volume set" - " help internal error"); + ret = glusterd_volset_help (NULL, &op_errstr); + if (ret) { + op_errstr = (op_errstr)? op_errstr: + "Volume set help internal error"; + gf_log (this->name, GF_LOG_ERROR, "%s", op_errstr); + } goto out; - } + } ret = dict_get_str (dict, "volname", &volname); if (ret) { @@ -1078,15 +1698,33 @@ glusterd_op_set_volume (dict_t *dict) goto out; } + if (strcasecmp (volname, "all") == 0) { + ret = glusterd_op_set_all_volume_options (this, dict); + goto out; + } + ret = glusterd_volinfo_find (volname, &volinfo); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Unable to allocate memory"); + gf_log (this->name, GF_LOG_ERROR, FMTSTR_CHECK_VOL_EXISTS, + volname); goto out; } + // TODO: Remove this once v3.3 compatability is not required + check_op_version = dict_get_str_boolean (dict, "check-op-version", + _gf_false); + + if (check_op_version) { + ret = dict_get_uint32 (dict, "new-op-version", &new_op_version); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to get new op-version from dict"); + goto out; + } + } + for (count = 1; ret != -1 ; count++) { - global_opt = _gf_false; sprintf (str, "key%d", count); ret = dict_get_str (dict, str, &key); if (ret) @@ -1101,21 +1739,44 @@ glusterd_op_set_volume (dict_t *dict) goto out; } - if (strcmp (key, "memory-accounting") == 0) { + if (strcmp (key, "config.memory-accounting") == 0) { ret = gf_string2boolean (value, &volinfo->memory_accounting); - goto out; } - ret = glusterd_check_option_exists (key, &key_fixed); - GF_ASSERT (ret); - if (ret == -1) { - key_fixed = NULL; - goto out; + + if (strcmp (key, "config.transport") == 0) { + gf_log (this->name, GF_LOG_INFO, + "changing transport-type for volume %s to %s", + volname, value); + ret = 0; + if (strcasecmp (value, "rdma") == 0) { + volinfo->transport_type = GF_TRANSPORT_RDMA; + } else if (strcasecmp (value, "tcp") == 0) { + volinfo->transport_type = GF_TRANSPORT_TCP; + } else if ((strcasecmp (value, "tcp,rdma") == 0) || + (strcasecmp (value, "rdma,tcp") == 0)) { + volinfo->transport_type = + GF_TRANSPORT_BOTH_TCP_RDMA; + } else { + ret = -1; + goto out; + } } - ret = glusterd_check_globaloption (key); - if (ret) + if (!is_key_glusterd_hooks_friendly (key)) { + ret = glusterd_check_option_exists (key, &key_fixed); + GF_ASSERT (ret); + if (ret <= 0) { + key_fixed = NULL; + goto out; + } + } + + global_opt = _gf_false; + if (glusterd_check_globaloption (key)) { global_opt = _gf_true; + global_opts_set = _gf_true; + } if (!global_opt) value = gf_strdup (value); @@ -1130,6 +1791,9 @@ glusterd_op_set_volume (dict_t *dict) if (key_fixed) key = key_fixed; + if (glusterd_is_quorum_changed (volinfo->dict, key, value)) + quorum_action = _gf_true; + if (global_opt) { list_for_each_entry (voliter, &priv->volumes, vol_list) { value = gf_strdup (value); @@ -1155,7 +1819,21 @@ glusterd_op_set_volume (dict_t *dict) goto out; } - if (!global_opt) { + /* Update the cluster op-version before regenerating volfiles so that + * correct volfiles are generated + */ + if (new_op_version > priv->op_version) { + priv->op_version = new_op_version; + ret = glusterd_store_global_info (this); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to store op-version"); + goto out; + } + } + + if (!global_opts_set) { + gd_update_volume_op_versions (volinfo); ret = glusterd_create_volfiles_and_notify_services (volinfo); if (ret) { gf_log (this->name, GF_LOG_ERROR, @@ -1181,6 +1859,7 @@ glusterd_op_set_volume (dict_t *dict) } else { list_for_each_entry (voliter, &priv->volumes, vol_list) { volinfo = voliter; + gd_update_volume_op_versions (volinfo); ret = glusterd_create_volfiles_and_notify_services (volinfo); if (ret) { gf_log (this->name, GF_LOG_ERROR, @@ -1206,11 +1885,11 @@ glusterd_op_set_volume (dict_t *dict) } } - ret = 0; out: - if (key_fixed) - GF_FREE (key_fixed); + GF_FREE (key_fixed); gf_log (this->name, GF_LOG_DEBUG, "returning %d", ret); + if (quorum_action) + glusterd_do_quorum_action (); return ret; } @@ -1242,7 +1921,7 @@ glusterd_op_sync_volume (dict_t *dict, char **op_errstr, goto out; } - if (glusterd_is_local_addr (hostname)) { + if (!gf_is_local_addr (hostname)) { ret = 0; goto out; } @@ -1413,6 +2092,241 @@ out: } static int +_add_brick_name_to_dict (dict_t *dict, char *key, glusterd_brickinfo_t *brick) +{ + int ret = -1; + char tmp[1024] = {0,}; + char *brickname = NULL; + xlator_t *this = NULL; + + GF_ASSERT (dict); + GF_ASSERT (key); + GF_ASSERT (brick); + + this = THIS; + GF_ASSERT (this); + + snprintf (tmp, sizeof (tmp), "%s:%s", brick->hostname, brick->path); + brickname = gf_strdup (tmp); + if (!brickname) { + gf_log (this->name, GF_LOG_ERROR, "Failed to dup brick name"); + goto out; + } + + ret = dict_set_dynstr (dict, key, brickname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to add brick name to dict"); + goto out; + } + brickname = NULL; +out: + if (brickname) + GF_FREE (brickname); + return ret; +} + +static int +_add_remove_bricks_to_dict (dict_t *dict, glusterd_volinfo_t *volinfo, + char *prefix) +{ + int ret = -1; + int count = 0; + int i = 0; + char brick_key[1024] = {0,}; + char dict_key[1024] ={0,}; + char *brick = NULL; + xlator_t *this = NULL; + + GF_ASSERT (dict); + GF_ASSERT (volinfo); + GF_ASSERT (prefix); + + this = THIS; + GF_ASSERT (this); + + ret = dict_get_int32 (volinfo->rebal.dict, "count", &count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to get brick count"); + goto out; + } + + snprintf (dict_key, sizeof (dict_key), "%s.count", prefix); + ret = dict_set_int32 (dict, dict_key, count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set brick count in dict"); + goto out; + } + + for (i = 1; i <= count; i++) { + memset (brick_key, 0, sizeof (brick_key)); + snprintf (brick_key, sizeof (brick_key), "brick%d", i); + + ret = dict_get_str (volinfo->rebal.dict, brick_key, &brick); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to get %s", brick_key); + goto out; + } + + memset (dict_key, 0, sizeof (dict_key)); + snprintf (dict_key, sizeof (dict_key), "%s.%s", prefix, + brick_key); + ret = dict_set_str (dict, dict_key, brick); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to add brick to dict"); + goto out; + } + brick = NULL; + } + +out: + return ret; +} + +/* This adds the respective task-id and all available parameters of a task into + * a dictionary + */ +static int +_add_task_to_dict (dict_t *dict, glusterd_volinfo_t *volinfo, int op, int index) +{ + + int ret = -1; + char key[128] = {0,}; + char *uuid_str = NULL; + int status = 0; + xlator_t *this = NULL; + + GF_ASSERT (dict); + GF_ASSERT (volinfo); + + this = THIS; + GF_ASSERT (this); + + switch (op) { + case GD_OP_REMOVE_BRICK: + snprintf (key, sizeof (key), "task%d", index); + ret = _add_remove_bricks_to_dict (dict, volinfo, key); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to add remove bricks to dict"); + goto out; + } + case GD_OP_REBALANCE: + uuid_str = gf_strdup (uuid_utoa (volinfo->rebal.rebalance_id)); + status = volinfo->rebal.defrag_status; + break; + + case GD_OP_REPLACE_BRICK: + snprintf (key, sizeof (key), "task%d.src-brick", index); + ret = _add_brick_name_to_dict (dict, key, + volinfo->rep_brick.src_brick); + if (ret) + goto out; + memset (key, 0, sizeof (key)); + + snprintf (key, sizeof (key), "task%d.dst-brick", index); + ret = _add_brick_name_to_dict (dict, key, + volinfo->rep_brick.dst_brick); + if (ret) + goto out; + memset (key, 0, sizeof (key)); + + uuid_str = gf_strdup (uuid_utoa (volinfo->rep_brick.rb_id)); + status = volinfo->rep_brick.rb_status; + break; + + default: + ret = -1; + gf_log (this->name, GF_LOG_ERROR, "%s operation doesn't have a" + " task_id", gd_op_list[op]); + goto out; + } + + snprintf (key, sizeof (key), "task%d.type", index); + ret = dict_set_str (dict, key, (char *)gd_op_list[op]); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Error setting task type in dict"); + goto out; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "task%d.id", index); + + if (!uuid_str) + goto out; + ret = dict_set_dynstr (dict, key, uuid_str); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Error setting task id in dict"); + goto out; + } + uuid_str = NULL; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "task%d.status", index); + ret = dict_set_int32 (dict, key, status); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Error setting task status in dict"); + goto out; + } + +out: + if (uuid_str) + GF_FREE (uuid_str); + return ret; +} + +static int +glusterd_aggregate_task_status (dict_t *rsp_dict, glusterd_volinfo_t *volinfo) +{ + int ret = -1; + int tasks = 0; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + + if (!uuid_is_null (volinfo->rebal.rebalance_id)) { + ret = _add_task_to_dict (rsp_dict, volinfo, volinfo->rebal.op, + tasks); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to add task details to dict"); + goto out; + } + tasks++; + } + + if (!uuid_is_null (volinfo->rep_brick.rb_id)) { + ret = _add_task_to_dict (rsp_dict, volinfo, GD_OP_REPLACE_BRICK, + tasks); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to add task details to dict"); + goto out; + } + tasks++; + } + + ret = dict_set_int32 (rsp_dict, "tasks", tasks); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Error setting tasks count in dict"); + goto out; + } + ret = 0; + +out: + return ret; +} + +static int glusterd_op_status_volume (dict_t *dict, char **op_errstr, dict_t *rsp_dict) { @@ -1431,6 +2345,7 @@ glusterd_op_status_volume (dict_t *dict, char **op_errstr, dict_t *vol_opts = NULL; gf_boolean_t nfs_disabled = _gf_false; gf_boolean_t shd_enabled = _gf_true; + gf_boolean_t origin_glusterd = _gf_false; this = THIS; GF_ASSERT (this); @@ -1440,23 +2355,21 @@ glusterd_op_status_volume (dict_t *dict, char **op_errstr, GF_ASSERT (dict); + origin_glusterd = is_origin_glusterd (dict); + ret = dict_get_uint32 (dict, "cmd", &cmd); if (ret) goto out; - if (!rsp_dict) { - //this should happen only on source + if (origin_glusterd) { ret = 0; - rsp_dict = glusterd_op_get_ctx (); - if ((cmd & GF_CLI_STATUS_ALL)) { ret = glusterd_get_all_volnames (rsp_dict); if (ret) - gf_log (THIS->name, GF_LOG_ERROR, + gf_log (this->name, GF_LOG_ERROR, "failed to get all volume " "names for status"); } - } ret = dict_set_uint32 (rsp_dict, "cmd", cmd); @@ -1472,7 +2385,7 @@ glusterd_op_status_volume (dict_t *dict, char **op_errstr, ret = glusterd_volinfo_find (volname, &volinfo); if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, "Volume with name: %s " + gf_log (this->name, GF_LOG_ERROR, "Volume with name: %s " "does not exist", volname); goto out; } @@ -1500,12 +2413,11 @@ glusterd_op_status_volume (dict_t *dict, char **op_errstr, ret = glusterd_volume_brickinfo_get_by_brick (brick, volinfo, - &brickinfo, - GF_PATH_COMPLETE); + &brickinfo); if (ret) goto out; - if (uuid_compare (brickinfo->uuid, priv->uuid)) + if (uuid_compare (brickinfo->uuid, MY_UUID)) goto out; glusterd_add_brick_to_dict (volinfo, brickinfo, rsp_dict, @@ -1516,10 +2428,14 @@ glusterd_op_status_volume (dict_t *dict, char **op_errstr, brick_index); node_count++; + } else if ((cmd & GF_CLI_STATUS_TASKS) != 0) { + ret = glusterd_aggregate_task_status (rsp_dict, volinfo); + goto out; + } else { list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { brick_index++; - if (uuid_compare (brickinfo->uuid, priv->uuid)) + if (uuid_compare (brickinfo->uuid, MY_UUID)) continue; glusterd_add_brick_to_dict (volinfo, brickinfo, @@ -1571,23 +2487,39 @@ glusterd_op_status_volume (dict_t *dict, char **op_errstr, ret = dict_set_int32 (rsp_dict, "brick-index-max", brick_index); if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, + gf_log (this->name, GF_LOG_ERROR, "Error setting brick-index-max to dict"); goto out; } ret = dict_set_int32 (rsp_dict, "other-count", other_count); if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, + gf_log (this->name, GF_LOG_ERROR, "Error setting other-count to dict"); goto out; } ret = dict_set_int32 (rsp_dict, "count", node_count); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Error setting node count to dict"); + goto out; + } + + /* Active tasks */ + /* Tasks are added only for normal volume status request for either a + * single volume or all volumes, and only by the origin glusterd + */ + if (((cmd & GF_CLI_STATUS_MASK) != GF_CLI_STATUS_NONE) || + !(cmd & (GF_CLI_STATUS_VOL | GF_CLI_STATUS_ALL)) || + !origin_glusterd) + goto out; + + ret = glusterd_aggregate_task_status (rsp_dict, volinfo); + if (ret) + goto out; + ret = 0; out: - gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret); + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } @@ -1597,7 +2529,7 @@ glusterd_op_ac_none (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + gf_log (THIS->name, GF_LOG_DEBUG, "Returning with %d", ret); return ret; } @@ -1611,6 +2543,7 @@ glusterd_op_ac_send_lock (glusterd_op_sm_event_t *event, void *ctx) xlator_t *this = NULL; glusterd_peerinfo_t *peerinfo = NULL; uint32_t pending_count = 0; + dict_t *dict = NULL; this = THIS; priv = this->private; @@ -1625,21 +2558,60 @@ glusterd_op_ac_send_lock (glusterd_op_sm_event_t *event, void *ctx) (glusterd_op_get_op() != GD_OP_SYNC_VOLUME)) continue; - proc = &peerinfo->mgmt->proctable[GLUSTERD_MGMT_CLUSTER_LOCK]; - if (proc->fn) { - ret = proc->fn (NULL, this, peerinfo); - if (ret) - continue; - pending_count++; + /* Based on the op_version, acquire a cluster or mgmt_v3 lock */ + if (priv->op_version < 3) { + proc = &peerinfo->mgmt->proctable[GLUSTERD_MGMT_CLUSTER_LOCK]; + if (proc->fn) { + ret = proc->fn (NULL, this, peerinfo); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, + "Failed to send lock request " + "for operation 'Volume %s' to " + "peer %s", + gd_op_list[opinfo.op], + peerinfo->hostname); + continue; + } + pending_count++; + } + } else { + dict = glusterd_op_get_ctx (); + dict_ref (dict); + + proc = &peerinfo->mgmt_v3->proctable + [GLUSTERD_MGMT_V3_LOCK]; + if (proc->fn) { + ret = dict_set_static_ptr (dict, "peerinfo", + peerinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to set peerinfo"); + dict_unref (dict); + goto out; + } + + ret = proc->fn (NULL, this, dict); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, + "Failed to send mgmt_v3 lock " + "request for operation " + "'Volume %s' to peer %s", + gd_op_list[opinfo.op], + peerinfo->hostname); + dict_unref (dict); + continue; + } + pending_count++; + } } } opinfo.pending_count = pending_count; if (!opinfo.pending_count) - ret = glusterd_op_sm_inject_all_acc (); - - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + ret = glusterd_op_sm_inject_all_acc (&event->txn_id); +out: + gf_log (this->name, GF_LOG_DEBUG, "Returning with %d", ret); return ret; } @@ -1652,17 +2624,12 @@ glusterd_op_ac_send_unlock (glusterd_op_sm_event_t *event, void *ctx) xlator_t *this = NULL; glusterd_peerinfo_t *peerinfo = NULL; uint32_t pending_count = 0; + dict_t *dict = NULL; this = THIS; priv = this->private; GF_ASSERT (priv); - /*ret = glusterd_unlock (priv->uuid); - - if (ret) - goto out; - */ - list_for_each_entry (peerinfo, &priv->peers, uuid_list) { GF_ASSERT (peerinfo); @@ -1672,23 +2639,62 @@ glusterd_op_ac_send_unlock (glusterd_op_sm_event_t *event, void *ctx) (glusterd_op_get_op() != GD_OP_SYNC_VOLUME)) continue; - proc = &peerinfo->mgmt->proctable[GLUSTERD_MGMT_CLUSTER_UNLOCK]; - if (proc->fn) { - ret = proc->fn (NULL, this, peerinfo); - if (ret) - continue; - pending_count++; + /* Based on the op_version, release the * + * cluster or mgmt_v3 lock */ + if (priv->op_version < 3) { + proc = &peerinfo->mgmt->proctable[GLUSTERD_MGMT_CLUSTER_UNLOCK]; + if (proc->fn) { + ret = proc->fn (NULL, this, peerinfo); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, + "Failed to send unlock request " + "for operation 'Volume %s' to " + "peer %s", + gd_op_list[opinfo.op], + peerinfo->hostname); + continue; + } + pending_count++; + } + } else { + dict = glusterd_op_get_ctx (); + dict_ref (dict); + + proc = &peerinfo->mgmt_v3->proctable + [GLUSTERD_MGMT_V3_UNLOCK]; + if (proc->fn) { + ret = dict_set_static_ptr (dict, "peerinfo", + peerinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to set peerinfo"); + dict_unref (dict); + goto out; + } + + ret = proc->fn (NULL, this, dict); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, + "Failed to send mgmt_v3 unlock " + "request for operation " + "'Volume %s' to peer %s", + gd_op_list[opinfo.op], + peerinfo->hostname); + dict_unref (dict); + continue; + } + pending_count++; + } } } opinfo.pending_count = pending_count; if (!opinfo.pending_count) - ret = glusterd_op_sm_inject_all_acc (); - - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + ret = glusterd_op_sm_inject_all_acc (&event->txn_id); +out: + gf_log (this->name, GF_LOG_DEBUG, "Returning with %d", ret); return ret; - } static int @@ -1700,9 +2706,10 @@ glusterd_op_ac_ack_drain (glusterd_op_sm_event_t *event, void *ctx) opinfo.pending_count--; if (!opinfo.pending_count) - ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACK, NULL); + ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACK, + &event->txn_id, NULL); - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + gf_log (THIS->name, GF_LOG_DEBUG, "Returning with %d", ret); return ret; } @@ -1716,41 +2723,97 @@ glusterd_op_ac_send_unlock_drain (glusterd_op_sm_event_t *event, void *ctx) static int glusterd_op_ac_lock (glusterd_op_sm_event_t *event, void *ctx) { - glusterd_op_lock_ctx_t *lock_ctx = NULL; - int32_t ret = 0; - + int32_t ret = 0; + char *volname = NULL; + glusterd_op_lock_ctx_t *lock_ctx = NULL; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; GF_ASSERT (event); GF_ASSERT (ctx); + this = THIS; + priv = this->private; + lock_ctx = (glusterd_op_lock_ctx_t *)ctx; - ret = glusterd_lock (lock_ctx->uuid); + /* If the req came from a node running on older op_version + * the dict won't be present. Based on it acquiring a cluster + * or mgmt_v3 lock */ + if (lock_ctx->dict == NULL) { + ret = glusterd_lock (lock_ctx->uuid); + glusterd_op_lock_send_resp (lock_ctx->req, ret); + } else { + ret = dict_get_str (lock_ctx->dict, "volname", &volname); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Unable to acquire volname"); + else { + ret = glusterd_mgmt_v3_lock (volname, lock_ctx->uuid, + "vol"); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Unable to acquire lock for %s", + volname); + } - gf_log ("", GF_LOG_DEBUG, "Lock Returned %d", ret); + glusterd_op_mgmt_v3_lock_send_resp (lock_ctx->req, + &event->txn_id, ret); - glusterd_op_lock_send_resp (lock_ctx->req, ret); + dict_unref (lock_ctx->dict); + } + gf_log (THIS->name, GF_LOG_DEBUG, "Lock Returned %d", ret); return ret; } static int glusterd_op_ac_unlock (glusterd_op_sm_event_t *event, void *ctx) { - int ret = 0; - glusterd_op_lock_ctx_t *lock_ctx = NULL; + int32_t ret = 0; + char *volname = NULL; + glusterd_op_lock_ctx_t *lock_ctx = NULL; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + GF_ASSERT (event); GF_ASSERT (ctx); + this = THIS; + priv = this->private; + lock_ctx = (glusterd_op_lock_ctx_t *)ctx; - ret = glusterd_unlock (lock_ctx->uuid); + /* If the req came from a node running on older op_version + * the dict won't be present. Based on it releasing the cluster + * or mgmt_v3 lock */ + if (lock_ctx->dict == NULL) { + ret = glusterd_unlock (lock_ctx->uuid); + glusterd_op_unlock_send_resp (lock_ctx->req, ret); + } else { + ret = dict_get_str (lock_ctx->dict, "volname", &volname); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Unable to acquire volname"); + else { + ret = glusterd_mgmt_v3_unlock (volname, lock_ctx->uuid, + "vol"); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Unable to release lock for %s", volname); + } + + glusterd_op_mgmt_v3_unlock_send_resp (lock_ctx->req, + &event->txn_id, ret); - gf_log ("", GF_LOG_DEBUG, "Unlock Returned %d", ret); + dict_unref (lock_ctx->dict); + } - glusterd_op_unlock_send_resp (lock_ctx->req, ret); + gf_log (this->name, GF_LOG_DEBUG, "Unlock Returned %d", ret); + if (priv->pending_quorum_action) + glusterd_do_quorum_action (); return ret; } @@ -1767,7 +2830,7 @@ glusterd_op_ac_local_unlock (glusterd_op_sm_event_t *event, void *ctx) ret = glusterd_unlock (*originator); - gf_log ("", GF_LOG_DEBUG, "Unlock Returned %d", ret); + gf_log (THIS->name, GF_LOG_DEBUG, "Unlock Returned %d", ret); return ret; } @@ -1785,9 +2848,10 @@ glusterd_op_ac_rcvd_lock_acc (glusterd_op_sm_event_t *event, void *ctx) if (opinfo.pending_count > 0) goto out; - ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACC, NULL); + ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACC, + &event->txn_id, NULL); - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret); out: return ret; @@ -1800,16 +2864,17 @@ glusterd_dict_set_volid (dict_t *dict, char *volname, char **op_errstr) glusterd_volinfo_t *volinfo = NULL; char *volid = NULL; char msg[1024] = {0,}; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); if (!dict || !volname) goto out; ret = glusterd_volinfo_find (volname, &volinfo); if (ret) { - snprintf (msg, sizeof (msg), "Volume %s does not exist", - volname); - gf_log (THIS->name, GF_LOG_ERROR, "%s", msg); - *op_errstr = gf_strdup (msg); + snprintf (msg, sizeof (msg), FMTSTR_CHECK_VOL_EXISTS, volname); goto out; } volid = gf_strdup (uuid_utoa (volinfo->volume_id)); @@ -1819,102 +2884,151 @@ glusterd_dict_set_volid (dict_t *dict, char *volname, char **op_errstr) } ret = dict_set_dynstr (dict, "vol-id", volid); if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, - "Failed to set volume id in dictionary"); + snprintf (msg, sizeof (msg), "Failed to set volume id of volume" + " %s", volname); goto out; } out: + if (msg[0] != '\0') { + gf_log (this->name, GF_LOG_ERROR, "%s", msg); + *op_errstr = gf_strdup (msg); + } return ret; } int -glusterd_op_build_payload (dict_t **req, char **op_errstr) +glusterd_op_build_payload (dict_t **req, char **op_errstr, dict_t *op_ctx) { int ret = -1; void *ctx = NULL; + dict_t *dict = NULL; dict_t *req_dict = NULL; glusterd_op_t op = GD_OP_NONE; char *volname = NULL; uint32_t status_cmd = GF_CLI_STATUS_NONE; char *errstr = NULL; + xlator_t *this = NULL; GF_ASSERT (req); + this = THIS; + GF_ASSERT (this); + req_dict = dict_new (); if (!req_dict) goto out; - op = glusterd_op_get_op (); - ctx = (void*)glusterd_op_get_ctx (); - if (!ctx) { - gf_log ("", GF_LOG_ERROR, "Null Context for " - "op %d", op); - ret = -1; - goto out; + if (!op_ctx) { + op = glusterd_op_get_op (); + ctx = (void*)glusterd_op_get_ctx (); + if (!ctx) { + gf_log (this->name, GF_LOG_ERROR, "Null Context for " + "op %d", op); + ret = -1; + goto out; + } + + } else { +#define GD_SYNC_OPCODE_KEY "sync-mgmt-operation" + ret = dict_get_int32 (op_ctx, GD_SYNC_OPCODE_KEY, (int32_t*)&op); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get volume" + " operation"); + goto out; + } + ctx = op_ctx; +#undef GD_SYNC_OPCODE_KEY } + dict = ctx; switch (op) { case GD_OP_CREATE_VOLUME: { - dict_t *dict = ctx; ++glusterfs_port; ret = dict_set_int32 (dict, "port", glusterfs_port); - if (ret) + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set port in " + "dictionary"); goto out; + } dict_copy (dict, req_dict); } break; + case GD_OP_GSYNC_CREATE: case GD_OP_GSYNC_SET: { - dict_t *dict = ctx; ret = glusterd_op_gsync_args_get (dict, &errstr, &volname, - NULL); - if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, - "%s", errstr); - goto out; + NULL, NULL); + if (ret == 0) { + ret = glusterd_dict_set_volid + (dict, volname, op_errstr); + if (ret) + goto out; } - - ret = glusterd_dict_set_volid (dict, volname, - op_errstr); - if (ret) - goto out; dict_copy (dict, req_dict); } break; case GD_OP_SET_VOLUME: { - dict_t *dict = ctx; ret = dict_get_str (dict, "volname", &volname); if (ret) { - gf_log (THIS->name, GF_LOG_CRITICAL, + gf_log (this->name, GF_LOG_CRITICAL, "volname is not present in " "operation ctx"); goto out; } if (strcmp (volname, "help") && - strcmp (volname, "help-xml")) { + strcmp (volname, "help-xml") && + strcasecmp (volname, "all")) { ret = glusterd_dict_set_volid - (dict, volname, op_errstr); + (dict, volname, op_errstr); if (ret) goto out; } + dict_destroy (req_dict); + req_dict = dict_ref (dict); + } + break; + + case GD_OP_SYNC_VOLUME: + { dict_copy (dict, req_dict); + break; + } + + case GD_OP_REMOVE_BRICK: + { + dict_t *dict = ctx; + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + gf_log (this->name, GF_LOG_CRITICAL, + "volname is not present in " + "operation ctx"); + goto out; + } + + ret = glusterd_dict_set_volid (dict, volname, + op_errstr); + if (ret) + goto out; + + dict_destroy (req_dict); + req_dict = dict_ref (dict); } break; case GD_OP_STATUS_VOLUME: { - dict_t *dict = ctx; ret = dict_get_uint32 (dict, "cmd", &status_cmd); if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, + gf_log (this->name, GF_LOG_ERROR, "Status command not present " "in op ctx"); goto out; @@ -1924,16 +3038,14 @@ glusterd_op_build_payload (dict_t **req, char **op_errstr) break; } } - + /*fall-through*/ case GD_OP_DELETE_VOLUME: case GD_OP_START_VOLUME: case GD_OP_STOP_VOLUME: case GD_OP_ADD_BRICK: case GD_OP_REPLACE_BRICK: case GD_OP_RESET_VOLUME: - case GD_OP_REMOVE_BRICK: case GD_OP_LOG_ROTATE: - case GD_OP_SYNC_VOLUME: case GD_OP_QUOTA: case GD_OP_PROFILE_VOLUME: case GD_OP_REBALANCE: @@ -1942,23 +3054,37 @@ glusterd_op_build_payload (dict_t **req, char **op_errstr) case GD_OP_CLEARLOCKS_VOLUME: case GD_OP_DEFRAG_BRICK_VOLUME: { - dict_t *dict = ctx; ret = dict_get_str (dict, "volname", &volname); if (ret) { - gf_log (THIS->name, GF_LOG_CRITICAL, + gf_log (this->name, GF_LOG_CRITICAL, "volname is not present in " "operation ctx"); goto out; } - ret = glusterd_dict_set_volid (dict, volname, - op_errstr); - if (ret) - goto out; + if (strcasecmp (volname, "all")) { + ret = glusterd_dict_set_volid (dict, + volname, + op_errstr); + if (ret) + goto out; + } dict_copy (dict, req_dict); } break; + case GD_OP_COPY_FILE: + { + dict_copy (dict, req_dict); + break; + } + + case GD_OP_SYS_EXEC: + { + dict_copy (dict, req_dict); + break; + } + default: break; } @@ -1970,6 +3096,105 @@ out: return ret; } +gf_boolean_t +glusterd_is_get_op (xlator_t *this, glusterd_op_t op, dict_t *dict) +{ + char *key = NULL; + char *volname = NULL; + int ret = 0; + + if (op == GD_OP_STATUS_VOLUME) + return _gf_true; + + if ((op == GD_OP_SET_VOLUME)) { + //check for set volume help + ret = dict_get_str (dict, "volname", &volname); + if (volname && + ((strcmp (volname, "help") == 0) || + (strcmp (volname, "help-xml") == 0))) { + ret = dict_get_str (dict, "key1", &key); + if (ret < 0) + return _gf_true; + } + } + + return _gf_false; +} + +gf_boolean_t +glusterd_is_op_quorum_validation_required (xlator_t *this, glusterd_op_t op, + dict_t *dict) +{ + gf_boolean_t required = _gf_true; + char *key = NULL; + char *key_fixed = NULL; + int ret = -1; + + if (glusterd_is_get_op (this, op, dict)) { + required = _gf_false; + goto out; + } + if ((op != GD_OP_SET_VOLUME) && (op != GD_OP_RESET_VOLUME)) + goto out; + if (op == GD_OP_SET_VOLUME) + ret = dict_get_str (dict, "key1", &key); + else if (op == GD_OP_RESET_VOLUME) + ret = dict_get_str (dict, "key", &key); + if (ret) + goto out; + ret = glusterd_check_option_exists (key, &key_fixed); + if (ret <= 0) + goto out; + if (key_fixed) + key = key_fixed; + if (glusterd_is_quorum_option (key)) + required = _gf_false; +out: + GF_FREE (key_fixed); + return required; +} + +static int +glusterd_op_validate_quorum (xlator_t *this, glusterd_op_t op, + dict_t *dict, char **op_errstr) +{ + int ret = 0; + char *volname = NULL; + glusterd_volinfo_t *volinfo = NULL; + char *errstr = NULL; + + + errstr = "Quorum not met. Volume operation not allowed."; + if (!glusterd_is_op_quorum_validation_required (this, op, dict)) + goto out; + + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + ret = 0; + goto out; + } + + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + ret = 0; + goto out; + } + + if (does_gd_meet_server_quorum (this)) { + ret = 0; + goto out; + } + + if (glusterd_is_volume_in_server_quorum (volinfo)) { + ret = -1; + *op_errstr = gf_strdup (errstr); + goto out; + } + ret = 0; +out: + return ret; +} + static int glusterd_op_ac_send_stage_op (glusterd_op_sm_event_t *event, void *ctx) { @@ -1990,9 +3215,19 @@ glusterd_op_ac_send_stage_op (glusterd_op_sm_event_t *event, void *ctx) op = glusterd_op_get_op (); - ret = glusterd_op_build_payload (&dict, &op_errstr); + ret = glusterd_op_build_payload (&dict, &op_errstr, NULL); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, LOGSTR_BUILD_PAYLOAD, + gd_op_list[op]); + if (op_errstr == NULL) + gf_asprintf (&op_errstr, OPERRSTR_BUILD_PAYLOAD); + opinfo.op_errstr = op_errstr; + goto out; + } + + ret = glusterd_op_validate_quorum (this, op, dict, &op_errstr); if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, "Building payload failed"); + gf_log (this->name, GF_LOG_ERROR, "%s", op_errstr); opinfo.op_errstr = op_errstr; goto out; } @@ -2000,7 +3235,12 @@ glusterd_op_ac_send_stage_op (glusterd_op_sm_event_t *event, void *ctx) /* rsp_dict NULL from source */ ret = glusterd_op_stage_validate (op, dict, &op_errstr, NULL); if (ret) { - gf_log ("", GF_LOG_ERROR, "Staging failed"); + gf_log (this->name, GF_LOG_ERROR, LOGSTR_STAGE_FAIL, + gd_op_list[op], "localhost", + (op_errstr) ? ":" : " ", (op_errstr) ? op_errstr : " "); + if (op_errstr == NULL) + gf_asprintf (&op_errstr, OPERRSTR_STAGE_FAIL, + "localhost"); opinfo.op_errstr = op_errstr; goto out; } @@ -2019,13 +3259,19 @@ glusterd_op_ac_send_stage_op (glusterd_op_sm_event_t *event, void *ctx) if (proc->fn) { ret = dict_set_static_ptr (dict, "peerinfo", peerinfo); if (ret) { - gf_log ("", GF_LOG_ERROR, "failed to set peerinfo"); + gf_log (this->name, GF_LOG_ERROR, "failed to " + "set peerinfo"); goto out; } ret = proc->fn (NULL, this, dict); - if (ret) + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Failed to " + "send stage request for operation " + "'Volume %s' to peer %s", + gd_op_list[op], peerinfo->hostname); continue; + } pending_count++; } } @@ -2035,27 +3281,29 @@ out: if (dict) dict_unref (dict); if (ret) { - glusterd_op_sm_inject_event (GD_OP_EVENT_RCVD_RJT, NULL); + glusterd_op_sm_inject_event (GD_OP_EVENT_RCVD_RJT, + &event->txn_id, NULL); opinfo.op_ret = ret; } - gf_log ("glusterd", GF_LOG_INFO, "Sent op req to %d peers", + gf_log (this->name, GF_LOG_DEBUG, "Sent stage op request for " + "'Volume %s' to %d peers", gd_op_list[op], opinfo.pending_count); if (!opinfo.pending_count) - ret = glusterd_op_sm_inject_all_acc (); + ret = glusterd_op_sm_inject_all_acc (&event->txn_id); - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + gf_log (this->name, GF_LOG_DEBUG, "Returning with %d", ret); return ret; } static int32_t -glusterd_op_start_rb_timer (dict_t *dict) +glusterd_op_start_rb_timer (dict_t *dict, uuid_t *txn_id) { int32_t op = 0; - struct timeval timeout = {0, }; + struct timespec timeout = {0, }; glusterd_conf_t *priv = NULL; int32_t ret = -1; dict_t *rb_ctx = NULL; @@ -2071,12 +3319,12 @@ glusterd_op_start_rb_timer (dict_t *dict) } if (op != GF_REPLACE_OP_START) { - ret = glusterd_op_sm_inject_all_acc (); + ret = glusterd_op_sm_inject_all_acc (txn_id); goto out; } timeout.tv_sec = 5; - timeout.tv_usec = 0; + timeout.tv_nsec = 0; rb_ctx = dict_copy (dict, rb_ctx); @@ -2086,6 +3334,17 @@ glusterd_op_start_rb_timer (dict_t *dict) ret = -1; goto out; } + + ret = dict_set_bin (rb_ctx, "transaction_id", + txn_id, sizeof(*txn_id)); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Failed to set transaction id."); + goto out; + } else + gf_log ("", GF_LOG_DEBUG, + "transaction_id = %s", uuid_utoa (*txn_id)); + priv->timer = gf_timer_call_after (THIS->ctx, timeout, glusterd_do_replace_brick, (void *) rb_ctx); @@ -2109,6 +3368,10 @@ glusterd_op_volume_dict_uuid_to_hostname (dict_t *dict, const char *key_fmt, char *uuid_str = NULL; uuid_t uuid = {0,}; char *hostname = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); GF_ASSERT (dict); GF_ASSERT (key_fmt); @@ -2120,7 +3383,7 @@ glusterd_op_volume_dict_uuid_to_hostname (dict_t *dict, const char *key_fmt, if (ret) continue; - gf_log (THIS->name, GF_LOG_DEBUG, "Got uuid %s", + gf_log (this->name, GF_LOG_DEBUG, "Got uuid %s", uuid_str); ret = uuid_parse (uuid_str, uuid); @@ -2132,12 +3395,13 @@ glusterd_op_volume_dict_uuid_to_hostname (dict_t *dict, const char *key_fmt, hostname = glusterd_uuid_to_hostname (uuid); if (hostname) { - gf_log (THIS->name, GF_LOG_DEBUG, "%s -> %s", + gf_log (this->name, GF_LOG_DEBUG, "%s -> %s", uuid_str, hostname); ret = dict_set_dynstr (dict, key, hostname); if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, - "Error setting hostname to dict"); + gf_log (this->name, GF_LOG_ERROR, + "Error setting hostname %s to dict", + hostname); GF_FREE (hostname); goto out; } @@ -2145,16 +3409,107 @@ glusterd_op_volume_dict_uuid_to_hostname (dict_t *dict, const char *key_fmt, } out: - gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret); + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } +static int +reassign_defrag_status (dict_t *dict, char *key, gf_defrag_status_t *status) +{ + int ret = 0; + + if (!*status) + return ret; + + switch (*status) { + case GF_DEFRAG_STATUS_STARTED: + *status = GF_DEFRAG_STATUS_LAYOUT_FIX_STARTED; + break; + + case GF_DEFRAG_STATUS_STOPPED: + *status = GF_DEFRAG_STATUS_LAYOUT_FIX_STOPPED; + break; + + case GF_DEFRAG_STATUS_COMPLETE: + *status = GF_DEFRAG_STATUS_LAYOUT_FIX_COMPLETE; + break; + + case GF_DEFRAG_STATUS_FAILED: + *status = GF_DEFRAG_STATUS_LAYOUT_FIX_FAILED; + break; + default: + break; + } + + ret = dict_set_int32(dict, key, *status); + if (ret) + gf_log (THIS->name, GF_LOG_WARNING, + "failed to reset defrag %s in dict", key); + + return ret; +} + +/* Check and reassign the defrag_status enum got from the rebalance process + * of all peers so that the rebalance-status CLI command can display if a + * full-rebalance or just a fix-layout was carried out. + */ +static int +glusterd_op_check_peer_defrag_status (dict_t *dict, int count) +{ + glusterd_volinfo_t *volinfo = NULL; + gf_defrag_status_t status = GF_DEFRAG_STATUS_NOT_STARTED; + char key[256] = {0,}; + char *volname = NULL; + int ret = -1; + int i = 1; + + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + gf_log (THIS->name, GF_LOG_WARNING, "Unable to get volume name"); + goto out; + } + + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_log (THIS->name, GF_LOG_WARNING, FMTSTR_CHECK_VOL_EXISTS, + volname); + goto out; + } + + if (volinfo->rebal.defrag_cmd != GF_DEFRAG_CMD_START_LAYOUT_FIX) { + /* Fix layout was not issued; we don't need to reassign + the status */ + ret = 0; + goto out; + } + + do { + memset (key, 0, 256); + snprintf (key, 256, "status-%d", i); + ret = dict_get_int32 (dict, key, (int32_t *)&status); + if (ret) { + gf_log (THIS->name, GF_LOG_WARNING, + "failed to get defrag %s", key); + goto out; + } + ret = reassign_defrag_status (dict, key, &status); + if (ret) + goto out; + i++; + } while (i <= count); + + ret = 0; +out: + return ret; + +} + /* This function is used to modify the op_ctx dict before sending it back * to cli. This is useful in situations like changing the peer uuids to * hostnames etc. */ void -glusterd_op_modify_op_ctx (glusterd_op_t op) +glusterd_op_modify_op_ctx (glusterd_op_t op, void *ctx) { int ret = -1; dict_t *op_ctx = NULL; @@ -2162,10 +3517,18 @@ glusterd_op_modify_op_ctx (glusterd_op_t op) int other_count = 0; int count = 0; uint32_t cmd = GF_CLI_STATUS_NONE; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + + if (ctx) + op_ctx = ctx; + else + op_ctx = glusterd_op_get_ctx(); - op_ctx = glusterd_op_get_ctx(); if (!op_ctx) { - gf_log (THIS->name, GF_LOG_CRITICAL, + gf_log (this->name, GF_LOG_CRITICAL, "Operation context is not present."); goto out; } @@ -2174,13 +3537,13 @@ glusterd_op_modify_op_ctx (glusterd_op_t op) case GD_OP_STATUS_VOLUME: ret = dict_get_uint32 (op_ctx, "cmd", &cmd); if (ret) { - gf_log (THIS->name, GF_LOG_DEBUG, + gf_log (this->name, GF_LOG_DEBUG, "Failed to get status cmd"); goto out; } if (!(cmd & GF_CLI_STATUS_NFS || cmd & GF_CLI_STATUS_SHD || (cmd & GF_CLI_STATUS_MASK) == GF_CLI_STATUS_NONE)) { - gf_log (THIS->name, GF_LOG_INFO, + gf_log (this->name, GF_LOG_DEBUG, "op_ctx modification not required for status " "operation being performed"); goto out; @@ -2189,14 +3552,14 @@ glusterd_op_modify_op_ctx (glusterd_op_t op) ret = dict_get_int32 (op_ctx, "brick-index-max", &brick_index_max); if (ret) { - gf_log (THIS->name, GF_LOG_DEBUG, + gf_log (this->name, GF_LOG_DEBUG, "Failed to get brick-index-max"); goto out; } ret = dict_get_int32 (op_ctx, "other-count", &other_count); if (ret) { - gf_log (THIS->name, GF_LOG_DEBUG, + gf_log (this->name, GF_LOG_DEBUG, "Failed to get other-count"); goto out; } @@ -2207,7 +3570,7 @@ glusterd_op_modify_op_ctx (glusterd_op_t op) "brick%d.path", 0, count); if (ret) - gf_log (THIS->name, GF_LOG_WARNING, + gf_log (this->name, GF_LOG_WARNING, "Failed uuid to hostname conversion"); break; @@ -2219,7 +3582,7 @@ glusterd_op_modify_op_ctx (glusterd_op_t op) ret = dict_get_int32 (op_ctx, "count", &count); if (ret) { - gf_log (THIS->name, GF_LOG_DEBUG, + gf_log (this->name, GF_LOG_DEBUG, "Failed to get brick count"); goto out; } @@ -2228,7 +3591,7 @@ glusterd_op_modify_op_ctx (glusterd_op_t op) "%d-brick", 1, (count + 1)); if (ret) - gf_log (THIS->name, GF_LOG_WARNING, + gf_log (this->name, GF_LOG_WARNING, "Failed uuid to hostname conversion"); break; @@ -2239,22 +3602,48 @@ glusterd_op_modify_op_ctx (glusterd_op_t op) case GD_OP_DEFRAG_BRICK_VOLUME: ret = dict_get_int32 (op_ctx, "count", &count); if (ret) { - gf_log (THIS->name, GF_LOG_DEBUG, + gf_log (this->name, GF_LOG_DEBUG, "Failed to get count"); goto out; } + /* add 'node-name-%d' into op_ctx with value uuid_str. + this will be used to convert to hostname later */ + { + char key[1024]; + char *uuid_str = NULL; + int i; + + for (i = 1; i <= count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "node-uuid-%d", i); + ret = dict_get_str (op_ctx, key, &uuid_str); + if (!ret) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), + "node-name-%d", i); + ret = dict_set_str (op_ctx, key, + uuid_str); + } + } + } + ret = glusterd_op_volume_dict_uuid_to_hostname (op_ctx, - "node-uuid-%d", + "node-name-%d", 1, (count + 1)); if (ret) - gf_log (THIS->name, GF_LOG_WARNING, + gf_log (this->name, GF_LOG_WARNING, "Failed uuid to hostname conversion"); + + ret = glusterd_op_check_peer_defrag_status (op_ctx, count); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Failed to reset defrag status for fix-layout"); break; default: ret = 0; - gf_log (THIS->name, GF_LOG_INFO, + gf_log (this->name, GF_LOG_DEBUG, "op_ctx modification not required"); break; @@ -2262,25 +3651,36 @@ glusterd_op_modify_op_ctx (glusterd_op_t op) out: if (ret) - gf_log (THIS->name, GF_LOG_WARNING, + gf_log (this->name, GF_LOG_WARNING, "op_ctx modification failed"); return; } static int -glusterd_op_commit_hook (glusterd_op_t op, dict_t *op_ctx, glusterd_commit_hook_type_t type) +glusterd_op_commit_hook (glusterd_op_t op, dict_t *op_ctx, + glusterd_commit_hook_type_t type) { glusterd_conf_t *priv = NULL; char hookdir[PATH_MAX] = {0, }; char scriptdir[PATH_MAX] = {0, }; char type_subdir[256] = {0, }; char *cmd_subdir = NULL; + int ret = -1; priv = THIS->private; - if (type == GD_COMMIT_HOOK_PRE) - strcpy (type_subdir, "pre"); - else if (type == GD_COMMIT_HOOK_POST) - strcpy (type_subdir, "post"); + switch (type) { + case GD_COMMIT_HOOK_NONE: + case GD_COMMIT_HOOK_MAX: + /*Won't be called*/ + break; + + case GD_COMMIT_HOOK_PRE: + strcpy (type_subdir, "pre"); + break; + case GD_COMMIT_HOOK_POST: + strcpy (type_subdir, "post"); + break; + } cmd_subdir = glusterd_hooks_get_hooks_cmd_subdir (op); if (strlen (cmd_subdir) == 0) @@ -2290,7 +3690,23 @@ glusterd_op_commit_hook (glusterd_op_t op, dict_t *op_ctx, glusterd_commit_hook snprintf (scriptdir, sizeof (scriptdir), "%s/%s/%s", hookdir, cmd_subdir, type_subdir); - return glusterd_hooks_run_hooks (scriptdir, op_ctx); + switch (type) { + case GD_COMMIT_HOOK_NONE: + case GD_COMMIT_HOOK_MAX: + /*Won't be called*/ + break; + + case GD_COMMIT_HOOK_PRE: + ret = glusterd_hooks_run_hooks (scriptdir, op, op_ctx, + type); + break; + case GD_COMMIT_HOOK_POST: + ret = glusterd_hooks_post_stub_enqueue (scriptdir, op, + op_ctx); + break; + } + + return ret; } static int @@ -2315,22 +3731,28 @@ glusterd_op_ac_send_commit_op (glusterd_op_sm_event_t *event, void *ctx) op = glusterd_op_get_op (); op_dict = glusterd_op_get_ctx (); - ret = glusterd_op_build_payload (&dict, &op_errstr); + ret = glusterd_op_build_payload (&dict, &op_errstr, NULL); if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, "Building payload failed"); + gf_log (this->name, GF_LOG_ERROR, LOGSTR_BUILD_PAYLOAD, + gd_op_list[op]); + if (op_errstr == NULL) + gf_asprintf (&op_errstr, OPERRSTR_BUILD_PAYLOAD); opinfo.op_errstr = op_errstr; goto out; } - glusterd_op_commit_hook (op, op_dict, GD_COMMIT_HOOK_PRE); ret = glusterd_op_commit_perform (op, dict, &op_errstr, NULL); //rsp_dict invalid for source if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, "Commit failed"); + gf_log (this->name, GF_LOG_ERROR, LOGSTR_COMMIT_FAIL, + gd_op_list[op], "localhost", (op_errstr) ? ":" : " ", + (op_errstr) ? op_errstr : " "); + if (op_errstr == NULL) + gf_asprintf (&op_errstr, OPERRSTR_COMMIT_FAIL, + "localhost"); opinfo.op_errstr = op_errstr; goto out; } - glusterd_op_commit_hook (op, op_dict, GD_COMMIT_HOOK_POST); list_for_each_entry (peerinfo, &priv->peers, uuid_list) { GF_ASSERT (peerinfo); @@ -2346,41 +3768,48 @@ glusterd_op_ac_send_commit_op (glusterd_op_sm_event_t *event, void *ctx) if (proc->fn) { ret = dict_set_static_ptr (dict, "peerinfo", peerinfo); if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, + gf_log (this->name, GF_LOG_ERROR, "failed to set peerinfo"); goto out; } ret = proc->fn (NULL, this, dict); - if (ret) + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Failed to " + "send commit request for operation " + "'Volume %s' to peer %s", + gd_op_list[op], peerinfo->hostname); continue; + } pending_count++; } } opinfo.pending_count = pending_count; - gf_log (THIS->name, GF_LOG_INFO, "Sent op req to %d peers", - opinfo.pending_count); + gf_log (this->name, GF_LOG_DEBUG, "Sent commit op req for 'Volume %s' " + "to %d peers", gd_op_list[op], opinfo.pending_count); out: if (dict) dict_unref (dict); if (ret) { - glusterd_op_sm_inject_event (GD_OP_EVENT_RCVD_RJT, NULL); + glusterd_op_sm_inject_event (GD_OP_EVENT_RCVD_RJT, + &event->txn_id, NULL); opinfo.op_ret = ret; } if (!opinfo.pending_count) { if (op == GD_OP_REPLACE_BRICK) { - ret = glusterd_op_start_rb_timer (op_dict); + ret = glusterd_op_start_rb_timer (op_dict, + &event->txn_id); } else { - glusterd_op_modify_op_ctx (op); - ret = glusterd_op_sm_inject_all_acc (); + glusterd_op_modify_op_ctx (op, NULL); + ret = glusterd_op_sm_inject_all_acc (&event->txn_id); } goto err; } err: - gf_log (THIS->name, GF_LOG_DEBUG, "Returning with %d", ret); + gf_log (this->name, GF_LOG_DEBUG, "Returning with %d", ret); return ret; @@ -2399,10 +3828,11 @@ glusterd_op_ac_rcvd_stage_op_acc (glusterd_op_sm_event_t *event, void *ctx) if (opinfo.pending_count > 0) goto out; - ret = glusterd_op_sm_inject_event (GD_OP_EVENT_STAGE_ACC, NULL); + ret = glusterd_op_sm_inject_event (GD_OP_EVENT_STAGE_ACC, + &event->txn_id, NULL); out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } @@ -2420,10 +3850,11 @@ glusterd_op_ac_stage_op_failed (glusterd_op_sm_event_t *event, void *ctx) if (opinfo.pending_count > 0) goto out; - ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACK, NULL); + ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACK, + &event->txn_id, NULL); out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } @@ -2441,10 +3872,11 @@ glusterd_op_ac_commit_op_failed (glusterd_op_sm_event_t *event, void *ctx) if (opinfo.pending_count > 0) goto out; - ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACK, NULL); + ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACK, + &event->txn_id, NULL); out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } @@ -2455,6 +3887,10 @@ glusterd_op_ac_brick_op_failed (glusterd_op_sm_event_t *event, void *ctx) int ret = 0; glusterd_op_brick_rsp_ctx_t *ev_ctx = NULL; gf_boolean_t free_errstr = _gf_false; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); GF_ASSERT (event); GF_ASSERT (ctx); @@ -2462,7 +3898,7 @@ glusterd_op_ac_brick_op_failed (glusterd_op_sm_event_t *event, void *ctx) ret = glusterd_remove_pending_entry (&opinfo.pending_bricks, ev_ctx->pending_node->node); if (ret) { - gf_log ("glusterd", GF_LOG_ERROR, "unknown response received "); + gf_log (this->name, GF_LOG_ERROR, "unknown response received "); ret = -1; free_errstr = _gf_true; goto out; @@ -2480,7 +3916,8 @@ glusterd_op_ac_brick_op_failed (glusterd_op_sm_event_t *event, void *ctx) if (opinfo.brick_pending_count > 0) goto out; - ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACK, ev_ctx->commit_ctx); + ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACK, + &event->txn_id, ev_ctx->commit_ctx); out: if (ev_ctx->rsp_dict) @@ -2488,7 +3925,7 @@ out: if (free_errstr && ev_ctx->op_errstr) GF_FREE (ev_ctx->op_errstr); GF_FREE (ctx); - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } @@ -2500,7 +3937,10 @@ glusterd_op_ac_rcvd_commit_op_acc (glusterd_op_sm_event_t *event, void *ctx) int ret = 0; gf_boolean_t commit_ack_inject = _gf_true; glusterd_op_t op = GD_OP_NONE; + xlator_t *this = NULL; + this = THIS; + GF_ASSERT (this); op = glusterd_op_get_op (); GF_ASSERT (event); @@ -2513,15 +3953,15 @@ glusterd_op_ac_rcvd_commit_op_acc (glusterd_op_sm_event_t *event, void *ctx) if (op == GD_OP_REPLACE_BRICK) { op_ctx = glusterd_op_get_ctx (); if (!op_ctx) { - gf_log (THIS->name, GF_LOG_CRITICAL, "Operation " + gf_log (this->name, GF_LOG_CRITICAL, "Operation " "context is not present."); ret = -1; goto out; } - ret = glusterd_op_start_rb_timer (op_ctx); + ret = glusterd_op_start_rb_timer (op_ctx, &event->txn_id); if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, "Couldn't start " + gf_log (this->name, GF_LOG_ERROR, "Couldn't start " "replace-brick operation."); goto out; } @@ -2534,10 +3974,12 @@ glusterd_op_ac_rcvd_commit_op_acc (glusterd_op_sm_event_t *event, void *ctx) out: if (commit_ack_inject) { if (ret) - ret = glusterd_op_sm_inject_event (GD_OP_EVENT_RCVD_RJT, NULL); + ret = glusterd_op_sm_inject_event (GD_OP_EVENT_RCVD_RJT, + &event->txn_id, NULL); else if (!opinfo.pending_count) { - glusterd_op_modify_op_ctx (op); - ret = glusterd_op_sm_inject_event (GD_OP_EVENT_COMMIT_ACC, NULL); + glusterd_op_modify_op_ctx (op, NULL); + ret = glusterd_op_sm_inject_event (GD_OP_EVENT_COMMIT_ACC, + &event->txn_id, NULL); } /*else do nothing*/ } @@ -2558,9 +4000,10 @@ glusterd_op_ac_rcvd_unlock_acc (glusterd_op_sm_event_t *event, void *ctx) if (opinfo.pending_count > 0) goto out; - ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACC, NULL); + ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACC, + &event->txn_id, NULL); - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret); out: return ret; @@ -2592,7 +4035,7 @@ glusterd_op_reset_ctx () } int32_t -glusterd_op_txn_complete () +glusterd_op_txn_complete (uuid_t *txn_id) { int32_t ret = -1; glusterd_conf_t *priv = NULL; @@ -2602,9 +4045,13 @@ glusterd_op_txn_complete () rpcsvc_request_t *req = NULL; void *ctx = NULL; char *op_errstr = NULL; + char *volname = NULL; + xlator_t *this = NULL; + this = THIS; + GF_ASSERT (this); - priv = THIS->private; + priv = this->private; GF_ASSERT (priv); op = glusterd_op_get_op (); @@ -2621,32 +4068,55 @@ glusterd_op_txn_complete () glusterd_op_reset_ctx (); glusterd_op_clear_errstr (); - ret = glusterd_unlock (priv->uuid); - - /* unlock cant/shouldnt fail here!! */ - if (ret) { - gf_log ("glusterd", GF_LOG_CRITICAL, - "Unable to clear local lock, ret: %d", ret); + /* Based on the op-version, we release the cluster or mgmt_v3 lock */ + if (priv->op_version < 3) { + ret = glusterd_unlock (MY_UUID); + /* unlock cant/shouldnt fail here!! */ + if (ret) + gf_log (this->name, GF_LOG_CRITICAL, + "Unable to clear local lock, ret: %d", ret); + else + gf_log (this->name, GF_LOG_DEBUG, "Cleared local lock"); } else { - gf_log ("glusterd", GF_LOG_INFO, "Cleared local lock"); + ret = dict_get_str (ctx, "volname", &volname); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Unable to acquire volname"); + + if (volname) { + ret = glusterd_mgmt_v3_unlock (volname, MY_UUID, + "vol"); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Unable to release lock for %s", + volname); + } } ret = glusterd_op_send_cli_response (op, op_ret, op_errno, req, ctx, op_errstr); if (ret) { - gf_log ("", GF_LOG_ERROR, "Responding to cli failed, ret: %d", - ret); + gf_log (this->name, GF_LOG_ERROR, "Responding to cli failed, " + "ret: %d", ret); //Ignore this error, else state machine blocks ret = 0; } - glusterd_op_free_ctx (op, ctx); if (op_errstr && (strcmp (op_errstr, ""))) GF_FREE (op_errstr); - gf_log ("glusterd", GF_LOG_DEBUG, "Returning %d", ret); + if (priv->pending_quorum_action) + glusterd_do_quorum_action (); + + /* Clearing the transaction opinfo */ + ret = glusterd_clear_txn_opinfo (txn_id); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Unable to clear transaction's opinfo"); + + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } @@ -2657,9 +4127,9 @@ glusterd_op_ac_unlocked_all (glusterd_op_sm_event_t *event, void *ctx) GF_ASSERT (event); - ret = glusterd_op_txn_complete (); + ret = glusterd_op_txn_complete (&event->txn_id); - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } @@ -2673,7 +4143,11 @@ glusterd_op_ac_stage_op (glusterd_op_sm_event_t *event, void *ctx) dict_t *rsp_dict = NULL; char *op_errstr = NULL; dict_t *dict = NULL; + xlator_t *this = NULL; + uuid_t *txn_id = NULL; + this = THIS; + GF_ASSERT (this); GF_ASSERT (ctx); req_ctx = ctx; @@ -2682,8 +4156,8 @@ glusterd_op_ac_stage_op (glusterd_op_sm_event_t *event, void *ctx) rsp_dict = dict_new (); if (!rsp_dict) { - gf_log ("", GF_LOG_DEBUG, - "Out of memory"); + gf_log (this->name, GF_LOG_ERROR, + "Failed to get new dictionary"); return -1; } @@ -2691,16 +4165,31 @@ glusterd_op_ac_stage_op (glusterd_op_sm_event_t *event, void *ctx) rsp_dict); if (status) { - gf_log ("", GF_LOG_ERROR, "Validate failed: %d", status); + gf_log (this->name, GF_LOG_ERROR, "Stage failed on operation" + " 'Volume %s', Status : %d", gd_op_list[req_ctx->op], + status); } + txn_id = GF_CALLOC (1, sizeof(uuid_t), gf_common_mt_uuid_t); + + if (txn_id) + uuid_copy (*txn_id, event->txn_id); + else + gf_log (this->name, GF_LOG_ERROR, "Out of Memory"); + + ret = dict_set_bin (rsp_dict, "transaction_id", + txn_id, sizeof(*txn_id)); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Failed to set transaction id."); + ret = glusterd_op_stage_send_resp (req_ctx->req, req_ctx->op, status, op_errstr, rsp_dict); if (op_errstr && (strcmp (op_errstr, ""))) GF_FREE (op_errstr); - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + gf_log (this->name, GF_LOG_DEBUG, "Returning with %d", ret); if (rsp_dict) dict_unref (rsp_dict); @@ -2729,7 +4218,7 @@ glusterd_need_brick_op (glusterd_op_t op) return ret; } -static dict_t* +dict_t* glusterd_op_init_commit_rsp_dict (glusterd_op_t op) { dict_t *rsp_dict = NULL; @@ -2757,7 +4246,11 @@ glusterd_op_ac_commit_op (glusterd_op_sm_event_t *event, void *ctx) char *op_errstr = NULL; dict_t *dict = NULL; dict_t *rsp_dict = NULL; + xlator_t *this = NULL; + uuid_t *txn_id = NULL; + this = THIS; + GF_ASSERT (this); GF_ASSERT (ctx); req_ctx = ctx; @@ -2768,7 +4261,6 @@ glusterd_op_ac_commit_op (glusterd_op_sm_event_t *event, void *ctx) if (NULL == rsp_dict) return -1; - glusterd_op_commit_hook (req_ctx->op, dict, GD_COMMIT_HOOK_PRE); if (GD_OP_CLEARLOCKS_VOLUME == req_ctx->op) { /*clear locks should be run only on @@ -2780,25 +4272,34 @@ glusterd_op_ac_commit_op (glusterd_op_sm_event_t *event, void *ctx) &op_errstr, rsp_dict); } - if (status) { - gf_log (THIS->name, GF_LOG_ERROR, "Commit failed: %d", status); - } else { - /* On successful commit */ - glusterd_op_commit_hook (req_ctx->op, dict, - GD_COMMIT_HOOK_POST); - } + if (status) + gf_log (this->name, GF_LOG_ERROR, "Commit of operation " + "'Volume %s' failed: %d", gd_op_list[req_ctx->op], + status); + + txn_id = GF_CALLOC (1, sizeof(uuid_t), gf_common_mt_uuid_t); + + if (txn_id) + uuid_copy (*txn_id, event->txn_id); + else + gf_log (this->name, GF_LOG_ERROR, "Out of Memory"); + + ret = dict_set_bin (rsp_dict, "transaction_id", + txn_id, sizeof(*txn_id)); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Failed to set transaction id."); ret = glusterd_op_commit_send_resp (req_ctx->req, req_ctx->op, status, op_errstr, rsp_dict); - glusterd_op_fini_ctx (); if (op_errstr && (strcmp (op_errstr, ""))) GF_FREE (op_errstr); if (rsp_dict) dict_unref (rsp_dict); - gf_log (THIS->name, GF_LOG_DEBUG, "Returning with %d", ret); + gf_log (this->name, GF_LOG_DEBUG, "Returning with %d", ret); return ret; } @@ -2820,13 +4321,12 @@ glusterd_op_ac_send_commit_failed (glusterd_op_sm_event_t *event, void *ctx) opinfo.op_ret, opinfo.op_errstr, op_ctx); - glusterd_op_fini_ctx (); if (opinfo.op_errstr && (strcmp (opinfo.op_errstr, ""))) { GF_FREE (opinfo.op_errstr); opinfo.op_errstr = NULL; } - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + gf_log (THIS->name, GF_LOG_DEBUG, "Returning with %d", ret); return ret; } @@ -2857,6 +4357,7 @@ glusterd_op_stage_validate (glusterd_op_t op, dict_t *dict, char **op_errstr, dict_t *rsp_dict) { int ret = -1; + xlator_t *this = THIS; switch (op) { case GD_OP_CREATE_VOLUME: @@ -2904,6 +4405,10 @@ glusterd_op_stage_validate (glusterd_op_t op, dict_t *dict, char **op_errstr, ret = glusterd_op_stage_sync_volume (dict, op_errstr); break; + case GD_OP_GSYNC_CREATE: + ret = glusterd_op_stage_gsync_create (dict, op_errstr); + break; + case GD_OP_GSYNC_SET: ret = glusterd_op_stage_gsync_set (dict, op_errstr); break; @@ -2938,13 +4443,20 @@ glusterd_op_stage_validate (glusterd_op_t op, dict_t *dict, char **op_errstr, op_errstr); break; + case GD_OP_COPY_FILE: + ret = glusterd_op_stage_copy_file (dict, op_errstr); + break; + + case GD_OP_SYS_EXEC: + ret = glusterd_op_stage_sys_exec (dict, op_errstr); + break; + default: - gf_log ("", GF_LOG_ERROR, "Unknown op %d", - op); + gf_log (this->name, GF_LOG_ERROR, "Unknown op %s", + gd_op_list[op]); } - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - + gf_log (this->name, GF_LOG_DEBUG, "OP = %d. Returning %d", op, ret); return ret; } @@ -2954,7 +4466,9 @@ glusterd_op_commit_perform (glusterd_op_t op, dict_t *dict, char **op_errstr, dict_t *rsp_dict) { int ret = -1; + xlator_t *this = THIS; + glusterd_op_commit_hook (op, dict, GD_COMMIT_HOOK_PRE); switch (op) { case GD_OP_CREATE_VOLUME: ret = glusterd_op_create_volume (dict, op_errstr); @@ -2985,7 +4499,7 @@ glusterd_op_commit_perform (glusterd_op_t op, dict_t *dict, char **op_errstr, break; case GD_OP_RESET_VOLUME: - ret = glusterd_op_reset_volume (dict); + ret = glusterd_op_reset_volume (dict, op_errstr); break; case GD_OP_REMOVE_BRICK: @@ -3000,6 +4514,11 @@ glusterd_op_commit_perform (glusterd_op_t op, dict_t *dict, char **op_errstr, ret = glusterd_op_sync_volume (dict, op_errstr, rsp_dict); break; + case GD_OP_GSYNC_CREATE: + ret = glusterd_op_gsync_create (dict, op_errstr, + rsp_dict); + break; + case GD_OP_GSYNC_SET: ret = glusterd_op_gsync_set (dict, op_errstr, rsp_dict); break; @@ -3010,7 +4529,7 @@ glusterd_op_commit_perform (glusterd_op_t op, dict_t *dict, char **op_errstr, break; case GD_OP_QUOTA: - ret = glusterd_op_quota (dict, op_errstr); + ret = glusterd_op_quota (dict, op_errstr, rsp_dict); break; case GD_OP_STATUS_VOLUME: @@ -3031,403 +4550,35 @@ glusterd_op_commit_perform (glusterd_op_t op, dict_t *dict, char **op_errstr, break; case GD_OP_CLEARLOCKS_VOLUME: - ret = glusterd_op_clearlocks_volume (dict, op_errstr); + ret = glusterd_op_clearlocks_volume (dict, op_errstr, + rsp_dict); break; - default: - gf_log ("", GF_LOG_ERROR, "Unknown op %d", - op); + case GD_OP_COPY_FILE: + ret = glusterd_op_copy_file (dict, op_errstr); break; - } - - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -void -_profile_volume_add_brick_rsp (dict_t *this, char *key, data_t *value, - void *data) -{ - char new_key[256] = {0}; - glusterd_pr_brick_rsp_conv_t *rsp_ctx = NULL; - data_t *new_value = NULL; - - rsp_ctx = data; - new_value = data_copy (value); - GF_ASSERT (new_value); - snprintf (new_key, sizeof (new_key), "%d-%s", rsp_ctx->count, key); - dict_set (rsp_ctx->dict, new_key, new_value); -} - -int -glusterd_profile_volume_brick_rsp (void *pending_entry, - dict_t *rsp_dict, dict_t *op_ctx, - char **op_errstr, gd_node_type type) -{ - int ret = 0; - glusterd_pr_brick_rsp_conv_t rsp_ctx = {0}; - int32_t count = 0; - char brick[PATH_MAX+1024] = {0}; - char key[256] = {0}; - char *full_brick = NULL; - glusterd_brickinfo_t *brickinfo = NULL; - xlator_t *this = NULL; - glusterd_conf_t *priv = NULL; - - GF_ASSERT (rsp_dict); - GF_ASSERT (op_ctx); - GF_ASSERT (op_errstr); - GF_ASSERT (pending_entry); - - this = THIS; - GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); - ret = dict_get_int32 (op_ctx, "count", &count); - if (ret) { - count = 1; - } else { - count++; - } - snprintf (key, sizeof (key), "%d-brick", count); - if (type == GD_NODE_BRICK) { - brickinfo = pending_entry; - snprintf (brick, sizeof (brick), "%s:%s", brickinfo->hostname, - brickinfo->path); - } else if (type == GD_NODE_NFS) { - snprintf (brick, sizeof (brick), "%s", uuid_utoa (priv->uuid)); - } - full_brick = gf_strdup (brick); - GF_ASSERT (full_brick); - ret = dict_set_dynstr (op_ctx, key, full_brick); - - rsp_ctx.count = count; - rsp_ctx.dict = op_ctx; - dict_foreach (rsp_dict, _profile_volume_add_brick_rsp, &rsp_ctx); - dict_del (op_ctx, "count"); - ret = dict_set_int32 (op_ctx, "count", count); - return ret; -} - -//input-key: <replica-id>:<child-id>-* -//output-key: <brick-id>-* -void -_heal_volume_add_shd_rsp (dict_t *this, char *key, data_t *value, void *data) -{ - char new_key[256] = {0,}; - char int_str[16] = {0}; - data_t *new_value = NULL; - char *rxl_end = NULL; - char *rxl_child_end = NULL; - glusterd_volinfo_t *volinfo = NULL; - int rxl_id = 0; - int rxl_child_id = 0; - int brick_id = 0; - int int_len = 0; - int ret = 0; - glusterd_heal_rsp_conv_t *rsp_ctx = NULL; - glusterd_brickinfo_t *brickinfo = NULL; - - rsp_ctx = data; - rxl_end = strchr (key, '-'); - if (!rxl_end) - goto out; - - int_len = strlen (key) - strlen (rxl_end); - strncpy (int_str, key, int_len); - int_str[int_len] = '\0'; - ret = gf_string2int (int_str, &rxl_id); - if (ret) - goto out; - - rxl_child_end = strchr (rxl_end + 1, '-'); - if (!rxl_child_end) - goto out; - - int_len = strlen (rxl_end) - strlen (rxl_child_end) - 1; - strncpy (int_str, rxl_end + 1, int_len); - int_str[int_len] = '\0'; - ret = gf_string2int (int_str, &rxl_child_id); - if (ret) - goto out; - - volinfo = rsp_ctx->volinfo; - brick_id = rxl_id * volinfo->replica_count + rxl_child_id; - - if (!strcmp (rxl_child_end, "-status")) { - brickinfo = glusterd_get_brickinfo_by_position (volinfo, - brick_id); - if (!brickinfo) - goto out; - if (!glusterd_is_local_brick (rsp_ctx->this, volinfo, - brickinfo)) - goto out; - } - new_value = data_copy (value); - snprintf (new_key, sizeof (new_key), "%d%s", brick_id, rxl_child_end); - dict_set (rsp_ctx->dict, new_key, new_value); - -out: - return; -} - -int -glusterd_heal_volume_brick_rsp (dict_t *req_dict, dict_t *rsp_dict, - dict_t *op_ctx, char **op_errstr) -{ - int ret = 0; - glusterd_heal_rsp_conv_t rsp_ctx = {0}; - char *volname = NULL; - glusterd_volinfo_t *volinfo = NULL; - - GF_ASSERT (rsp_dict); - GF_ASSERT (op_ctx); - GF_ASSERT (op_errstr); - - ret = dict_get_str (req_dict, "volname", &volname); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); - goto out; - } - - ret = glusterd_volinfo_find (volname, &volinfo); - - if (ret) - goto out; - - rsp_ctx.dict = op_ctx; - rsp_ctx.volinfo = volinfo; - rsp_ctx.this = THIS; - dict_foreach (rsp_dict, _heal_volume_add_shd_rsp, &rsp_ctx); - -out: - return ret; -} - -void -_status_volume_add_brick_rsp (dict_t *this, char *key, data_t *value, - void *data) -{ - char new_key[256] = {0,}; - data_t *new_value = 0; - glusterd_pr_brick_rsp_conv_t *rsp_ctx = NULL; - - rsp_ctx = data; - new_value = data_copy (value); - snprintf (new_key, sizeof (new_key), "brick%d.%s", rsp_ctx->count, key); - dict_set (rsp_ctx->dict, new_key, new_value); - - return; -} - -int -glusterd_status_volume_brick_rsp (dict_t *rsp_dict, dict_t *op_ctx, - char **op_errstr) -{ - int ret = 0; - glusterd_pr_brick_rsp_conv_t rsp_ctx = {0}; - int32_t count = 0; - int index = 0; - - GF_ASSERT (rsp_dict); - GF_ASSERT (op_ctx); - GF_ASSERT (op_errstr); - - ret = dict_get_int32 (op_ctx, "count", &count); - if (ret) { - count = 0; - } else { - count++; - } - ret = dict_get_int32 (rsp_dict, "index", &index); - if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, "Couldn't get node index"); - goto out; - } - dict_del (rsp_dict, "index"); - - rsp_ctx.count = index; - rsp_ctx.dict = op_ctx; - dict_foreach (rsp_dict, _status_volume_add_brick_rsp, &rsp_ctx); - ret = dict_set_int32 (op_ctx, "count", count); - -out: - return ret; -} - - -int -glusterd_defrag_volume_node_rsp (dict_t *req_dict, dict_t *rsp_dict, - dict_t *op_ctx) -{ - int ret = 0; - char *volname = NULL; - glusterd_volinfo_t *volinfo = NULL; - uint64_t files = 0; - uint64_t size = 0; - uint64_t lookup = 0; - gf_defrag_status_t status = GF_DEFRAG_STATUS_NOT_STARTED; - char key[256] = {0,}; - int32_t i = 0; - char buf[1024] = {0,}; - char *node_str = NULL; - glusterd_conf_t *priv = NULL; - uint64_t failures = 0; - - priv = THIS->private; - GF_ASSERT (req_dict); - - ret = dict_get_str (req_dict, "volname", &volname); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); - goto out; - } - - ret = glusterd_volinfo_find (volname, &volinfo); - - if (ret) - goto out; - - if (!rsp_dict) - goto populate; - - ret = dict_get_uint64 (rsp_dict, "files", &files); - if (ret) - gf_log (THIS->name, GF_LOG_TRACE, - "failed to get file count"); - - ret = dict_get_uint64 (rsp_dict, "size", &size); - if (ret) - gf_log (THIS->name, GF_LOG_TRACE, - "failed to get size of xfer"); - - ret = dict_get_uint64 (rsp_dict, "lookups", &lookup); - if (ret) - gf_log (THIS->name, GF_LOG_TRACE, - "failed to get lookedup file count"); - ret = dict_get_int32 (rsp_dict, "status", (int32_t *)&status); - if (ret) - gf_log (THIS->name, GF_LOG_TRACE, - "failed to get status"); - - ret = dict_get_uint64 (rsp_dict, "failures", &failures); - if (ret) - gf_log (THIS->name, GF_LOG_TRACE, - "failed to get failure count"); - - if (files) - volinfo->rebalance_files = files; - if (size) - volinfo->rebalance_data = size; - if (lookup) - volinfo->lookedup_files = lookup; - if (failures) - volinfo->rebalance_failures = failures; + case GD_OP_SYS_EXEC: + ret = glusterd_op_sys_exec (dict, op_errstr, rsp_dict); + break; - if (!op_ctx) { - dict_copy (rsp_dict, op_ctx); - goto out; + default: + gf_log (this->name, GF_LOG_ERROR, "Unknown op %s", + gd_op_list[op]); + break; } -populate: - ret = dict_get_int32 (op_ctx, "count", &i); - i++; - - ret = dict_set_int32 (op_ctx, "count", i); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, "Failed to set count"); - - snprintf (buf, 1024, "%s", uuid_utoa (priv->uuid)); - node_str = gf_strdup (buf); - - snprintf (key, 256, "node-uuid-%d",i); - ret = dict_set_dynstr (op_ctx, key, node_str); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, - "failed to set node-uuid"); - - memset (key, 0 , 256); - snprintf (key, 256, "files-%d", i); - ret = dict_set_uint64 (op_ctx, key, volinfo->rebalance_files); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, - "failed to set file count"); + if (ret == 0) + glusterd_op_commit_hook (op, dict, GD_COMMIT_HOOK_POST); - memset (key, 0 , 256); - snprintf (key, 256, "size-%d", i); - ret = dict_set_uint64 (op_ctx, key, volinfo->rebalance_data); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, - "failed to set size of xfer"); - - memset (key, 0 , 256); - snprintf (key, 256, "lookups-%d", i); - ret = dict_set_uint64 (op_ctx, key, volinfo->lookedup_files); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, - "failed to set lookedup file count"); - if (!status) - status = volinfo->defrag_status; - - memset (key, 0 , 256); - snprintf (key, 256, "status-%d", i); - ret = dict_set_int32 (op_ctx, key, status); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, - "failed to set status"); - - memset (key, 0 , 256); - snprintf (key, 256, "failures-%d", i); - ret = dict_set_uint64 (op_ctx, key, volinfo->rebalance_failures); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, - "failed to set failure count"); - -out: + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } -int32_t -glusterd_handle_node_rsp (glusterd_req_ctx_t *req_ctx, void *pending_entry, - glusterd_op_t op, dict_t *rsp_dict, dict_t *op_ctx, - char **op_errstr, gd_node_type type) -{ - int ret = 0; - - GF_ASSERT (op_errstr); - - switch (op) { - case GD_OP_PROFILE_VOLUME: - ret = glusterd_profile_volume_brick_rsp (pending_entry, - rsp_dict, op_ctx, - op_errstr, type); - break; - case GD_OP_STATUS_VOLUME: - ret = glusterd_status_volume_brick_rsp (rsp_dict, op_ctx, - op_errstr); - break; - - case GD_OP_DEFRAG_BRICK_VOLUME: - glusterd_defrag_volume_node_rsp (req_ctx->dict, - rsp_dict, op_ctx); - break; - - case GD_OP_HEAL_VOLUME: - ret = glusterd_heal_volume_brick_rsp (req_ctx->dict, rsp_dict, - op_ctx, op_errstr); - break; - default: - break; - } - - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; -} static int -glusterd_bricks_select_stop_volume (dict_t *dict, char **op_errstr) +glusterd_bricks_select_stop_volume (dict_t *dict, char **op_errstr, + struct list_head *selected) { int ret = 0; int flags = 0; @@ -3436,15 +4587,17 @@ glusterd_bricks_select_stop_volume (dict_t *dict, char **op_errstr) glusterd_brickinfo_t *brickinfo = NULL; glusterd_pending_node_t *pending_node = NULL; - ret = glusterd_op_stop_volume_args_get (dict, &volname, &flags); if (ret) goto out; ret = glusterd_volinfo_find (volname, &volinfo); - - if (ret) + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, FMTSTR_CHECK_VOL_EXISTS, + volname); + gf_asprintf (op_errstr, FMTSTR_CHECK_VOL_EXISTS, volname); goto out; + } list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { if (glusterd_is_brick_started (brickinfo)) { @@ -3456,7 +4609,7 @@ glusterd_bricks_select_stop_volume (dict_t *dict, char **op_errstr) } else { pending_node->node = brickinfo; pending_node->type = GD_NODE_BRICK; - list_add_tail (&pending_node->list, &opinfo.pending_bricks); + list_add_tail (&pending_node->list, selected); pending_node = NULL; } } @@ -3467,7 +4620,8 @@ out: } static int -glusterd_bricks_select_remove_brick (dict_t *dict, char **op_errstr) +glusterd_bricks_select_remove_brick (dict_t *dict, char **op_errstr, + struct list_head *selected) { int ret = -1; char *volname = NULL; @@ -3480,6 +4634,8 @@ glusterd_bricks_select_remove_brick (dict_t *dict, char **op_errstr) glusterd_pending_node_t *pending_node = NULL; int32_t force = 0; + + ret = dict_get_str (dict, "volname", &volname); if (ret) { @@ -3516,8 +4672,7 @@ glusterd_bricks_select_remove_brick (dict_t *dict, char **op_errstr) } ret = glusterd_volume_brickinfo_get_by_brick (brick, volinfo, - &brickinfo, - GF_PATH_COMPLETE); + &brickinfo); if (ret) goto out; if (glusterd_is_brick_started (brickinfo)) { @@ -3529,7 +4684,7 @@ glusterd_bricks_select_remove_brick (dict_t *dict, char **op_errstr) } else { pending_node->node = brickinfo; pending_node->type = GD_NODE_BRICK; - list_add_tail (&pending_node->list, &opinfo.pending_bricks); + list_add_tail (&pending_node->list, selected); pending_node = NULL; } } @@ -3541,7 +4696,8 @@ out: } static int -glusterd_bricks_select_profile_volume (dict_t *dict, char **op_errstr) +glusterd_bricks_select_profile_volume (dict_t *dict, char **op_errstr, + struct list_head *selected) { int ret = -1; char *volname = NULL; @@ -3554,6 +4710,8 @@ glusterd_bricks_select_profile_volume (dict_t *dict, char **op_errstr) glusterd_pending_node_t *pending_node = NULL; char *brick = NULL; + + this = THIS; GF_ASSERT (this); priv = this->private; @@ -3590,7 +4748,7 @@ glusterd_bricks_select_profile_volume (dict_t *dict, char **op_errstr) case GF_CLI_STATS_INFO: ret = dict_get_str_boolean (dict, "nfs", _gf_false); if (ret) { - if (!glusterd_nodesvc_is_running ("nfs")) { + if (!glusterd_is_nodesvc_online ("nfs")) { ret = -1; gf_log (this->name, GF_LOG_ERROR, "NFS server" " is not running"); @@ -3604,8 +4762,7 @@ glusterd_bricks_select_profile_volume (dict_t *dict, char **op_errstr) } pending_node->node = priv->nfs; pending_node->type = GD_NODE_NFS; - list_add_tail (&pending_node->list, - &opinfo.pending_bricks); + list_add_tail (&pending_node->list, selected); pending_node = NULL; ret = 0; @@ -3623,7 +4780,7 @@ glusterd_bricks_select_profile_volume (dict_t *dict, char **op_errstr) pending_node->node = brickinfo; pending_node->type = GD_NODE_BRICK; list_add_tail (&pending_node->list, - &opinfo.pending_bricks); + selected); pending_node = NULL; } } @@ -3633,7 +4790,7 @@ glusterd_bricks_select_profile_volume (dict_t *dict, char **op_errstr) case GF_CLI_STATS_TOP: ret = dict_get_str_boolean (dict, "nfs", _gf_false); if (ret) { - if (!glusterd_nodesvc_is_running ("nfs")) { + if (!glusterd_is_nodesvc_online ("nfs")) { ret = -1; gf_log (this->name, GF_LOG_ERROR, "NFS server" " is not running"); @@ -3647,8 +4804,7 @@ glusterd_bricks_select_profile_volume (dict_t *dict, char **op_errstr) } pending_node->node = priv->nfs; pending_node->type = GD_NODE_NFS; - list_add_tail (&pending_node->list, - &opinfo.pending_bricks); + list_add_tail (&pending_node->list, selected); pending_node = NULL; ret = 0; @@ -3658,8 +4814,7 @@ glusterd_bricks_select_profile_volume (dict_t *dict, char **op_errstr) ret = dict_get_str (dict, "brick", &brick); if (!ret) { ret = glusterd_volume_brickinfo_get_by_brick (brick, volinfo, - &brickinfo, - GF_PATH_COMPLETE); + &brickinfo); if (ret) goto out; @@ -3675,7 +4830,7 @@ glusterd_bricks_select_profile_volume (dict_t *dict, char **op_errstr) pending_node->node = brickinfo; pending_node->type = GD_NODE_BRICK; list_add_tail (&pending_node->list, - &opinfo.pending_bricks); + selected); pending_node = NULL; goto out; } @@ -3692,7 +4847,7 @@ glusterd_bricks_select_profile_volume (dict_t *dict, char **op_errstr) pending_node->node = brickinfo; pending_node->type = GD_NODE_BRICK; list_add_tail (&pending_node->list, - &opinfo.pending_bricks); + selected); pending_node = NULL; } } @@ -3737,24 +4892,95 @@ out: } int +get_replica_index_for_per_replica_cmd (glusterd_volinfo_t *volinfo, + dict_t *dict) { + int ret = 0; + char *hostname = NULL; + char *path = NULL; + int index = 0; + glusterd_brickinfo_t *brickinfo = NULL; + int cmd_replica_index = -1; + int replica_count = -1; + + + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_get_str (dict, "per-replica-cmd-hostname", &hostname); + if (ret) + goto out; + ret = dict_get_str (dict, "per-replica-cmd-path", &path); + if (ret) + goto out; + + replica_count = volinfo->replica_count; + + list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { + if (uuid_is_null (brickinfo->uuid)) + (void)glusterd_resolve_brick (brickinfo); + if (!strcmp (brickinfo->path, path) && + !strcmp (brickinfo->hostname, hostname)) { + cmd_replica_index = index/(replica_count); + goto out; + } + index++; + } + + +out: + if (ret) + cmd_replica_index = -1; + + return cmd_replica_index; +} + +int _select_rxlators_with_local_bricks (xlator_t *this, glusterd_volinfo_t *volinfo, - dict_t *dict) + dict_t *dict, cli_cmd_type type) { glusterd_brickinfo_t *brickinfo = NULL; glusterd_conf_t *priv = NULL; - int index = 1; + int index = 0; int rxlator_count = 0; int replica_count = 0; gf_boolean_t add = _gf_false; + int ret = 0; + int cmd_replica_index = -1; priv = this->private; replica_count = volinfo->replica_count; + + if (type == PER_REPLICA) { + + cmd_replica_index = get_replica_index_for_per_replica_cmd + (volinfo, dict); + if (cmd_replica_index == -1) { + ret = -1; + goto err; + } + } + + index = 1; + list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { if (uuid_is_null (brickinfo->uuid)) (void)glusterd_resolve_brick (brickinfo); - if (!uuid_compare (priv->uuid, brickinfo->uuid)) - add = _gf_true; + switch (type) { + case ALL_REPLICA: + if (!uuid_compare (MY_UUID, brickinfo->uuid)) + add = _gf_true; + break; + case PER_REPLICA: + if (!uuid_compare (MY_UUID, brickinfo->uuid) && + ((index-1)/replica_count == cmd_replica_index)) + + add = _gf_true; + break; + } + if (index % replica_count == 0) { if (add) { _add_rxlator_to_dict (dict, volinfo->volname, @@ -3767,6 +4993,10 @@ _select_rxlators_with_local_bricks (xlator_t *this, glusterd_volinfo_t *volinfo, index++; } +err: + if (ret) + rxlator_count = -1; + return rxlator_count; } @@ -3793,7 +5023,7 @@ _select_rxlators_for_full_self_heal (xlator_t *this, uuid_copy (candidate, brickinfo->uuid); if (index % replica_count == 0) { - if (!uuid_compare (priv->uuid, candidate)) { + if (!uuid_compare (MY_UUID, candidate)) { _add_rxlator_to_dict (dict, volinfo->volname, (index-1)/replica_count, rxlator_count); @@ -3807,8 +5037,135 @@ _select_rxlators_for_full_self_heal (xlator_t *this, return rxlator_count; } + +static int +glusterd_bricks_select_snap (dict_t *dict, char **op_errstr, + struct list_head *selected) +{ + int ret = -1; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + glusterd_pending_node_t *pending_node = NULL; + glusterd_volinfo_t *volinfo = NULL; + char *volname = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + int brick_index = -1; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to get" + " volname"); + goto out; + } + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) + goto out; + + list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { + brick_index++; + if (uuid_compare (brickinfo->uuid, MY_UUID) || + !glusterd_is_brick_started (brickinfo)) { + continue; + } + pending_node = GF_CALLOC (1, sizeof (*pending_node), + gf_gld_mt_pending_node_t); + if (!pending_node) { + ret = -1; + goto out; + } + pending_node->node = brickinfo; + pending_node->type = GD_NODE_BRICK; + pending_node->index = brick_index; + list_add_tail (&pending_node->list, + selected); + pending_node = NULL; + } + + ret = 0; + +out: + gf_log (THIS->name, GF_LOG_DEBUG, "Returning ret %d", ret); + return ret; +} + static int -glusterd_bricks_select_heal_volume (dict_t *dict, char **op_errstr) +fill_shd_status_for_local_bricks (dict_t *dict, glusterd_volinfo_t *volinfo, + cli_cmd_type type, dict_t *req_dict) +{ + glusterd_brickinfo_t *brickinfo = NULL; + char msg[1024] = {0,}; + char key[1024] = {0,}; + char value[1024] = {0,}; + int index = 0; + int ret = 0; + xlator_t *this = NULL; + int cmd_replica_index = -1; + + this = THIS; + snprintf (msg, sizeof (msg), "self-heal-daemon is not running on"); + + if (type == PER_REPLICA) { + cmd_replica_index = get_replica_index_for_per_replica_cmd + (volinfo, req_dict); + if (cmd_replica_index == -1) { + gf_log (THIS->name, GF_LOG_ERROR, "Could not find the " + "replica index for per replica type command"); + ret = -1; + goto out; + } + } + + list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { + if (uuid_is_null (brickinfo->uuid)) + (void)glusterd_resolve_brick (brickinfo); + + if (uuid_compare (MY_UUID, brickinfo->uuid)) { + index++; + continue; + } + + if (type == PER_REPLICA) { + if (cmd_replica_index != (index/volinfo->replica_count)) { + index++; + continue; + } + + } + snprintf (key, sizeof (key), "%d-status",index); + snprintf (value, sizeof (value), "%s %s",msg, + uuid_utoa(MY_UUID)); + ret = dict_set_dynstr (dict, key, gf_strdup(value)); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to" + "set the dictionary for shd status msg"); + goto out; + } + snprintf (key, sizeof (key), "%d-shd-status",index); + ret = dict_set_str (dict, key, "off"); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to" + " set dictionary for shd status msg"); + goto out; + } + + index++; + } + +out: + return ret; + +} + + +static int +glusterd_bricks_select_heal_volume (dict_t *dict, char **op_errstr, + struct list_head *selected, + dict_t *rsp_dict) { int ret = -1; char *volname = NULL; @@ -3848,19 +5205,79 @@ glusterd_bricks_select_heal_volume (dict_t *dict, char **op_errstr) } switch (heal_op) { + case GF_AFR_OP_INDEX_SUMMARY: + case GF_AFR_OP_STATISTICS_HEAL_COUNT: + if (!glusterd_is_nodesvc_online ("glustershd")) { + if (!rsp_dict) { + gf_log (this->name, GF_LOG_ERROR, "Received " + "empty ctx."); + goto out; + } + + ret = fill_shd_status_for_local_bricks (rsp_dict, + volinfo, + ALL_REPLICA, + dict); + if (ret) + gf_log (this->name, GF_LOG_ERROR, "Unable to " + "fill the shd status for the local " + "bricks"); + goto out; + + } + break; + case GF_AFR_OP_STATISTICS_HEAL_COUNT_PER_REPLICA: + if (!glusterd_is_nodesvc_online ("glustershd")) { + if (!rsp_dict) { + gf_log (this->name, GF_LOG_ERROR, "Received " + "empty ctx."); + goto out; + } + ret = fill_shd_status_for_local_bricks (rsp_dict, + volinfo, + PER_REPLICA, + dict); + if (ret) + gf_log (this->name, GF_LOG_ERROR, "Unable to " + "fill the shd status for the local" + " bricks."); + goto out; + + } + break; + default: + break; + } + + + switch (heal_op) { case GF_AFR_OP_HEAL_FULL: rxlator_count = _select_rxlators_for_full_self_heal (this, volinfo, dict); break; + case GF_AFR_OP_STATISTICS_HEAL_COUNT_PER_REPLICA: + rxlator_count = _select_rxlators_with_local_bricks (this, + volinfo, + dict, + PER_REPLICA); + break; default: rxlator_count = _select_rxlators_with_local_bricks (this, volinfo, - dict); + dict, + ALL_REPLICA); break; } if (!rxlator_count) goto out; + if (rxlator_count == -1){ + gf_log (this->name, GF_LOG_ERROR, "Could not determine the" + "translator count"); + ret = -1; + goto out; + } + ret = dict_set_int32 (dict, "count", rxlator_count); if (ret) goto out; @@ -3873,8 +5290,7 @@ glusterd_bricks_select_heal_volume (dict_t *dict, char **op_errstr) } else { pending_node->node = priv->shd; pending_node->type = GD_NODE_SHD; - list_add_tail (&pending_node->list, - &opinfo.pending_bricks); + list_add_tail (&pending_node->list, selected); pending_node = NULL; } @@ -3884,9 +5300,9 @@ out: } - static int -glusterd_bricks_select_rebalance_volume (dict_t *dict, char **op_errstr) +glusterd_bricks_select_rebalance_volume (dict_t *dict, char **op_errstr, + struct list_head *selected) { int ret = -1; char *volname = NULL; @@ -3898,7 +5314,6 @@ glusterd_bricks_select_rebalance_volume (dict_t *dict, char **op_errstr) this = THIS; GF_ASSERT (this); - ret = dict_get_str (dict, "volname", &volname); if (ret) { gf_log ("glusterd", GF_LOG_ERROR, "volume name get failed"); @@ -3935,7 +5350,8 @@ out: static int -glusterd_bricks_select_status_volume (dict_t *dict, char **op_errstr) +glusterd_bricks_select_status_volume (dict_t *dict, char **op_errstr, + struct list_head *selected) { int ret = -1; int cmd = 0; @@ -3995,12 +5411,11 @@ glusterd_bricks_select_status_volume (dict_t *dict, char **op_errstr) } ret = glusterd_volume_brickinfo_get_by_brick (brickname, volinfo, - &brickinfo, - GF_PATH_COMPLETE); + &brickinfo); if (ret) goto out; - if (uuid_compare (brickinfo->uuid, priv->uuid)|| + if (uuid_compare (brickinfo->uuid, MY_UUID)|| !glusterd_is_brick_started (brickinfo)) goto out; @@ -4013,11 +5428,11 @@ glusterd_bricks_select_status_volume (dict_t *dict, char **op_errstr) pending_node->node = brickinfo; pending_node->type = GD_NODE_BRICK; pending_node->index = 0; - list_add_tail (&pending_node->list, &opinfo.pending_bricks); + list_add_tail (&pending_node->list, selected); ret = 0; } else if ((cmd & GF_CLI_STATUS_NFS) != 0) { - if (!glusterd_nodesvc_is_running ("nfs")) { + if (!glusterd_is_nodesvc_online ("nfs")) { ret = -1; gf_log (this->name, GF_LOG_ERROR, "NFS server is not running"); @@ -4032,11 +5447,11 @@ glusterd_bricks_select_status_volume (dict_t *dict, char **op_errstr) pending_node->node = priv->nfs; pending_node->type = GD_NODE_NFS; pending_node->index = 0; - list_add_tail (&pending_node->list, &opinfo.pending_bricks); + list_add_tail (&pending_node->list, selected); ret = 0; } else if ((cmd & GF_CLI_STATUS_SHD) != 0) { - if (!glusterd_nodesvc_is_running ("glustershd")) { + if (!glusterd_is_nodesvc_online ("glustershd")) { ret = -1; gf_log (this->name, GF_LOG_ERROR, "Self-heal daemon is not running"); @@ -4051,13 +5466,13 @@ glusterd_bricks_select_status_volume (dict_t *dict, char **op_errstr) pending_node->node = priv->shd; pending_node->type = GD_NODE_SHD; pending_node->index = 0; - list_add_tail (&pending_node->list, &opinfo.pending_bricks); + list_add_tail (&pending_node->list, selected); ret = 0; } else { list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { brick_index++; - if (uuid_compare (brickinfo->uuid, priv->uuid) || + if (uuid_compare (brickinfo->uuid, MY_UUID) || !glusterd_is_brick_started (brickinfo)) { continue; } @@ -4072,8 +5487,7 @@ glusterd_bricks_select_status_volume (dict_t *dict, char **op_errstr) pending_node->node = brickinfo; pending_node->type = GD_NODE_BRICK; pending_node->index = brick_index; - list_add_tail (&pending_node->list, - &opinfo.pending_bricks); + list_add_tail (&pending_node->list, selected); pending_node = NULL; } } @@ -4102,11 +5516,15 @@ glusterd_op_ac_send_brick_op (glusterd_op_sm_event_t *event, void *ctx) gf_gld_mt_op_allack_ctx_t); op = glusterd_op_get_op (); req_ctx->op = op; - uuid_copy (req_ctx->uuid, priv->uuid); - ret = glusterd_op_build_payload (&req_ctx->dict, &op_errstr); + uuid_copy (req_ctx->uuid, MY_UUID); + ret = glusterd_op_build_payload (&req_ctx->dict, &op_errstr, + NULL); if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Building payload failed"); + gf_log (this->name, GF_LOG_ERROR, LOGSTR_BUILD_PAYLOAD, + gd_op_list[op]); + if (op_errstr == NULL) + gf_asprintf (&op_errstr, + OPERRSTR_BUILD_PAYLOAD); opinfo.op_errstr = op_errstr; goto out; } @@ -4121,11 +5539,12 @@ glusterd_op_ac_send_brick_op (glusterd_op_sm_event_t *event, void *ctx) if (!opinfo.pending_count && !opinfo.brick_pending_count) { glusterd_clear_pending_nodes (&opinfo.pending_bricks); - ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACK, req_ctx); + ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACK, + &event->txn_id, req_ctx); } out: - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + gf_log (this->name, GF_LOG_DEBUG, "Returning with %d", ret); return ret; } @@ -4142,7 +5561,10 @@ glusterd_op_ac_rcvd_brick_op_acc (glusterd_op_sm_event_t *event, void *ctx) dict_t *op_ctx = NULL; glusterd_req_ctx_t *req_ctx = NULL; void *pending_entry = NULL; + xlator_t *this = NULL; + this = THIS; + GF_ASSERT (this); GF_ASSERT (event); GF_ASSERT (ctx); ev_ctx = ctx; @@ -4158,7 +5580,7 @@ glusterd_op_ac_rcvd_brick_op_acc (glusterd_op_sm_event_t *event, void *ctx) ret = glusterd_remove_pending_entry (&opinfo.pending_bricks, pending_entry); if (ret) { - gf_log ("glusterd", GF_LOG_ERROR, "unknown response received "); + gf_log (this->name, GF_LOG_ERROR, "unknown response received "); ret = -1; goto out; } @@ -4166,25 +5588,27 @@ glusterd_op_ac_rcvd_brick_op_acc (glusterd_op_sm_event_t *event, void *ctx) if (opinfo.brick_pending_count > 0) opinfo.brick_pending_count--; - glusterd_handle_node_rsp (req_ctx, pending_entry, op, ev_ctx->rsp_dict, + glusterd_handle_node_rsp (req_ctx->dict, pending_entry, op, ev_ctx->rsp_dict, op_ctx, &op_errstr, type); if (opinfo.brick_pending_count > 0) goto out; - ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACK, ev_ctx->commit_ctx); + ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACK, &event->txn_id, + ev_ctx->commit_ctx); out: if (ev_ctx->rsp_dict) dict_unref (ev_ctx->rsp_dict); GF_FREE (ev_ctx); - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } int32_t -glusterd_op_bricks_select (glusterd_op_t op, dict_t *dict, char **op_errstr) +glusterd_op_bricks_select (glusterd_op_t op, dict_t *dict, char **op_errstr, + struct list_head *selected, dict_t *rsp_dict) { int ret = 0; @@ -4195,33 +5619,42 @@ glusterd_op_bricks_select (glusterd_op_t op, dict_t *dict, char **op_errstr) switch (op) { case GD_OP_STOP_VOLUME: - ret = glusterd_bricks_select_stop_volume (dict, op_errstr); + ret = glusterd_bricks_select_stop_volume (dict, op_errstr, + selected); break; case GD_OP_REMOVE_BRICK: - ret = glusterd_bricks_select_remove_brick (dict, op_errstr); + ret = glusterd_bricks_select_remove_brick (dict, op_errstr, + selected); break; case GD_OP_PROFILE_VOLUME: - ret = glusterd_bricks_select_profile_volume (dict, op_errstr); + ret = glusterd_bricks_select_profile_volume (dict, op_errstr, + selected); break; case GD_OP_HEAL_VOLUME: - ret = glusterd_bricks_select_heal_volume (dict, op_errstr); + ret = glusterd_bricks_select_heal_volume (dict, op_errstr, + selected, rsp_dict); break; case GD_OP_STATUS_VOLUME: - ret = glusterd_bricks_select_status_volume (dict, op_errstr); + ret = glusterd_bricks_select_status_volume (dict, op_errstr, + selected); break; case GD_OP_DEFRAG_BRICK_VOLUME: - ret = glusterd_bricks_select_rebalance_volume (dict, op_errstr); + ret = glusterd_bricks_select_rebalance_volume (dict, op_errstr, + selected); + break; + case GD_OP_SNAP: + ret = glusterd_bricks_select_snap (dict, op_errstr, selected); break; default: break; } - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } @@ -4538,7 +5971,7 @@ glusterd_op_sm_new_event (glusterd_op_sm_event_type_t event_type, int glusterd_op_sm_inject_event (glusterd_op_sm_event_type_t event_type, - void *ctx) + uuid_t *txn_id, void *ctx) { int32_t ret = -1; glusterd_op_sm_event_t *event = NULL; @@ -4553,7 +5986,10 @@ glusterd_op_sm_inject_event (glusterd_op_sm_event_type_t event_type, event->ctx = ctx; - gf_log ("glusterd", GF_LOG_DEBUG, "Enqueue event: '%s'", + if (txn_id) + uuid_copy (event->txn_id, *txn_id); + + gf_log (THIS->name, GF_LOG_DEBUG, "Enqueue event: '%s'", glusterd_op_sm_event_name_get (event->event)); list_add_tail (&event->list, &gd_op_sm_queue); @@ -4612,9 +6048,14 @@ glusterd_op_sm () glusterd_op_sm_ac_fn handler = NULL; glusterd_op_sm_t *state = NULL; glusterd_op_sm_event_type_t event_type = GD_OP_EVENT_NONE; + xlator_t *this = NULL; + glusterd_op_info_t txn_op_info; + + this = THIS; + GF_ASSERT (this); if ((lock_err = pthread_mutex_trylock (&gd_op_sm_lock))) { - gf_log (THIS->name, GF_LOG_DEBUG, "lock failed due to %s", + gf_log (this->name, GF_LOG_ERROR, "lock failed due to %s", strerror (lock_err)); goto lock_failed; } @@ -4625,9 +6066,24 @@ glusterd_op_sm () list_del_init (&event->list); event_type = event->event; - gf_log ("", GF_LOG_DEBUG, "Dequeued event of type: '%s'", + gf_log (this->name, GF_LOG_DEBUG, "Dequeued event of " + "type: '%s'", glusterd_op_sm_event_name_get(event_type)); + gf_log ("", GF_LOG_DEBUG, "transaction ID = %s", + uuid_utoa (event->txn_id)); + + ret = glusterd_get_txn_opinfo (&event->txn_id, + &txn_op_info); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to get transaction's opinfo"); + glusterd_destroy_op_event_ctx (event); + GF_FREE (event); + continue; + } else + opinfo = txn_op_info; + state = glusterd_op_state_table[opinfo.state.state]; GF_ASSERT (state); @@ -4638,7 +6094,7 @@ glusterd_op_sm () ret = handler (event, event->ctx); if (ret) { - gf_log ("glusterd", GF_LOG_ERROR, + gf_log (this->name, GF_LOG_ERROR, "handler returned: %d", ret); glusterd_destroy_op_event_ctx (event); GF_FREE (event); @@ -4649,7 +6105,7 @@ glusterd_op_sm () event_type); if (ret) { - gf_log ("glusterd", GF_LOG_ERROR, + gf_log (this->name, GF_LOG_ERROR, "Unable to transition" "state from '%s' to '%s'", glusterd_op_sm_state_name_get(opinfo.state.state), @@ -4658,8 +6114,27 @@ glusterd_op_sm () return ret; } + if ((state[event_type].next_state == + GD_OP_STATE_DEFAULT) && + (event_type == GD_OP_EVENT_UNLOCK)) { + /* Clearing the transaction opinfo */ + ret = glusterd_clear_txn_opinfo(&event->txn_id); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Unable to clear " + "transaction's opinfo"); + } else { + ret = glusterd_set_txn_opinfo (&event->txn_id, + &opinfo); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Unable to set " + "transaction's opinfo"); + } + glusterd_destroy_op_event_ctx (event); GF_FREE (event); + } } @@ -4713,48 +6188,6 @@ glusterd_op_clear_op (glusterd_op_t op) } int32_t -glusterd_op_init_ctx (glusterd_op_t op) -{ - int ret = 0; - dict_t *dict = NULL; - - GF_ASSERT (GD_OP_NONE < op && op < GD_OP_MAX); - - if (_gf_false == glusterd_need_brick_op (op)) { - gf_log ("", GF_LOG_DEBUG, "Received op: %d, returning", op); - goto out; - } - dict = dict_new (); - if (dict == NULL) { - ret = -1; - goto out; - } - ret = glusterd_op_set_ctx (dict); - if (ret) - goto out; -out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; -} - - - -int32_t -glusterd_op_fini_ctx () -{ - dict_t *dict = NULL; - - dict = glusterd_op_get_ctx (); - if (dict) - dict_unref (dict); - - glusterd_op_reset_ctx (); - return 0; -} - - - -int32_t glusterd_op_free_ctx (glusterd_op_t op, void *ctx) { @@ -4808,4 +6241,3 @@ glusterd_op_sm_init () pthread_mutex_init (&gd_op_sm_lock, NULL); return 0; } - |
