summaryrefslogtreecommitdiffstats
path: root/xlators/mgmt/glusterd/src/glusterd-brick-ops.c
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/mgmt/glusterd/src/glusterd-brick-ops.c')
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-brick-ops.c920
1 files changed, 920 insertions, 0 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-brick-ops.c b/xlators/mgmt/glusterd/src/glusterd-brick-ops.c
new file mode 100644
index 00000000000..d05dd49a14a
--- /dev/null
+++ b/xlators/mgmt/glusterd/src/glusterd-brick-ops.c
@@ -0,0 +1,920 @@
+/*
+ Copyright (c) 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/>.
+*/
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+#include "common-utils.h"
+#include "cli1.h"
+#include "glusterd.h"
+#include "glusterd-op-sm.h"
+#include "glusterd-store.h"
+#include "glusterd-utils.h"
+#include "glusterd-volgen.h"
+#include "run.h"
+
+int
+glusterd_handle_add_brick (rpcsvc_request_t *req)
+{
+ int32_t ret = -1;
+ gf1_cli_add_brick_req cli_req = {0,};
+ dict_t *dict = NULL;
+ glusterd_brickinfo_t *brickinfo = NULL;
+ char *brick = NULL;
+ char *bricks = NULL;
+ char *volname = NULL;
+ int brick_count = 0;
+ char *tmpptr = NULL;
+ int i = 0;
+ char *brick_list = NULL;
+ void *cli_rsp = NULL;
+ char err_str[2048] = {0,};
+ gf1_cli_add_brick_rsp rsp = {0,};
+ glusterd_volinfo_t *volinfo = NULL;
+ glusterd_conf_t *priv = NULL;
+ xlator_t *this = NULL;
+ char *free_ptr = NULL;
+ glusterd_brickinfo_t *tmpbrkinfo = NULL;
+ glusterd_volinfo_t tmpvolinfo = {{0},};
+ int total_bricks = 0;
+
+ this = THIS;
+ GF_ASSERT(this);
+
+ priv = this->private;
+
+ GF_ASSERT (req);
+
+ INIT_LIST_HEAD (&tmpvolinfo.bricks);
+
+ if (!gf_xdr_to_cli_add_brick_req (req->msg[0], &cli_req)) {
+ //failed to decode msg;
+ req->rpc_err = GARBAGE_ARGS;
+ snprintf (err_str, sizeof (err_str), "Garbage args received");
+ goto out;
+ }
+
+ gf_cmd_log ("Volume add-brick", "on volname: %s attempted",
+ cli_req.volname);
+ gf_log ("glusterd", GF_LOG_INFO, "Received add brick req");
+
+ if (cli_req.bricks.bricks_len) {
+ /* Unserialize the dictionary */
+ dict = dict_new ();
+
+ ret = dict_unserialize (cli_req.bricks.bricks_val,
+ cli_req.bricks.bricks_len,
+ &dict);
+ if (ret < 0) {
+ gf_log ("glusterd", GF_LOG_ERROR,
+ "failed to "
+ "unserialize req-buffer to dictionary");
+ snprintf (err_str, sizeof (err_str), "Unable to decode "
+ "the buffer");
+ goto out;
+ } else {
+ dict->extra_stdfree = cli_req.bricks.bricks_val;
+ }
+ }
+
+ ret = dict_get_str (dict, "volname", &volname);
+
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to get volume name");
+ snprintf (err_str, sizeof (err_str), "Unable to get volume "
+ "name");
+ goto out;
+ }
+
+ if (!(ret = glusterd_check_volume_exists (volname))) {
+ ret = -1;
+ snprintf(err_str, 2048, "Volume %s does not exist", volname);
+ gf_log ("glusterd", GF_LOG_ERROR, "%s", err_str);
+ goto out;
+ }
+
+ ret = dict_get_int32 (dict, "count", &brick_count);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to get count");
+ snprintf (err_str, sizeof (err_str), "Unable to get volume "
+ "brick count");
+ goto out;
+ }
+
+ if (!(ret = glusterd_volinfo_find (volname, &volinfo))) {
+ if (volinfo->type == GF_CLUSTER_TYPE_NONE)
+ goto brick_val;
+ if (!brick_count || !volinfo->sub_count)
+ goto brick_val;
+
+ total_bricks = volinfo->brick_count + brick_count;
+ /* If the brick count is less than sub_count then, allow add-brick only for
+ plain replicate volume since in plain stripe brick_count becoming less than
+ the sub_count is not allowed */
+ if (volinfo->brick_count < volinfo->sub_count &&
+ (volinfo->type == GF_CLUSTER_TYPE_REPLICATE)) {
+ if (total_bricks <= volinfo->sub_count)
+ goto brick_val;
+ }
+
+ if ((brick_count % volinfo->sub_count) != 0) {
+ snprintf(err_str, 2048, "Incorrect number of bricks"
+ " supplied %d for type %s with count %d",
+ brick_count, (volinfo->type == 1)? "STRIPE":
+ "REPLICATE", volinfo->sub_count);
+ gf_log("glusterd", GF_LOG_ERROR, "%s", err_str);
+ ret = -1;
+ goto out;
+ }
+ } else {
+ snprintf (err_str, sizeof (err_str), "Unable to get volinfo "
+ "for volume name %s", volname);
+ gf_log ("glusterd", GF_LOG_ERROR, "%s", err_str);
+ goto out;
+ }
+
+brick_val:
+ ret = dict_get_str (dict, "bricks", &bricks);
+ if (ret) {
+ snprintf (err_str, sizeof (err_str), "Unable to get volume "
+ "bricks");
+ gf_log ("glusterd", GF_LOG_ERROR, "%s", err_str);
+ goto out;
+ }
+
+ if (bricks)
+ brick_list = gf_strdup (bricks);
+ if (!brick_list) {
+ ret = -1;
+ snprintf (err_str, sizeof (err_str), "Out of memory");
+ goto out;
+ } else {
+ free_ptr = brick_list;
+ }
+
+ gf_cmd_log ("Volume add-brick", "volname: %s type %s count:%d bricks:%s"
+ ,volname, ((volinfo->type == 0)? "DEFAULT" : ((volinfo->type
+ == 1)? "STRIPE": "REPLICATE")), brick_count, brick_list);
+
+
+ while ( i < brick_count) {
+ i++;
+ brick= strtok_r (brick_list, " \n", &tmpptr);
+ brick_list = tmpptr;
+ brickinfo = NULL;
+ ret = glusterd_brickinfo_from_brick (brick, &brickinfo);
+ if (ret) {
+ snprintf (err_str, sizeof (err_str), "Unable to get "
+ "brick info from brick %s", brick);
+ goto out;
+ }
+ ret = glusterd_new_brick_validate (brick, brickinfo, err_str,
+ sizeof (err_str));
+ if (ret)
+ goto out;
+ ret = glusterd_volume_brickinfo_get (brickinfo->uuid,
+ brickinfo->hostname,
+ brickinfo->path,
+ &tmpvolinfo, &tmpbrkinfo);
+ if (!ret) {
+ ret = -1;
+ snprintf (err_str, sizeof (err_str), "Brick: %s:%s, %s"
+ " one of the arguments contain the other",
+ tmpbrkinfo->hostname, tmpbrkinfo->path, brick);
+ goto out;
+ }
+ list_add_tail (&brickinfo->brick_list, &tmpvolinfo.bricks);
+ brickinfo = NULL;
+ }
+
+ ret = glusterd_op_begin (req, GD_OP_ADD_BRICK, dict);
+ gf_cmd_log ("Volume add-brick","on volname: %s %s", volname,
+ (ret != 0)? "FAILED" : "SUCCESS");
+
+out:
+ if (ret) {
+ if (dict)
+ dict_unref (dict);
+ rsp.op_ret = -1;
+ rsp.op_errno = 0;
+ rsp.volname = "";
+ if (err_str[0] == '\0')
+ snprintf (err_str, sizeof (err_str), "Operation failed");
+ rsp.op_errstr = err_str;
+ cli_rsp = &rsp;
+ glusterd_submit_reply(req, cli_rsp, NULL, 0, NULL,
+ gf_xdr_serialize_cli_add_brick_rsp,
+ (xdrproc_t)xdr_gf1_cli_add_brick_rsp);
+ ret = 0; //sent error to cli, prevent second reply
+ }
+
+ glusterd_friend_sm ();
+ glusterd_op_sm ();
+
+ if (free_ptr)
+ GF_FREE (free_ptr);
+ glusterd_volume_brickinfos_delete (&tmpvolinfo);
+ if (brickinfo)
+ glusterd_brickinfo_delete (brickinfo);
+ if (cli_req.volname)
+ free (cli_req.volname); //its malloced by xdr
+
+ return ret;
+}
+
+int
+glusterd_handle_remove_brick (rpcsvc_request_t *req)
+{
+ int32_t ret = -1;
+ gf1_cli_remove_brick_req cli_req = {0,};
+ dict_t *dict = NULL;
+ int32_t count = 0;
+ char *brick = NULL;
+ char key[256] = {0,};
+ char *brick_list = NULL;
+ int i = 1;
+ glusterd_volinfo_t *volinfo = NULL;
+ glusterd_brickinfo_t *brickinfo = NULL;
+ int32_t pos = 0;
+ int32_t sub_volume = 0;
+ int32_t sub_volume_start = 0;
+ int32_t sub_volume_end = 0;
+ glusterd_brickinfo_t *tmp = NULL;
+ char err_str[2048] = {0};
+ gf1_cli_remove_brick_rsp rsp = {0,};
+ void *cli_rsp = NULL;
+ char vol_type[256] = {0,};
+
+ GF_ASSERT (req);
+
+ if (!gf_xdr_to_cli_remove_brick_req (req->msg[0], &cli_req)) {
+ //failed to decode msg;
+ req->rpc_err = GARBAGE_ARGS;
+ goto out;
+ }
+
+ gf_cmd_log ("Volume remove-brick","on volname: %s attempted",cli_req.volname);
+ gf_log ("glusterd", GF_LOG_INFO, "Received rem brick req");
+
+ if (cli_req.bricks.bricks_len) {
+ /* Unserialize the dictionary */
+ dict = dict_new ();
+
+ ret = dict_unserialize (cli_req.bricks.bricks_val,
+ cli_req.bricks.bricks_len,
+ &dict);
+ if (ret < 0) {
+ gf_log ("glusterd", GF_LOG_ERROR,
+ "failed to "
+ "unserialize req-buffer to dictionary");
+ goto out;
+ } else {
+ dict->extra_stdfree = cli_req.bricks.bricks_val;
+ }
+ }
+
+ ret = dict_get_int32 (dict, "count", &count);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to get count");
+ goto out;
+ }
+
+ ret = glusterd_volinfo_find (cli_req.volname, &volinfo);
+ if (ret) {
+ snprintf (err_str, 2048, "Volume %s does not exist",
+ cli_req.volname);
+ gf_log ("", GF_LOG_ERROR, "%s", err_str);
+ goto out;
+ }
+
+ if (volinfo->type == GF_CLUSTER_TYPE_REPLICATE)
+ strcpy (vol_type, "replica");
+ else if (volinfo->type == GF_CLUSTER_TYPE_STRIPE)
+ strcpy (vol_type, "stripe");
+ else
+ strcpy (vol_type, "distribute");
+
+ /* Do not allow remove-brick if the volume is plain stripe */
+ if ((volinfo->type == GF_CLUSTER_TYPE_STRIPE) && (volinfo->brick_count == volinfo->sub_count)) {
+ snprintf (err_str, 2048, "Removing brick from a plain stripe is not allowed");
+ gf_log ("glusterd", GF_LOG_ERROR, "%s", err_str);
+ ret = -1;
+ goto out;
+ }
+
+ /* Do not allow remove-brick if the bricks given is less than the replica count
+ or stripe count */
+ if (((volinfo->type == GF_CLUSTER_TYPE_REPLICATE) || (volinfo->type == GF_CLUSTER_TYPE_STRIPE))
+ && !(volinfo->brick_count <= volinfo->sub_count)) {
+ if (volinfo->sub_count && (count % volinfo->sub_count != 0)) {
+ snprintf (err_str, 2048, "Remove brick incorrect"
+ " brick count of %d for %s %d",
+ count, vol_type, volinfo->sub_count);
+ gf_log ("", GF_LOG_ERROR, "%s", err_str);
+ ret = -1;
+ goto out;
+ }
+ }
+
+ brick_list = GF_MALLOC (120000 * sizeof(*brick_list),gf_common_mt_char);
+
+ if (!brick_list) {
+ ret = -1;
+ goto out;
+ }
+
+ strcpy (brick_list, " ");
+ while ( i <= count) {
+ snprintf (key, 256, "brick%d", i);
+ ret = dict_get_str (dict, key, &brick);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to get %s", key);
+ goto out;
+ }
+ gf_log ("", GF_LOG_DEBUG, "Remove brick count %d brick: %s",
+ i, brick);
+
+ ret = glusterd_volume_brickinfo_get_by_brick(brick, volinfo, &brickinfo);
+ if (ret) {
+ snprintf(err_str, 2048,"Incorrect brick %s for volume"
+ " %s", brick, cli_req.volname);
+ gf_log ("", GF_LOG_ERROR, "%s", err_str);
+ goto out;
+ }
+ strcat(brick_list, brick);
+ strcat(brick_list, " ");
+
+ i++;
+ if ((volinfo->type == GF_CLUSTER_TYPE_NONE) ||
+ (volinfo->brick_count <= volinfo->sub_count))
+ continue;
+
+ pos = 0;
+ list_for_each_entry (tmp, &volinfo->bricks, brick_list) {
+
+ if ((!strcmp (tmp->hostname,brickinfo->hostname)) &&
+ !strcmp (tmp->path, brickinfo->path)) {
+ gf_log ("", GF_LOG_INFO, "Found brick");
+ if (!sub_volume && volinfo->sub_count) {
+ sub_volume = (pos / volinfo->
+ sub_count) + 1;
+ sub_volume_start = volinfo->sub_count *
+ (sub_volume - 1);
+ sub_volume_end = (volinfo->sub_count *
+ sub_volume) -1 ;
+ } else {
+ if (pos < sub_volume_start ||
+ pos >sub_volume_end) {
+ ret = -1;
+ snprintf(err_str, 2048,"Bricks"
+ " not from same subvol"
+ " for %s", vol_type);
+ gf_log ("",GF_LOG_ERROR,
+ "%s", err_str);
+ goto out;
+ }
+ }
+ break;
+ }
+ pos++;
+ }
+ }
+ gf_cmd_log ("Volume remove-brick","volname: %s count:%d bricks:%s",
+ cli_req.volname, count, brick_list);
+
+ ret = glusterd_op_begin (req, GD_OP_REMOVE_BRICK, dict);
+ gf_cmd_log ("Volume remove-brick","on volname: %s %s",cli_req.volname,
+ (ret) ? "FAILED" : "SUCCESS");
+
+out:
+ if (ret) {
+ if (dict)
+ dict_unref (dict);
+ rsp.op_ret = -1;
+ rsp.op_errno = 0;
+ rsp.volname = "";
+ if (err_str[0] == '\0')
+ snprintf (err_str, sizeof (err_str), "Operation failed");
+ gf_log ("", GF_LOG_ERROR, "%s", err_str);
+ rsp.op_errstr = err_str;
+ cli_rsp = &rsp;
+ glusterd_submit_reply(req, cli_rsp, NULL, 0, NULL,
+ gf_xdr_serialize_cli_remove_brick_rsp,
+ (xdrproc_t)xdr_gf1_cli_remove_brick_rsp);
+
+ ret = 0; //sent error to cli, prevent second reply
+
+ }
+ if (brick_list)
+ GF_FREE (brick_list);
+ if (cli_req.volname)
+ free (cli_req.volname); //its malloced by xdr
+
+ glusterd_friend_sm ();
+ glusterd_op_sm ();
+
+ return ret;
+}
+
+
+/* op-sm */
+
+int
+glusterd_op_perform_add_bricks (glusterd_volinfo_t *volinfo, int32_t count,
+ char *bricks)
+{
+ glusterd_brickinfo_t *brickinfo = NULL;
+ char *brick = NULL;
+ int32_t i = 1;
+ char *brick_list = NULL;
+ char *free_ptr1 = NULL;
+ char *free_ptr2 = NULL;
+ char *saveptr = NULL;
+ int32_t ret = -1;
+ glusterd_conf_t *priv = NULL;
+
+ priv = THIS->private;
+
+ GF_ASSERT (volinfo);
+
+ if (bricks) {
+ brick_list = gf_strdup (bricks);
+ free_ptr1 = brick_list;
+ }
+
+ if (count)
+ brick = strtok_r (brick_list+1, " \n", &saveptr);
+
+ while ( i <= count) {
+ ret = glusterd_brickinfo_from_brick (brick, &brickinfo);
+ if (ret)
+ goto out;
+
+ ret = glusterd_resolve_brick (brickinfo);
+ if (ret)
+ goto out;
+ list_add_tail (&brickinfo->brick_list, &volinfo->bricks);
+ brick = strtok_r (NULL, " \n", &saveptr);
+ i++;
+ volinfo->brick_count++;
+
+ }
+
+ brick_list = gf_strdup (bricks);
+ free_ptr2 = brick_list;
+ i = 1;
+
+ if (count)
+ brick = strtok_r (brick_list+1, " \n", &saveptr);
+
+ ret = glusterd_create_volfiles_and_notify_services (volinfo);
+ if (ret)
+ goto out;
+
+ while (i <= count) {
+
+ ret = glusterd_volume_brickinfo_get_by_brick (brick, volinfo,
+ &brickinfo);
+ if (ret)
+ goto out;
+
+ if (GLUSTERD_STATUS_STARTED == volinfo->status) {
+ ret = glusterd_brick_start (volinfo, brickinfo);
+ if (ret)
+ goto out;
+ }
+ i++;
+ brick = strtok_r (NULL, " \n", &saveptr);
+ }
+
+out:
+ if (free_ptr1)
+ GF_FREE (free_ptr1);
+ if (free_ptr2)
+ GF_FREE (free_ptr2);
+
+ gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
+ return ret;
+}
+
+
+int
+glusterd_op_perform_remove_brick (glusterd_volinfo_t *volinfo, char *brick)
+{
+
+ glusterd_brickinfo_t *brickinfo = NULL;
+ char *dup_brick = NULL;
+ glusterd_conf_t *priv = NULL;
+ int32_t ret = -1;
+
+ GF_ASSERT (volinfo);
+ GF_ASSERT (brick);
+
+ priv = THIS->private;
+
+ dup_brick = gf_strdup (brick);
+ if (!dup_brick)
+ goto out;
+
+ ret = glusterd_volume_brickinfo_get_by_brick (dup_brick, volinfo, &brickinfo);
+ if (ret)
+ goto out;
+
+ ret = glusterd_resolve_brick (brickinfo);
+ if (ret)
+ goto out;
+
+ if (GLUSTERD_STATUS_STARTED == volinfo->status) {
+ ret = glusterd_brick_stop (volinfo, brickinfo);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to stop "
+ "glusterfs, ret: %d", ret);
+ goto out;
+ }
+ }
+ glusterd_delete_brick (volinfo, brickinfo);
+out:
+ if (dup_brick)
+ GF_FREE (dup_brick);
+
+ gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
+ return ret;
+}
+
+int
+glusterd_op_stage_add_brick (dict_t *dict, char **op_errstr)
+{
+ int ret = 0;
+ char *volname = NULL;
+ int count = 0;
+ int i = 0;
+ char *bricks = NULL;
+ char *brick_list = NULL;
+ char *saveptr = NULL;
+ char *free_ptr = NULL;
+ char *brick = NULL;
+ glusterd_brickinfo_t *brickinfo = NULL;
+ glusterd_volinfo_t *volinfo = NULL;
+ char cmd_str[1024];
+ glusterd_conf_t *priv = NULL;
+ char msg[2048] = {0,};
+ gf_boolean_t brick_alloc = _gf_false;
+ char *all_bricks = NULL;
+ char *str_ret = NULL;
+
+ priv = THIS->private;
+ if (!priv)
+ goto out;
+
+ ret = dict_get_str (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) {
+ gf_log ("", GF_LOG_ERROR, "Unable to find volume: %s", volname);
+ goto out;
+ }
+
+ if (glusterd_is_defrag_on(volinfo)) {
+ snprintf (msg, sizeof(msg), "Volume name %s rebalance is in "
+ "progress. Please retry after completion", volname);
+ gf_log ("glusterd", GF_LOG_ERROR, "%s", msg);
+ *op_errstr = gf_strdup (msg);
+ ret = -1;
+ goto out;
+ }
+ ret = dict_get_int32 (dict, "count", &count);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to get count");
+ goto out;
+ }
+
+ ret = dict_get_str (dict, "bricks", &bricks);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to get bricks");
+ goto out;
+ }
+
+ if (bricks) {
+ brick_list = gf_strdup (bricks);
+ all_bricks = gf_strdup (bricks);
+ free_ptr = brick_list;
+ }
+
+ /* Check whether any of the bricks given is the destination brick of the
+ replace brick running */
+
+ str_ret = glusterd_check_brick_rb_part (all_bricks, count, volinfo);
+ if (str_ret) {
+ gf_log ("glusterd", GF_LOG_ERROR,
+ "%s", str_ret);
+ *op_errstr = gf_strdup (str_ret);
+ ret = -1;
+ goto out;
+ }
+
+ if (count)
+ brick = strtok_r (brick_list+1, " \n", &saveptr);
+
+
+ while ( i < count) {
+ if (!glusterd_store_is_valid_brickpath (volname, brick) ||
+ !glusterd_is_valid_volfpath (volname, brick)) {
+ snprintf (msg, sizeof (msg), "brick path %s is too "
+ "long.", brick);
+ gf_log ("", GF_LOG_ERROR, "%s", msg);
+ *op_errstr = gf_strdup (msg);
+
+ ret = -1;
+ goto out;
+
+ }
+
+ ret = glusterd_volume_brickinfo_get_by_brick (brick, volinfo,
+ &brickinfo);
+ if (!ret) {
+ gf_log ("", GF_LOG_ERROR, "Adding duplicate brick: %s",
+ brick);
+ ret = -1;
+ goto out;
+ } else {
+ ret = glusterd_brickinfo_from_brick (brick, &brickinfo);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Add-brick: Unable"
+ " to get brickinfo");
+ goto out;
+ }
+ brick_alloc = _gf_true;
+ }
+
+ snprintf (cmd_str, 1024, "%s", brickinfo->path);
+ ret = glusterd_resolve_brick (brickinfo);
+ if (ret) {
+ gf_log ("glusterd", GF_LOG_ERROR,
+ "resolve brick failed");
+ goto out;
+ }
+
+ if (!uuid_compare (brickinfo->uuid, priv->uuid)) {
+ ret = glusterd_brick_create_path (brickinfo->hostname,
+ brickinfo->path,
+ volinfo->volume_id,
+ 0777, op_errstr);
+ if (ret)
+ goto out;
+ }
+
+ glusterd_brickinfo_delete (brickinfo);
+ brick_alloc = _gf_false;
+ brickinfo = NULL;
+ brick = strtok_r (NULL, " \n", &saveptr);
+ i++;
+ }
+
+out:
+ if (free_ptr)
+ GF_FREE (free_ptr);
+ if (brick_alloc && brickinfo)
+ glusterd_brickinfo_delete (brickinfo);
+ if (str_ret)
+ GF_FREE (str_ret);
+ if (all_bricks)
+ GF_FREE (all_bricks);
+
+ gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
+
+ return ret;
+}
+
+int
+glusterd_op_stage_remove_brick (dict_t *dict)
+{
+ int ret = -1;
+ char *volname = NULL;
+ glusterd_volinfo_t *volinfo = NULL;
+ dict_t *ctx = NULL;
+ char *errstr = NULL;
+ int32_t brick_count = 0;
+
+ ret = dict_get_str (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) {
+ gf_log ("", GF_LOG_ERROR, "Volume %s does not exist", volname);
+ goto out;
+ }
+
+ if (glusterd_is_defrag_on(volinfo)) {
+ ctx = glusterd_op_get_ctx ();
+ errstr = gf_strdup("Rebalance is in progress. Please retry"
+ " after completion");
+ if (!errstr) {
+ ret = -1;
+ goto out;
+ }
+ gf_log ("glusterd", GF_LOG_ERROR, "%s", errstr);
+ ret = dict_set_dynstr (ctx, "errstr", errstr);
+ if (ret) {
+ GF_FREE (errstr);
+ gf_log ("", GF_LOG_DEBUG,
+ "failed to set errstr ctx");
+ goto out;
+ }
+
+ ret = -1;
+ goto out;
+ }
+
+ ret = dict_get_int32 (dict, "count", &brick_count);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to get brick count");
+ goto out;
+ }
+
+ if (volinfo->brick_count == brick_count) {
+ ctx = glusterd_op_get_ctx ();
+ if (!ctx) {
+ gf_log ("", GF_LOG_ERROR,
+ "Operation Context is not present");
+ ret = -1;
+ goto out;
+ }
+ errstr = gf_strdup ("Deleting all the bricks of the "
+ "volume is not allowed");
+ if (!errstr) {
+ gf_log ("", GF_LOG_ERROR, "Out of memory");
+ ret = -1;
+ goto out;
+ }
+
+ ret = dict_set_dynstr (ctx, "errstr", errstr);
+ if (ret) {
+ GF_FREE (errstr);
+ gf_log ("", GF_LOG_DEBUG,
+ "failed to set pump status in ctx");
+ goto out;
+ }
+
+ ret = -1;
+ goto out;
+ }
+
+out:
+ gf_log ("", GF_LOG_DEBUG, "Returning %d", ret);
+
+ return ret;
+}
+
+int
+glusterd_op_add_brick (dict_t *dict, char **op_errstr)
+{
+ int ret = 0;
+ char *volname = NULL;
+ glusterd_conf_t *priv = NULL;
+ glusterd_volinfo_t *volinfo = NULL;
+ xlator_t *this = NULL;
+ char *bricks = NULL;
+ int32_t count = 0;
+
+ this = THIS;
+ GF_ASSERT (this);
+
+ priv = this->private;
+ GF_ASSERT (priv);
+
+ ret = dict_get_str (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) {
+ gf_log ("", GF_LOG_ERROR, "Unable to allocate memory");
+ goto out;
+ }
+
+ ret = dict_get_int32 (dict, "count", &count);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to get count");
+ goto out;
+ }
+
+
+ ret = dict_get_str (dict, "bricks", &bricks);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to get bricks");
+ goto out;
+ }
+
+ ret = glusterd_op_perform_add_bricks (volinfo, count, bricks);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to add bricks");
+ goto out;
+ }
+
+ volinfo->defrag_status = 0;
+
+ ret = glusterd_store_volinfo (volinfo, GLUSTERD_VOLINFO_VER_AC_INCREMENT);
+ if (ret)
+ goto out;
+
+ if (GLUSTERD_STATUS_STARTED == volinfo->status)
+ ret = glusterd_check_generate_start_nfs ();
+
+out:
+ return ret;
+}
+
+int
+glusterd_op_remove_brick (dict_t *dict)
+{
+ int ret = -1;
+ char *volname = NULL;
+ glusterd_volinfo_t *volinfo = NULL;
+ char *brick = NULL;
+ int32_t count = 0;
+ int32_t i = 1;
+ char key[256] = {0,};
+
+ ret = dict_get_str (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) {
+ gf_log ("", GF_LOG_ERROR, "Unable to allocate memory");
+ goto out;
+ }
+
+ ret = dict_get_int32 (dict, "count", &count);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to get count");
+ goto out;
+ }
+
+
+ while ( i <= count) {
+ snprintf (key, 256, "brick%d", i);
+ ret = dict_get_str (dict, key, &brick);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to get %s", key);
+ goto out;
+ }
+
+ ret = glusterd_op_perform_remove_brick (volinfo, brick);
+ if (ret)
+ goto out;
+ i++;
+ }
+
+ ret = glusterd_create_volfiles_and_notify_services (volinfo);
+ if (ret)
+ goto out;
+
+ volinfo->defrag_status = 0;
+
+ ret = glusterd_store_volinfo (volinfo, GLUSTERD_VOLINFO_VER_AC_INCREMENT);
+
+ if (ret)
+ goto out;
+
+ if (GLUSTERD_STATUS_STARTED == volinfo->status)
+ ret = glusterd_check_generate_start_nfs ();
+
+out:
+ return ret;
+}