/* Copyright (c) 2006-2009 Gluster, Inc. This file is part of GlusterFS. GlusterFS is GF_FREE software; you can redistribute it and/or modify it under the terms of the GNU Affero 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #ifndef _CONFIG_H #define _CONFIG_H #include "config.h" #endif #include #include #include #include #include "uuid.h" #include "fnmatch.h" #include "xlator.h" #include "protocol-common.h" #include "glusterd.h" #include "call-stub.h" #include "defaults.h" #include "list.h" #include "dict.h" #include "compat.h" #include "compat-errno.h" #include "statedump.h" #include "glusterd-sm.h" #include "glusterd-op-sm.h" #include "glusterd-utils.h" #include "glusterd-store.h" #include "cli1.h" #include "glusterd-volgen.h" #include #include #define glusterd_op_start_volume_args_get(req, dict, volname, flags) \ glusterd_op_stop_volume_args_get (req, dict, volname, flags) static struct list_head gd_op_sm_queue; pthread_mutex_t gd_op_sm_lock; glusterd_op_info_t opinfo = {{0},}; static int glusterfs_port = GLUSTERD_DEFAULT_PORT; void glusterd_destroy_lock_ctx (glusterd_op_lock_ctx_t *ctx) { if (!ctx) return; GF_FREE (ctx); } void glusterd_destroy_stage_ctx (glusterd_op_stage_ctx_t *ctx) { if (!ctx) return; if (ctx->stage_req.buf.buf_val) GF_FREE (ctx->stage_req.buf.buf_val); GF_FREE (ctx); } void glusterd_destroy_commit_ctx (glusterd_op_commit_ctx_t *ctx) { if (!ctx) return; if (ctx->stage_req.buf.buf_val) GF_FREE (ctx->stage_req.buf.buf_val); GF_FREE (ctx); } void glusterd_set_volume_status (glusterd_volinfo_t *volinfo, glusterd_volume_status status) { GF_ASSERT (volinfo); volinfo->status = status; } static int glusterd_is_volume_started (glusterd_volinfo_t *volinfo) { GF_ASSERT (volinfo); return (!(volinfo->status == GLUSTERD_STATUS_STARTED)); } gf_boolean_t glusterd_are_all_volumes_stopped () { glusterd_conf_t *priv = NULL; xlator_t *this = NULL; glusterd_volinfo_t *voliter = NULL; this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); list_for_each_entry (voliter, &priv->volumes, vol_list) { if (voliter->status == GLUSTERD_STATUS_STARTED) return _gf_false; } return _gf_true; } static int glusterd_op_get_len (glusterd_op_t op) { GF_ASSERT (op < GD_OP_MAX); GF_ASSERT (op > GD_OP_NONE); int ret = -1; switch (op) { case GD_OP_CREATE_VOLUME: { dict_t *dict = glusterd_op_get_ctx (op); ret = dict_serialized_length (dict); return ret; } break; case GD_OP_START_BRICK: break; case GD_OP_SET_VOLUME: case GD_OP_RESET_VOLUME: case GD_OP_REPLACE_BRICK: case GD_OP_ADD_BRICK: { dict_t *dict = glusterd_op_get_ctx (op); ret = dict_serialized_length (dict); return ret; } case GD_OP_REMOVE_BRICK: { dict_t *dict = glusterd_op_get_ctx (op); ret = dict_serialized_length (dict); return ret; } break; break; default: GF_ASSERT (op); } return 0; } static int glusterd_op_sm_inject_all_acc () { int32_t ret = -1; ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACC, NULL); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } int glusterd_op_build_payload (glusterd_op_t op, gd1_mgmt_stage_op_req **req) { int len = 0; int ret = -1; gd1_mgmt_stage_op_req *stage_req = NULL; void *ctx = NULL; GF_ASSERT (op < GD_OP_MAX); GF_ASSERT (op > GD_OP_NONE); GF_ASSERT (req); len = glusterd_op_get_len (op); stage_req = GF_CALLOC (1, sizeof (*stage_req), gf_gld_mt_mop_stage_req_t); if (!stage_req) { gf_log ("", GF_LOG_ERROR, "Out of Memory"); goto out; } glusterd_get_uuid (&stage_req->uuid); stage_req->op = op; //stage_req->buf.buf_len = len; ctx = (void*)glusterd_op_get_ctx (op); if (!ctx) { gf_log ("", GF_LOG_ERROR, "Null Context for " "op %d", op); ret = -1; goto out; } switch (op) { case GD_OP_CREATE_VOLUME: { dict_t *dict = ctx; ++glusterfs_port; ret = dict_set_int32 (dict, "port", glusterfs_port); ret = dict_allocate_and_serialize (dict, &stage_req->buf.buf_val, (size_t *)&stage_req->buf.buf_len); if (ret) { goto out; } } break; case GD_OP_DELETE_VOLUME: { glusterd_op_delete_volume_ctx_t *ctx1 = ctx; stage_req->buf.buf_len = strlen (ctx1->volume_name); stage_req->buf.buf_val = gf_strdup (ctx1->volume_name); } break; case GD_OP_START_VOLUME: case GD_OP_STOP_VOLUME: case GD_OP_ADD_BRICK: case GD_OP_REPLACE_BRICK: case GD_OP_SET_VOLUME: case GD_OP_RESET_VOLUME: case GD_OP_REMOVE_BRICK: case GD_OP_LOG_FILENAME: case GD_OP_LOG_ROTATE: case GD_OP_SYNC_VOLUME: { dict_t *dict = ctx; ret = dict_allocate_and_serialize (dict, &stage_req->buf.buf_val, (size_t *)&stage_req->buf.buf_len); if (ret) { goto out; } } break; default: break; } *req = stage_req; ret = 0; out: return ret; } static int glusterd_op_stage_create_volume (gd1_mgmt_stage_op_req *req, char **op_errstr) { int ret = 0; dict_t *dict = NULL; char *volname = NULL; gf_boolean_t exists = _gf_false; char *bricks = NULL; char *brick_list = NULL; char *free_ptr = NULL; glusterd_brickinfo_t *brick_info = NULL; int32_t brick_count = 0; int32_t i = 0; struct stat st_buf = {0,}; char *brick = NULL; char *tmpptr = NULL; char cmd_str[1024]; xlator_t *this = NULL; glusterd_conf_t *priv = NULL; char msg[2048] = {0,}; GF_ASSERT (req); this = THIS; if (!this) { gf_log ("glusterd", GF_LOG_ERROR, "this is NULL"); goto out; } priv = this->private; if (!priv) { gf_log ("glusterd", GF_LOG_ERROR, "priv is NULL"); goto out; } dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); goto out; } ret = dict_get_str (dict, "volname", &volname); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); goto out; } exists = glusterd_check_volume_exists (volname); if (exists) { gf_log ("", GF_LOG_ERROR, "Volume with name: %s exists", volname); ret = -1; } else { ret = 0; } ret = dict_get_int32 (dict, "count", &brick_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); if (!brick_list) { ret = -1; gf_log ("", GF_LOG_ERROR, "Out of memory"); goto out; } else { free_ptr = brick_list; } } while ( i < brick_count) { i++; brick= strtok_r (brick_list, " \n", &tmpptr); brick_list = tmpptr; ret = glusterd_brickinfo_from_brick (brick, &brick_info); if (ret) goto out; snprintf (cmd_str, 1024, "%s", brick_info->path); ret = glusterd_resolve_brick (brick_info); if (ret) { gf_log ("glusterd", GF_LOG_ERROR, "cannot resolve " "brick: %s:%s", brick_info->hostname, brick_info->path); goto out; } if (!uuid_compare (brick_info->uuid, priv->uuid)) { ret = stat (cmd_str, &st_buf); if (ret == -1) { snprintf (msg, 2048,"Volume name %s, brick" ": %s:%s, path %s not present", volname, brick_info->hostname, brick_info->path, brick_info->path); gf_log ("glusterd",GF_LOG_ERROR, "%s", msg); *op_errstr = gf_strdup (msg); goto out; } if (!S_ISDIR (st_buf.st_mode)) { snprintf (msg, 2048, "Volume name %s, brick" ": %s, path %s is not a directory", volname, brick, brick_info->path); gf_log ("glusterd", GF_LOG_ERROR, "%s", msg); *op_errstr = gf_strdup (msg); ret = -1; goto out; } brick_list = tmpptr; } glusterd_brickinfo_delete (brick_info); } out: if (dict) dict_unref (dict); if (free_ptr) GF_FREE (free_ptr); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_op_stop_volume_args_get (gd1_mgmt_stage_op_req *req, dict_t *dict, char** volname, int *flags) { int ret = -1; if (!req || !dict || !volname || !flags) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); goto out; } ret = dict_get_str (dict, "volname", volname); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); goto out; } ret = dict_get_int32 (dict, "flags", flags); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get flags"); goto out; } out: return ret; } static int glusterd_op_stage_start_volume (gd1_mgmt_stage_op_req *req, char **op_errstr) { int ret = 0; dict_t *dict = NULL; char *volname = NULL; int flags = 0; gf_boolean_t exists = _gf_false; glusterd_volinfo_t *volinfo = NULL; glusterd_brickinfo_t *brickinfo = NULL; struct stat statbuf = {0,}; char msg[2048]; glusterd_conf_t *priv = NULL; GF_ASSERT (req); priv = THIS->private; if (!priv) { gf_log ("glusterd", GF_LOG_ERROR, "priv is NULL"); ret = -1; goto out; } dict = dict_new (); if (!dict) goto out; ret = glusterd_op_start_volume_args_get (req, dict, &volname, &flags); if (ret) goto out; exists = glusterd_check_volume_exists (volname); if (!exists) { snprintf (msg, 2048, "Volume with name %s does not exist", volname); gf_log ("", GF_LOG_ERROR, "%s", msg); *op_errstr = gf_strdup (msg); ret = -1; } else { ret = 0; } ret = glusterd_volinfo_find (volname, &volinfo); if (ret) goto out; list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { ret = glusterd_resolve_brick (brickinfo); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to resolve brick" " with hostname: %s, export: %s", brickinfo->hostname,brickinfo->path); goto out; } if (!uuid_compare (brickinfo->uuid, priv->uuid)) { ret = stat (brickinfo->path, &statbuf); if (ret == -1) { snprintf (msg, 2048, "Volume name %s, brick" ": %s:%s, path %s is not present", volname, brickinfo->hostname, brickinfo->path, brickinfo->path); gf_log ("glusterd", GF_LOG_ERROR, "%s", msg); *op_errstr = gf_strdup (msg); goto out; } } if (!(flags & GF_CLI_FLAG_OP_FORCE)) { ret = glusterd_is_volume_started (volinfo); if (!ret) { snprintf (msg, 2048, "Volume %s already started", volname); gf_log ("glusterd", GF_LOG_ERROR, "%s", msg); *op_errstr = gf_strdup (msg); ret = -1; goto out; } } } ret = 0; out: if (dict) dict_unref (dict); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_op_stage_stop_volume (gd1_mgmt_stage_op_req *req) { int ret = -1; dict_t *dict = NULL; char *volname = NULL; int flags = 0; gf_boolean_t exists = _gf_false; glusterd_volinfo_t *volinfo = NULL; dict = dict_new (); if (!dict) goto out; ret = glusterd_op_stop_volume_args_get (req, dict, &volname, &flags); if (ret) goto out; exists = glusterd_check_volume_exists (volname); if (!exists) { gf_log ("", GF_LOG_ERROR, "Volume with name %s does not exist", volname); ret = -1; } else { ret = 0; } ret = glusterd_volinfo_find (volname, &volinfo); if (ret) goto out; if (!(flags & GF_CLI_FLAG_OP_FORCE)) { ret = glusterd_is_volume_started (volinfo); if (ret) { gf_log ("", GF_LOG_ERROR, "Volume %s " "has not been started", volname); goto out; } } out: if (dict) dict_unref (dict); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_op_stage_delete_volume (gd1_mgmt_stage_op_req *req) { int ret = 0; char volname [1024] = {0,}; gf_boolean_t exists = _gf_false; glusterd_volinfo_t *volinfo = NULL; GF_ASSERT (req); strncpy (volname, req->buf.buf_val, req->buf.buf_len); exists = glusterd_check_volume_exists (volname); if (!exists) { gf_log ("", GF_LOG_ERROR, "Volume with name %s does not exist", volname); ret = -1; goto out; } else { ret = 0; } ret = glusterd_volinfo_find (volname, &volinfo); if (ret) goto out; ret = glusterd_is_volume_started (volinfo); if (!ret) { gf_log ("", GF_LOG_ERROR, "Volume %s has been started." "Volume needs to be stopped before deletion.", volname); ret = -1; goto out; } ret = 0; out: gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_op_stage_add_brick (gd1_mgmt_stage_op_req *req, char **op_errstr) { int ret = 0; dict_t *dict = NULL; 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; struct stat st_buf = {0,}; char cmd_str[1024]; glusterd_conf_t *priv = NULL; char msg[2048] = {0,}; GF_ASSERT (req); priv = THIS->private; if (!priv) goto out; dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); 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); free_ptr = brick_list; } if (count) brick = strtok_r (brick_list+1, " \n", &saveptr); while ( i < count) { 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; } } 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 = stat (cmd_str, &st_buf); if (ret == -1) { snprintf (msg, 2048, "Volume name %s, brick" ": %s, path %s not present", volname, brick, brickinfo->path); gf_log ("glusterd", GF_LOG_ERROR, "%s", msg); *op_errstr = gf_strdup (msg); goto out; } if (!S_ISDIR (st_buf.st_mode)) { snprintf (msg, 2048, "Volume name %s, brick" ": %s, path %s is not a directory", volname, brick, brickinfo->path); gf_log ("glusterd", GF_LOG_ERROR, "%s", msg); *op_errstr = gf_strdup (msg); ret = -1; goto out; } } glusterd_brickinfo_delete (brickinfo); brick = strtok_r (NULL, " \n", &saveptr); i++; } out: if (dict) dict_unref (dict); if (free_ptr) GF_FREE (free_ptr); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_op_stage_replace_brick (gd1_mgmt_stage_op_req *req, char **op_errstr) { int ret = 0; dict_t *dict = NULL; char *src_brick = NULL; char *dst_brick = NULL; char *volname = NULL; gf1_cli_replace_op replace_op = 0; glusterd_volinfo_t *volinfo = NULL; glusterd_brickinfo_t *src_brickinfo = NULL; char *host = NULL; char *path = NULL; char msg[2048] = {0}; char *dup_dstbrick = NULL; glusterd_peerinfo_t *peerinfo = NULL; struct stat st_buf = {0,}; GF_ASSERT (req); dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); goto out; } ret = dict_get_str (dict, "src-brick", &src_brick); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get src brick"); goto out; } gf_log ("", GF_LOG_DEBUG, "src brick=%s", src_brick); ret = dict_get_str (dict, "dst-brick", &dst_brick); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get dest brick"); goto out; } gf_log ("", GF_LOG_DEBUG, "dst brick=%s", dst_brick); ret = dict_get_str (dict, "volname", &volname); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); goto out; } ret = dict_get_int32 (dict, "operation", (int32_t *)&replace_op); if (ret) { gf_log ("", GF_LOG_DEBUG, "dict get on replace-brick operation failed"); goto out; } ret = glusterd_volinfo_find (volname, &volinfo); if (ret) { snprintf (msg, sizeof (msg), "volume: %s does not exist", volname); *op_errstr = gf_strdup (msg); goto out; } if (GLUSTERD_STATUS_STARTED != volinfo->status) { ret = -1; snprintf (msg, sizeof (msg), "volume: %s is not started", volname); *op_errstr = gf_strdup (msg); 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 = glusterd_volume_brickinfo_get_by_brick (src_brick, volinfo, &src_brickinfo); if (ret) { snprintf (msg, sizeof (msg), "brick: %s does not exist in " "volume: %s", src_brick, volname); *op_errstr = gf_strdup (msg); goto out; } if (!glusterd_is_local_addr (src_brickinfo->hostname)) { gf_log ("", GF_LOG_DEBUG, "I AM THE SOURCE HOST"); } dup_dstbrick = gf_strdup (dst_brick); if (!dup_dstbrick) { ret = -1; gf_log ("", GF_LOG_ERROR, "Memory allocation failed"); goto out; } host = strtok (dup_dstbrick, ":"); path = strtok (NULL, ":"); if (!host || !path) { gf_log ("", GF_LOG_ERROR, "dst brick %s is not of form :", dst_brick); ret = -1; goto out; } if (!glusterd_brickinfo_get (NULL, host, path, NULL)) { snprintf(msg, sizeof(msg), "Brick: %s:%s already in use", host, path); *op_errstr = gf_strdup (msg); ret = -1; goto out; } if (!glusterd_is_local_addr (host)) { ret = stat (path, &st_buf); if (ret == -1) { snprintf (msg, sizeof (msg) ,"path: %s for brick: %s" " does not exist", path, dst_brick); gf_log ("glusterd", GF_LOG_ERROR, "%s", msg); *op_errstr = gf_strdup (msg); goto out; } if (!S_ISDIR (st_buf.st_mode)) { snprintf (msg, sizeof (msg), "Volume name %s, brick" ": %s, path %s is not a directory", volname, dst_brick, path); gf_log ("glusterd", GF_LOG_ERROR, "%s", msg); *op_errstr = gf_strdup (msg); ret = -1; goto out; } } else { ret = glusterd_friend_find (NULL, host, &peerinfo); if (ret) { snprintf (msg, sizeof (msg), "%s, is not a friend", host); *op_errstr = gf_strdup (msg); goto out; } if (!peerinfo->connected) { snprintf (msg, sizeof (msg), "%s, is not connected at " "the moment", host); *op_errstr = gf_strdup (msg); ret = -1; goto out; } if (GD_FRIEND_STATE_BEFRIENDED != peerinfo->state.state) { snprintf (msg, sizeof (msg), "%s, is not befriended " "at the moment", host); *op_errstr = gf_strdup (msg); ret = -1; goto out; } } ret = 0; out: if (dup_dstbrick) GF_FREE (dup_dstbrick); if (dict) dict_unref (dict); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_op_stage_log_filename (gd1_mgmt_stage_op_req *req) { int ret = -1; dict_t *dict = NULL; char *volname = NULL; gf_boolean_t exists = _gf_false; GF_ASSERT (req); dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); goto out; } ret = dict_get_str (dict, "volname", &volname); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); goto out; } exists = glusterd_check_volume_exists (volname); if (!exists) { gf_log ("", GF_LOG_ERROR, "Volume with name: %s not exists", volname); ret = -1; goto out; } out: if (dict) dict_unref (dict); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_op_stage_log_rotate (gd1_mgmt_stage_op_req *req) { int ret = -1; dict_t *dict = NULL; char *volname = NULL; gf_boolean_t exists = _gf_false; GF_ASSERT (req); dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); goto out; } ret = dict_get_str (dict, "volname", &volname); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); goto out; } exists = glusterd_check_volume_exists (volname); if (!exists) { gf_log ("", GF_LOG_ERROR, "Volume with name: %s not exists", volname); ret = -1; goto out; } out: if (dict) dict_unref (dict); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_op_stage_set_volume (gd1_mgmt_stage_op_req *req, char **op_errstr) { int ret = 0; dict_t *dict = NULL; char *volname = NULL; gf_boolean_t exists = _gf_false; char *key = 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_ASSERT (req); dict = dict_new (); if (!dict) goto out; val_dict = dict_new(); if (!val_dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); goto out; } ret = dict_get_str (dict, "volname", &volname); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); goto out; } exists = glusterd_check_volume_exists (volname); if (!exists) { gf_log ("", GF_LOG_ERROR, "Volume with name: %s " "does not exist", volname); snprintf (errstr, 2048, "Volume : %s does not exist", key); *op_errstr = gf_strdup (errstr); ret = -1; 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", &dict_count); if (ret) { gf_log ("", GF_LOG_ERROR, "Count(dict),not set in Volume-Set"); goto out; } if ( dict_count == 1 ) { if (dict_get (dict, "history" )) { ret = 0; goto out; } gf_log ("", GF_LOG_ERROR, "No options received "); ret = -1; goto out; } for ( count = 1; ret != -1 ; count++ ) { sprintf (str, "key%d", count); ret = dict_get_str (dict, str, &key); if (ret) break; exists = glusterd_check_option_exists (key, NULL); if (exists != 1) { gf_log ("", GF_LOG_ERROR, "Option with name: %s " "does not exist", key); snprintf (errstr, 2048, "option : %s does not exist", key); *op_errstr = gf_strdup (errstr); ret = -1; goto out; } sprintf (str, "value%d", count); ret = dict_get_str (dict, str, &value); if (ret) { gf_log ("", GF_LOG_ERROR, "invalid key,value pair" "in 'volume set'"); ret = -1; goto out; } ret = dict_set_str (val_dict, key, value); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to set the options" "in 'volume set'"); ret = -1; goto out; } } *op_errstr = NULL; ret = glusterd_validate_reconfopts (volinfo, val_dict, op_errstr); if (ret) { gf_log ("glsuterd", GF_LOG_DEBUG, "Could not create temp volfile, some option failed: %s", *op_errstr); goto out; } ret = 0; out: if (dict) dict_unref (dict); if (ret) { if (!(*op_errstr)) { *op_errstr = gf_strdup ("Error, Validation Failed"); gf_log ("glsuterd", GF_LOG_DEBUG, "Error, Cannot Validate option :%s", *op_errstr); } else gf_log ("glsuterd", GF_LOG_DEBUG, "Error, Cannot Validate option"); } return ret; } static int glusterd_op_stage_reset_volume (gd1_mgmt_stage_op_req *req) { int ret = 0; dict_t *dict = NULL; char *volname = NULL; gf_boolean_t exists = _gf_false; GF_ASSERT (req); dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); goto out; } ret = dict_get_str (dict, "volname", &volname); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); goto out; } exists = glusterd_check_volume_exists (volname); if (!exists) { gf_log ("", GF_LOG_ERROR, "Volume with name: %s " "does not exist", volname); ret = -1; goto out; } out: if (dict) dict_unref (dict); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static 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_volfile (volinfo, brickinfo); glusterd_store_delete_brick (volinfo, brickinfo); glusterd_brickinfo_delete (brickinfo); volinfo->brick_count--; out: if (dup_brick) GF_FREE (dup_brick); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_op_perform_replace_brick (glusterd_volinfo_t *volinfo, char *old_brick, char *new_brick) { glusterd_brickinfo_t *old_brickinfo = NULL; glusterd_brickinfo_t *new_brickinfo = NULL; int32_t ret = -1; glusterd_conf_t *priv = NULL; priv = THIS->private; GF_ASSERT (volinfo); ret = glusterd_brickinfo_from_brick (new_brick, &new_brickinfo); if (ret) goto out; ret = glusterd_volume_brickinfo_get_by_brick (old_brick, volinfo, &old_brickinfo); if (ret) goto out; ret = glusterd_resolve_brick (new_brickinfo); if (ret) goto out; list_add_tail (&new_brickinfo->brick_list, &old_brickinfo->brick_list); volinfo->brick_count++; ret = glusterd_op_perform_remove_brick (volinfo, old_brick); if (ret) goto out; ret = glusterd_create_volfiles (volinfo); if (ret) goto out; if (GLUSTERD_STATUS_STARTED == volinfo->status) { ret = glusterd_brick_start (volinfo, new_brickinfo); if (ret) goto out; } out: gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static 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++; } 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 (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); } volinfo->brick_count += count; 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; } static int glusterd_op_stage_remove_brick (gd1_mgmt_stage_op_req *req) { int ret = -1; dict_t *dict = NULL; char *volname = NULL; glusterd_volinfo_t *volinfo = NULL; dict_t *ctx = NULL; char *errstr = NULL; GF_ASSERT (req); dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); 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, "Volume %s does not exist", volname); goto out; } if (glusterd_is_defrag_on(volinfo)) { ctx = glusterd_op_get_ctx (GD_OP_REMOVE_BRICK); 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; } if (volinfo->brick_count == 1) { ctx = glusterd_op_get_ctx (GD_OP_REMOVE_BRICK); if (!ctx) { gf_log ("", GF_LOG_ERROR, "Operation Context is not present"); ret = -1; goto out; } errstr = gf_strdup ("Deleting the last brick 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: if (dict) dict_unref (dict); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_op_stage_sync_volume (gd1_mgmt_stage_op_req *req, char **op_errstr) { int ret = -1; dict_t *dict = NULL; char *volname = NULL; char *hostname = NULL; gf_boolean_t exists = _gf_false; glusterd_peerinfo_t *peerinfo = NULL; char msg[2048] = {0,}; GF_ASSERT (req); dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); goto out; } ret = dict_get_str (dict, "hostname", &hostname); if (ret) { snprintf (msg, sizeof (msg), "hostname couldn't be " "retrieved from msg"); *op_errstr = gf_strdup (msg); 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 { //volname is not present in case of sync all ret = dict_get_str (dict, "volname", &volname); if (!ret) { exists = glusterd_check_volume_exists (volname); if (!exists) { snprintf (msg, sizeof (msg), "volume: %s, " "doesn't exist", volname); *op_errstr = gf_strdup (msg); ret = -1; goto out; } } else { ret = 0; } } out: if (dict) dict_unref (dict); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_op_create_volume (gd1_mgmt_stage_op_req *req, char **op_errstr) { int ret = 0; dict_t *dict = NULL; char *volname = NULL; glusterd_conf_t *priv = NULL; glusterd_volinfo_t *volinfo = NULL; glusterd_brickinfo_t *brickinfo = NULL; xlator_t *this = NULL; char *brick = NULL; int32_t count = 0; int32_t i = 1; char *bricks = NULL; char *brick_list = NULL; char *free_ptr = NULL; char *saveptr = NULL; int32_t sub_count = 0; char *trans_type = NULL; char *str = NULL; GF_ASSERT (req); this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); goto out; } ret = glusterd_volinfo_new (&volinfo); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to allocate memory"); goto out; } ret = dict_get_str (dict, "volname", &volname); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); goto out; } strncpy (volinfo->volname, volname, GLUSTERD_MAX_VOLUME_NAME); GF_ASSERT (volinfo->volname); ret = dict_get_int32 (dict, "type", &volinfo->type); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get type"); goto out; } ret = dict_get_int32 (dict, "count", &volinfo->brick_count); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get count"); goto out; } ret = dict_get_int32 (dict, "port", &volinfo->port); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get port"); goto out; } count = volinfo->brick_count; ret = dict_get_str (dict, "bricks", &bricks); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get bricks"); goto out; } if (GF_CLUSTER_TYPE_REPLICATE == volinfo->type) { ret = dict_get_int32 (dict, "replica-count", &sub_count); if (ret) goto out; } else if (GF_CLUSTER_TYPE_STRIPE == volinfo->type) { ret = dict_get_int32 (dict, "stripe-count", &sub_count); if (ret) goto out; } ret = dict_get_str (dict, "transport", &trans_type); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get transport"); goto out; } ret = dict_get_str (dict, "volume-id", &str); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get volume-id"); goto out; } ret = uuid_parse (str, volinfo->volume_id); if (ret) { gf_log ("", GF_LOG_ERROR, "unable to parse uuid %s", str); goto out; } if (strcasecmp (trans_type, "rdma") == 0) { volinfo->transport_type = GF_TRANSPORT_RDMA; } else { volinfo->transport_type = GF_TRANSPORT_TCP; } volinfo->sub_count = sub_count; if (bricks) { brick_list = gf_strdup (bricks); free_ptr = 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++; } list_add_tail (&volinfo->vol_list, &priv->volumes); volinfo->version++; volinfo->defrag_status = 0; ret = glusterd_store_create_volume (volinfo); if (ret) goto out; ret = glusterd_create_volfiles (volinfo); ret = glusterd_volume_compute_cksum (volinfo); if (ret) goto out; out: if (dict) dict_unref (dict); if (free_ptr) GF_FREE(free_ptr); return ret; } static int glusterd_op_add_brick (gd1_mgmt_stage_op_req *req, char **op_errstr) { int ret = 0; dict_t *dict = NULL; char *volname = NULL; glusterd_conf_t *priv = NULL; glusterd_volinfo_t *volinfo = NULL; xlator_t *this = NULL; char *bricks = NULL; int32_t count = 0; GF_ASSERT (req); this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); 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 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->version++; volinfo->defrag_status = 0; ret = glusterd_store_update_volume (volinfo); if (ret) goto out; ret = glusterd_volume_compute_cksum (volinfo); if (ret) goto out; if (GLUSTERD_STATUS_STARTED == volinfo->status) ret = glusterd_check_generate_start_nfs (volinfo); out: if (dict) dict_unref (dict); return ret; } static int rb_regenerate_volfiles (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *brickinfo, int32_t pump_needed) { dict_t *dict = NULL; int ret = 0; dict = volinfo->dict; gf_log ("", GF_LOG_DEBUG, "attempting to set pump value=%d", pump_needed); ret = dict_set_int32 (dict, "enable-pump", pump_needed); if (ret) { gf_log ("", GF_LOG_DEBUG, "could not dict_set enable-pump"); goto out; } ret = glusterd_create_rb_volfiles (volinfo, brickinfo); out: return ret; } static int rb_src_brick_restart (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *src_brickinfo, int activate_pump) { int ret = 0; gf_log ("", GF_LOG_DEBUG, "Attempting to kill src"); ret = glusterd_volume_stop_glusterfs (volinfo, src_brickinfo); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to stop " "glusterfs, ret: %d", ret); goto out; } glusterd_delete_volfile (volinfo, src_brickinfo); if (activate_pump) { ret = rb_regenerate_volfiles (volinfo, src_brickinfo, 1); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not regenerate volfiles with pump"); goto out; } } else { ret = rb_regenerate_volfiles (volinfo, src_brickinfo, 0); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not regenerate volfiles without pump"); goto out; } } sleep (2); ret = glusterd_volume_start_glusterfs (volinfo, src_brickinfo); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to start " "glusterfs, ret: %d", ret); goto out; } out: return ret; } static int rb_send_xattr_command (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *src_brickinfo, glusterd_brickinfo_t *dst_brickinfo, const char *xattr_key, const char *value) { glusterd_conf_t *priv = NULL; char mount_point_path[PATH_MAX] = {0,}; struct stat buf; int ret = -1; priv = THIS->private; snprintf (mount_point_path, PATH_MAX, "%s/vols/%s/%s", priv->workdir, volinfo->volname, RB_CLIENT_MOUNTPOINT); ret = stat (mount_point_path, &buf); if (ret) { gf_log ("", GF_LOG_DEBUG, "stat failed. Could not send " " %s command", xattr_key); goto out; } ret = lsetxattr (mount_point_path, xattr_key, value, strlen (value) + 1, 0); if (ret) { gf_log ("", GF_LOG_DEBUG, "setxattr failed"); goto out; } ret = 0; out: return ret; } static int rb_spawn_dst_brick (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *brickinfo) { glusterd_conf_t *priv = NULL; char cmd_str[8192] = {0,}; int ret = -1; int32_t port = 0; priv = THIS->private; port = pmap_registry_alloc (THIS); brickinfo->port = port; GF_ASSERT (port); snprintf (cmd_str, 8192, "%s/sbin/glusterfs -f %s/vols/%s/%s -p %s/vols/%s/%s " "--xlator-option src-server.listen-port=%d", GFS_PREFIX, priv->workdir, volinfo->volname, RB_DSTBRICKVOL_FILENAME, priv->workdir, volinfo->volname, RB_DSTBRICK_PIDFILE, port); ret = gf_system (cmd_str); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not start glusterfs"); goto out; } gf_log ("", GF_LOG_DEBUG, "Successfully started glusterfs: brick=%s:%s", brickinfo->hostname, brickinfo->path); ret = 0; out: return ret; } static int rb_spawn_glusterfs_client (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *brickinfo) { glusterd_conf_t *priv = NULL; char cmd_str[8192] = {0,}; struct stat buf; int ret = -1; priv = THIS->private; snprintf (cmd_str, 4096, "%s/sbin/glusterfs -f %s/vols/%s/%s %s/vols/%s/%s", GFS_PREFIX, priv->workdir, volinfo->volname, RB_CLIENTVOL_FILENAME, priv->workdir, volinfo->volname, RB_CLIENT_MOUNTPOINT); ret = gf_system (cmd_str); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not start glusterfs"); goto out; } gf_log ("", GF_LOG_DEBUG, "Successfully started glusterfs: brick=%s:%s", brickinfo->hostname, brickinfo->path); memset (cmd_str, 0, sizeof (cmd_str)); snprintf (cmd_str, 4096, "%s/vols/%s/%s", priv->workdir, volinfo->volname, RB_CLIENT_MOUNTPOINT); ret = stat (cmd_str, &buf); if (ret) { gf_log ("", GF_LOG_DEBUG, "stat on mountpoint failed"); goto out; } gf_log ("", GF_LOG_DEBUG, "stat on mountpoint succeeded"); ret = 0; out: return ret; } static const char *client_volfile_str = "volume mnt-client\n" " type protocol/client\n" " option remote-host %s\n" " option remote-subvolume %s\n" " option remote-port %d\n" "end-volume\n" "volume mnt-wb\n" " type performance/write-behind\n" " subvolumes mnt-client\n" "end-volume\n"; static int rb_generate_client_volfile (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *src_brickinfo) { glusterd_conf_t *priv = NULL; FILE *file = NULL; char filename[PATH_MAX]; int ret = -1; priv = THIS->private; gf_log ("", GF_LOG_DEBUG, "Creating volfile"); snprintf (filename, PATH_MAX, "%s/vols/%s/%s", priv->workdir, volinfo->volname, RB_CLIENTVOL_FILENAME); file = fopen (filename, "w+"); if (!file) { gf_log ("", GF_LOG_DEBUG, "Open of volfile failed"); ret = -1; goto out; } GF_ASSERT (src_brickinfo->port); fprintf (file, client_volfile_str, src_brickinfo->hostname, src_brickinfo->path, src_brickinfo->port); fclose (file); ret = 0; out: return ret; } static const char *dst_brick_volfile_str = "volume src-posix\n" " type storage/posix\n" " option directory %s\n" "end-volume\n" "volume %s\n" " type features/locks\n" " subvolumes src-posix\n" "end-volume\n" "volume src-server\n" " type protocol/server\n" " option auth.addr.%s.allow *\n" " option transport-type tcp\n" " subvolumes %s\n" "end-volume\n"; static int rb_generate_dst_brick_volfile (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *dst_brickinfo) { glusterd_conf_t *priv = NULL; FILE *file = NULL; char filename[PATH_MAX]; int ret = -1; priv = THIS->private; gf_log ("", GF_LOG_DEBUG, "Creating volfile"); snprintf (filename, PATH_MAX, "%s/vols/%s/%s", priv->workdir, volinfo->volname, RB_DSTBRICKVOL_FILENAME); file = fopen (filename, "w+"); if (!file) { gf_log ("", GF_LOG_DEBUG, "Open of volfile failed"); ret = -1; goto out; } fprintf (file, dst_brick_volfile_str, dst_brickinfo->path, dst_brickinfo->path, dst_brickinfo->path, dst_brickinfo->path); fclose (file); ret = 0; out: return ret; } static int rb_mountpoint_mkdir (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *src_brickinfo) { glusterd_conf_t *priv = NULL; char mount_point_path[PATH_MAX] = {0,}; int ret = -1; priv = THIS->private; snprintf (mount_point_path, PATH_MAX, "%s/vols/%s/%s", priv->workdir, volinfo->volname, RB_CLIENT_MOUNTPOINT); ret = mkdir (mount_point_path, 0777); if (ret && (errno != EEXIST)) { gf_log ("", GF_LOG_DEBUG, "mkdir failed, errno: %d", errno); goto out; } ret = 0; out: return ret; } static int rb_mountpoint_rmdir (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *src_brickinfo) { glusterd_conf_t *priv = NULL; char mount_point_path[PATH_MAX] = {0,}; int ret = -1; priv = THIS->private; snprintf (mount_point_path, PATH_MAX, "%s/vols/%s/%s", priv->workdir, volinfo->volname, RB_CLIENT_MOUNTPOINT); ret = rmdir (mount_point_path); if (ret) { gf_log ("", GF_LOG_DEBUG, "rmdir failed"); goto out; } ret = 0; out: return ret; } static int rb_destroy_maintainence_client (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *src_brickinfo) { glusterd_conf_t *priv = NULL; char cmd_str[8192] = {0,}; char filename[PATH_MAX] = {0,}; struct stat buf; char mount_point_path[PATH_MAX] = {0,}; int ret = -1; priv = THIS->private; snprintf (mount_point_path, PATH_MAX, "%s/vols/%s/%s", priv->workdir, volinfo->volname, RB_CLIENT_MOUNTPOINT); ret = stat (mount_point_path, &buf); if (ret) { gf_log ("", GF_LOG_DEBUG, "stat failed. Cannot destroy maintainence " "client"); goto out; } snprintf (cmd_str, 8192, "/bin/umount -f %s/vols/%s/%s", priv->workdir, volinfo->volname, RB_CLIENT_MOUNTPOINT); ret = gf_system (cmd_str); if (ret) { gf_log ("", GF_LOG_DEBUG, "umount failed on maintainence client"); goto out; } ret = rb_mountpoint_rmdir (volinfo, src_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "rmdir of mountpoint failed"); goto out; } snprintf (filename, PATH_MAX, "%s/vols/%s/%s", priv->workdir, volinfo->volname, RB_CLIENTVOL_FILENAME); ret = unlink (filename); if (ret) { gf_log ("", GF_LOG_DEBUG, "unlink failed"); goto out; } ret = 0; out: return ret; } static int rb_spawn_maintainence_client (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *src_brickinfo) { int ret = -1; ret = rb_generate_client_volfile (volinfo, src_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Unable to generate client " "volfile"); goto out; } ret = rb_mountpoint_mkdir (volinfo, src_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Unable to mkdir " "mountpoint"); goto out; } ret = rb_spawn_glusterfs_client (volinfo, src_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Unable to start glusterfs"); goto out; } ret = 0; out: return ret; } static int rb_spawn_destination_brick (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *dst_brickinfo) { int ret = -1; ret = rb_generate_dst_brick_volfile (volinfo, dst_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Unable to generate client " "volfile"); goto out; } ret = rb_spawn_dst_brick (volinfo, dst_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Unable to start glusterfs"); goto out; } ret = 0; out: return ret; } static int rb_do_operation_start (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *src_brickinfo, glusterd_brickinfo_t *dst_brickinfo) { char start_value[8192] = {0,}; int ret = -1; gf_log ("", GF_LOG_DEBUG, "replace-brick sending start xattr"); ret = rb_spawn_maintainence_client (volinfo, src_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not spawn maintainence " "client"); goto out; } gf_log ("", GF_LOG_DEBUG, "mounted the replace brick client"); snprintf (start_value, 8192, "%s:%s:%d", dst_brickinfo->hostname, dst_brickinfo->path, dst_brickinfo->port); ret = rb_send_xattr_command (volinfo, src_brickinfo, dst_brickinfo, RB_PUMP_START_CMD, start_value); if (ret) { gf_log ("", GF_LOG_DEBUG, "Failed to send command to pump"); } ret = rb_destroy_maintainence_client (volinfo, src_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Failed to destroy maintainence " "client"); goto out; } gf_log ("", GF_LOG_DEBUG, "unmounted the replace brick client"); ret = 0; out: return ret; } static int rb_do_operation_pause (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *src_brickinfo, glusterd_brickinfo_t *dst_brickinfo) { int ret = -1; gf_log ("", GF_LOG_NORMAL, "replace-brick send pause xattr"); ret = rb_spawn_maintainence_client (volinfo, src_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not spawn maintainence " "client"); goto out; } gf_log ("", GF_LOG_DEBUG, "mounted the replace brick client"); ret = rb_send_xattr_command (volinfo, src_brickinfo, dst_brickinfo, RB_PUMP_PAUSE_CMD, "jargon"); if (ret) { gf_log ("", GF_LOG_DEBUG, "Failed to send command to pump"); } ret = rb_destroy_maintainence_client (volinfo, src_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Failed to destroy maintainence " "client"); goto out; } gf_log ("", GF_LOG_DEBUG, "unmounted the replace brick client"); ret = 0; out: if (!glusterd_is_local_addr (src_brickinfo->hostname)) { ret = rb_src_brick_restart (volinfo, src_brickinfo, 0); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not restart src-brick"); } } return ret; } static int rb_kill_destination_brick (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *dst_brickinfo) { glusterd_conf_t *priv = NULL; char pidfile[PATH_MAX] = {0,}; priv = THIS->private; snprintf (pidfile, PATH_MAX, "%s/vols/%s/%s", priv->workdir, volinfo->volname, RB_DSTBRICK_PIDFILE); return glusterd_service_stop ("brick", pidfile, SIGTERM, _gf_true); } static int rb_do_operation_abort (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *src_brickinfo, glusterd_brickinfo_t *dst_brickinfo) { int ret = -1; gf_log ("", GF_LOG_DEBUG, "replace-brick sending abort xattr"); ret = rb_spawn_maintainence_client (volinfo, src_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not spawn maintainence " "client"); goto out; } gf_log ("", GF_LOG_DEBUG, "mounted the replace brick client"); ret = rb_send_xattr_command (volinfo, src_brickinfo, dst_brickinfo, RB_PUMP_ABORT_CMD, "jargon"); if (ret) { gf_log ("", GF_LOG_DEBUG, "Failed to send command to pump"); } ret = rb_destroy_maintainence_client (volinfo, src_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Failed to destroy maintainence " "client"); goto out; } gf_log ("", GF_LOG_DEBUG, "unmounted the replace brick client"); ret = 0; out: if (!glusterd_is_local_addr (src_brickinfo->hostname)) { ret = rb_src_brick_restart (volinfo, src_brickinfo, 0); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not restart src-brick"); } } return ret; } static int rb_get_xattr_command (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *src_brickinfo, glusterd_brickinfo_t *dst_brickinfo, const char *xattr_key, char *value) { glusterd_conf_t *priv = NULL; char mount_point_path[PATH_MAX] = {0,}; struct stat buf; int ret = -1; priv = THIS->private; snprintf (mount_point_path, PATH_MAX, "%s/vols/%s/%s", priv->workdir, volinfo->volname, RB_CLIENT_MOUNTPOINT); ret = stat (mount_point_path, &buf); if (ret) { gf_log ("", GF_LOG_DEBUG, "stat failed. Could not send " " %s command", xattr_key); goto out; } ret = lgetxattr (mount_point_path, xattr_key, value, 8192); if (ret < 0) { gf_log ("", GF_LOG_DEBUG, "getxattr failed"); goto out; } ret = 0; out: return ret; } static int rb_do_operation_status (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *src_brickinfo, glusterd_brickinfo_t *dst_brickinfo) { char status[2048] = {0,}; char *status_reply = NULL; dict_t *ctx = NULL; int ret = 0; gf_boolean_t origin = _gf_false; ctx = glusterd_op_get_ctx (GD_OP_REPLACE_BRICK); if (!ctx) { gf_log ("", GF_LOG_ERROR, "Operation Context is not present"); goto out; } origin = _gf_true; if (origin) { ret = rb_spawn_maintainence_client (volinfo, src_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not spawn maintainence " "client"); goto out; } gf_log ("", GF_LOG_DEBUG, "mounted the replace brick client"); ret = rb_get_xattr_command (volinfo, src_brickinfo, dst_brickinfo, RB_PUMP_STATUS_CMD, status); if (ret) { gf_log ("", GF_LOG_DEBUG, "Failed to get status from pump"); goto umount; } gf_log ("", GF_LOG_DEBUG, "pump status is %s", status); status_reply = gf_strdup (status); if (!status_reply) { gf_log ("", GF_LOG_ERROR, "Out of memory"); ret = -1; goto umount; } ret = dict_set_dynstr (ctx, "status-reply", status_reply); if (ret) { gf_log ("", GF_LOG_DEBUG, "failed to set pump status in ctx"); } umount: ret = rb_destroy_maintainence_client (volinfo, src_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Failed to destroy maintainence " "client"); goto out; } } gf_log ("", GF_LOG_DEBUG, "unmounted the replace brick client"); out: return ret; } static int glusterd_op_replace_brick (gd1_mgmt_stage_op_req *req, dict_t *rsp_dict) { int ret = 0; dict_t *dict = NULL; dict_t *ctx = NULL; gf1_cli_replace_op replace_op; glusterd_volinfo_t *volinfo = NULL; char *volname = NULL; xlator_t *this = NULL; glusterd_conf_t *priv = NULL; char *src_brick = NULL; char *dst_brick = NULL; glusterd_brickinfo_t *src_brickinfo = NULL; glusterd_brickinfo_t *dst_brickinfo = NULL; GF_ASSERT (req); this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); goto out; } ret = dict_get_str (dict, "src-brick", &src_brick); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get src brick"); goto out; } gf_log (this->name, GF_LOG_DEBUG, "src brick=%s", src_brick); ret = dict_get_str (dict, "dst-brick", &dst_brick); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get dst brick"); goto out; } gf_log (this->name, GF_LOG_DEBUG, "dst brick=%s", dst_brick); ret = dict_get_str (dict, "volname", &volname); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); goto out; } ret = dict_get_int32 (dict, "operation", (int32_t *)&replace_op); if (ret) { gf_log (this->name, GF_LOG_DEBUG, "dict_get on operation failed"); goto out; } ret = glusterd_volinfo_find (volname, &volinfo); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to allocate memory"); goto out; } ret = glusterd_volume_brickinfo_get_by_brick (src_brick, volinfo, &src_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Unable to get src-brickinfo"); goto out; } ret = glusterd_brickinfo_from_brick (dst_brick, &dst_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Unable to get dst-brickinfo"); goto out; } ret = glusterd_resolve_brick (dst_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Unable to resolve dst-brickinfo"); goto out; } /* Set src-brick's port number to be used in the maintainance mount * after all commit acks are received. */ if (!glusterd_is_local_addr (src_brickinfo->hostname)) { gf_log ("", GF_LOG_NORMAL, "adding src-brick port no"); src_brickinfo->port = pmap_registry_search (this, src_brickinfo->path, GF_PMAP_PORT_BRICKSERVER); if (!src_brickinfo->port && replace_op != GF_REPLACE_OP_COMMIT_FORCE ) { gf_log ("", GF_LOG_ERROR, "Src brick port not available"); ret = -1; goto out; } if (rsp_dict) { ret = dict_set_int32 (rsp_dict, "src-brick-port", src_brickinfo->port); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not set src-brick port no"); goto out; } } else { ctx = glusterd_op_get_ctx (GD_OP_REPLACE_BRICK); GF_ASSERT (ctx); ret = dict_set_int32 (ctx, "src-brick-port", src_brickinfo->port); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not set src-brick port no"); goto out; } } } switch (replace_op) { case GF_REPLACE_OP_START: { if (!glusterd_is_local_addr (dst_brickinfo->hostname)) { gf_log ("", GF_LOG_NORMAL, "I AM THE DESTINATION HOST"); ret = rb_spawn_destination_brick (volinfo, dst_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Failed to spawn destination brick"); goto out; } if (!glusterd_is_local_addr (dst_brickinfo->hostname)) { gf_log ("", GF_LOG_NORMAL, "adding dst-brick port no"); if (rsp_dict) { ret = dict_set_int32 (rsp_dict, "dst-brick-port", dst_brickinfo->port); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not set dst-brick port no"); goto out; } } else { ctx = glusterd_op_get_ctx (GD_OP_REPLACE_BRICK); GF_ASSERT (ctx); ret = dict_set_int32 (ctx, "dst-brick-port", dst_brickinfo->port); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not set dst-brick port no"); goto out; } } } } if (!glusterd_is_local_addr (src_brickinfo->hostname)) { ret = rb_src_brick_restart (volinfo, src_brickinfo, 1); if (ret) { gf_log ("", GF_LOG_DEBUG, "Could not restart src-brick"); goto out; } } break; } case GF_REPLACE_OP_COMMIT: case GF_REPLACE_OP_COMMIT_FORCE: { ret = dict_set_int32 (volinfo->dict, "enable-pump", 0); gf_log ("", GF_LOG_DEBUG, "Received commit - will be adding dst brick and " "removing src brick"); if (!glusterd_is_local_addr (dst_brickinfo->hostname) && replace_op != GF_REPLACE_OP_COMMIT_FORCE) { gf_log ("", GF_LOG_NORMAL, "I AM THE DESTINATION HOST"); ret = rb_kill_destination_brick (volinfo, dst_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Failed to kill destination brick"); goto out; } } if (ret) { gf_log ("", GF_LOG_CRITICAL, "Unable to cleanup " "dst brick"); goto out; } ret = glusterd_op_perform_replace_brick (volinfo, src_brick, dst_brick); if (ret) { gf_log ("", GF_LOG_CRITICAL, "Unable to add " "dst-brick: %s to volume: %s", dst_brick, volinfo->volname); goto out; } volinfo->version++; volinfo->defrag_status = 0; ret = glusterd_store_update_volume (volinfo); if (ret) goto out; ret = glusterd_volume_compute_cksum (volinfo); if (ret) goto out; ret = glusterd_check_generate_start_nfs (volinfo); if (ret) { gf_log ("", GF_LOG_CRITICAL, "Failed to generate " " nfs volume file"); } ret = glusterd_fetchspec_notify (THIS); } break; case GF_REPLACE_OP_PAUSE: { gf_log ("", GF_LOG_DEBUG, "Recieved pause - doing nothing"); ret = rb_do_operation_pause (volinfo, src_brickinfo, dst_brickinfo); if (!glusterd_is_local_addr (dst_brickinfo->hostname)) { gf_log ("", GF_LOG_NORMAL, "I AM THE DESTINATION HOST"); ret = rb_kill_destination_brick (volinfo, dst_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Failed to kill destination brick"); goto out; } } } break; case GF_REPLACE_OP_ABORT: { ret = dict_set_int32 (volinfo->dict, "enable-pump", 0); if (ret) { gf_log ("", GF_LOG_CRITICAL, "Unable to disable pump"); } ret = rb_do_operation_abort (volinfo, src_brickinfo, dst_brickinfo); if (!glusterd_is_local_addr (dst_brickinfo->hostname)) { gf_log ("", GF_LOG_NORMAL, "I AM THE DESTINATION HOST"); ret = rb_kill_destination_brick (volinfo, dst_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Failed to kill destination brick"); goto out; } } } break; case GF_REPLACE_OP_STATUS: { gf_log ("", GF_LOG_DEBUG, "received status - doing nothing"); ret = rb_do_operation_status (volinfo, src_brickinfo, dst_brickinfo); } break; default: ret = -1; goto out; } if (ret) goto out; out: if (dict) dict_unref (dict); return ret; } void _delete_reconfig_opt (dict_t *this, char *key, data_t *value, void *data) { int exists = 0; exists = glusterd_check_option_exists (key, NULL); if (exists == 1) { gf_log ("", GF_LOG_DEBUG, "deleting dict with key=%s,value=%s", key, value->data); dict_del (this, key); } } int glusterd_options_reset (glusterd_volinfo_t *volinfo) { int ret = 0; gf_log ("", GF_LOG_DEBUG, "Received volume set reset command"); GF_ASSERT (volinfo->dict); dict_foreach (volinfo->dict, _delete_reconfig_opt, volinfo->dict); ret = glusterd_create_volfiles (volinfo); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to create volfile for" " 'volume set'"); ret = -1; goto out; } ret = glusterd_store_update_volume (volinfo); if (ret) goto out; ret = glusterd_volume_compute_cksum (volinfo); if (ret) goto out; if (GLUSTERD_STATUS_STARTED == volinfo->status) ret = glusterd_check_generate_start_nfs (volinfo); if (ret) goto out; ret = 0; out: gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_op_reset_volume (gd1_mgmt_stage_op_req *req) { glusterd_volinfo_t *volinfo = NULL; int ret = -1; char *volname = NULL; dict_t *dict = NULL; dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); 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 allocate memory"); goto out; } ret = glusterd_options_reset (volinfo); out: gf_log ("", GF_LOG_DEBUG, "'volume reset' returning %d", ret); return ret; } static int glusterd_op_set_volume (gd1_mgmt_stage_op_req *req) { int ret = 0; dict_t *dict = NULL; glusterd_volinfo_t *volinfo = NULL; char *volname = NULL; xlator_t *this = NULL; glusterd_conf_t *priv = NULL; int count = 1; char *key = NULL; char *value = NULL; char str[50] = {0, }; GF_ASSERT (req); this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); 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 allocate memory"); goto out; } for ( count = 1; ret != -1 ; count++ ) { sprintf (str, "key%d", count); ret = dict_get_str (dict, str, &key); if (ret) break; sprintf (str, "value%d", count); ret = dict_get_str (dict, str, &value); if (ret) { gf_log ("", GF_LOG_ERROR, "invalid key,value pair" "in 'volume set'"); ret = -1; goto out; } value = gf_strdup (value); if (value) ret = dict_set_dynstr (volinfo->dict, key, value); else ret = -1; if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to set the options" "in 'volume set'"); ret = -1; goto out; } } if ( count == 1 ) { gf_log ("", GF_LOG_ERROR, "No options received "); ret = -1; goto out; } ret = glusterd_create_volfiles (volinfo); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to create volfile for" " 'volume set'"); ret = -1; goto out; } ret = glusterd_store_update_volume (volinfo); if (ret) goto out; ret = glusterd_volume_compute_cksum (volinfo); if (ret) goto out; if (GLUSTERD_STATUS_STARTED == volinfo->status) ret = glusterd_check_generate_start_nfs (volinfo); ret = 0; out: if (dict) dict_unref (dict); gf_log ("", GF_LOG_DEBUG, "returning %d", ret); return ret; } static int glusterd_op_remove_brick (gd1_mgmt_stage_op_req *req) { int ret = -1; dict_t *dict = NULL; char *volname = NULL; glusterd_volinfo_t *volinfo = NULL; char *brick = NULL; int32_t count = 0; int32_t i = 1; char key[256] = {0,}; GF_ASSERT (req); dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); 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 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 (volinfo); if (ret) goto out; volinfo->version++; volinfo->defrag_status = 0; ret = glusterd_store_update_volume (volinfo); if (ret) goto out; ret = glusterd_volume_compute_cksum (volinfo); if (ret) goto out; if (GLUSTERD_STATUS_STARTED == volinfo->status) ret = glusterd_check_generate_start_nfs (volinfo); out: if (dict) dict_unref (dict); return ret; } static int glusterd_op_delete_volume (gd1_mgmt_stage_op_req *req) { int ret = 0; char volname[1024] = {0,}; glusterd_conf_t *priv = NULL; glusterd_volinfo_t *volinfo = NULL; xlator_t *this = NULL; GF_ASSERT (req); this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); strncpy (volname, req->buf.buf_val, req->buf.buf_len); ret = glusterd_volinfo_find (volname, &volinfo); if (ret) goto out; ret = glusterd_store_delete_volume (volinfo); if (ret) goto out; ret = glusterd_volinfo_delete (volinfo); if (ret) goto out; out: return ret; } static int glusterd_op_start_volume (gd1_mgmt_stage_op_req *req, char **op_errstr) { int ret = 0; char *volname = NULL; int flags = 0; glusterd_volinfo_t *volinfo = NULL; glusterd_brickinfo_t *brickinfo = NULL; dict_t *dict = NULL; GF_ASSERT (req); dict = dict_new (); if (!dict) goto out; ret = glusterd_op_start_volume_args_get (req, dict, &volname, &flags); if (ret) goto out; ret = glusterd_volinfo_find (volname, &volinfo); if (ret) goto out; list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { ret = glusterd_brick_start (volinfo, brickinfo); if (ret) goto out; } glusterd_set_volume_status (volinfo, GLUSTERD_STATUS_STARTED); ret = glusterd_store_update_volume (volinfo); if (ret) goto out; ret = glusterd_volume_compute_cksum (volinfo); if (ret) goto out; ret = glusterd_check_generate_start_nfs (volinfo); out: if (dict) dict_unref (dict); gf_log ("", GF_LOG_DEBUG, "returning %d ", ret); return ret; } static int glusterd_op_log_filename (gd1_mgmt_stage_op_req *req) { int ret = -1; dict_t *dict = NULL; glusterd_conf_t *priv = NULL; glusterd_volinfo_t *volinfo = NULL; glusterd_brickinfo_t *brickinfo = NULL; xlator_t *this = NULL; char *volname = NULL; char *brick = NULL; char *path = NULL; char logfile[PATH_MAX] = {0,}; char exp_path[PATH_MAX] = {0,}; struct stat stbuf = {0,}; int valid_brick = 0; glusterd_brickinfo_t *tmpbrkinfo = NULL; GF_ASSERT (req); this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); dict = dict_new (); if (!dict) { gf_log ("", GF_LOG_ERROR, "ENOMEM, !dict"); goto out; } ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); goto out; } ret = dict_get_str (dict, "volname", &volname); if (ret) { gf_log ("", GF_LOG_ERROR, "volname not found"); goto out; } ret = dict_get_str (dict, "path", &path); if (ret) { gf_log ("", GF_LOG_ERROR, "path not found"); goto out; } ret = dict_get_str (dict, "brick", &brick); if (ret) goto out; if (!strchr (brick, ':')) brick = NULL; else { ret = glusterd_brickinfo_from_brick (brick, &tmpbrkinfo); if (ret) { gf_log ("glusterd", GF_LOG_ERROR, "cannot get brickinfo from brick"); goto out; } } ret = glusterd_volinfo_find (volname, &volinfo); if (ret) goto out; ret = -1; list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { if (uuid_is_null (brickinfo->uuid)) { ret = glusterd_resolve_brick (brickinfo); } /* check if the brickinfo belongs to the 'this' machine */ if (uuid_compare (brickinfo->uuid, priv->uuid)) continue; if (brick && (strcmp (tmpbrkinfo->hostname, brickinfo->hostname) || strcmp (tmpbrkinfo->path,brickinfo->path))) continue; valid_brick = 1; /* If there are more than one brick in 'this' server, its an * extra check, but it doesn't harm functionality */ ret = stat (path, &stbuf); if (ret || !S_ISDIR (stbuf.st_mode)) { ret = -1; gf_log ("", GF_LOG_ERROR, "not a directory"); goto out; } GLUSTERD_REMOVE_SLASH_FROM_PATH (brickinfo->path, exp_path); snprintf (logfile, PATH_MAX, "%s/%s.log", path, exp_path); if (brickinfo->logfile) GF_FREE (brickinfo->logfile); brickinfo->logfile = gf_strdup (logfile); ret = 0; /* If request was for brick, only one iteration is enough */ if (brick) break; } if (ret && !valid_brick) ret = 0; out: if (dict) dict_unref (dict); if (tmpbrkinfo) glusterd_brickinfo_delete (tmpbrkinfo); return ret; } static int glusterd_op_log_rotate (gd1_mgmt_stage_op_req *req) { int ret = -1; dict_t *dict = NULL; glusterd_conf_t *priv = NULL; glusterd_volinfo_t *volinfo = NULL; glusterd_brickinfo_t *brickinfo = NULL; xlator_t *this = NULL; char *volname = NULL; char *brick = NULL; char path[PATH_MAX] = {0,}; char logfile[PATH_MAX] = {0,}; char pidfile[PATH_MAX] = {0,}; FILE *file = NULL; pid_t pid = 0; uint64_t key = 0; int valid_brick = 0; glusterd_brickinfo_t *tmpbrkinfo = NULL; GF_ASSERT (req); this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); dict = dict_new (); if (!dict) { gf_log ("", GF_LOG_ERROR, "ENOMEM, !dict"); goto out; } ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); goto out; } ret = dict_get_str (dict, "volname", &volname); if (ret) { gf_log ("", GF_LOG_ERROR, "volname not found"); goto out; } ret = dict_get_uint64 (dict, "rotate-key", &key); if (ret) { gf_log ("", GF_LOG_ERROR, "rotate key not found"); goto out; } ret = dict_get_str (dict, "brick", &brick); if (ret) goto out; if (!strchr (brick, ':')) brick = NULL; else { ret = glusterd_brickinfo_from_brick (brick, &tmpbrkinfo); if (ret) { gf_log ("glusterd", GF_LOG_ERROR, "cannot get brickinfo from brick"); goto out; } } ret = glusterd_volinfo_find (volname, &volinfo); if (ret) goto out; ret = -1; list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { if (uuid_compare (brickinfo->uuid, priv->uuid)) continue; if (brick && (strcmp (tmpbrkinfo->hostname, brickinfo->hostname) || strcmp (tmpbrkinfo->path,brickinfo->path))) continue; valid_brick = 1; GLUSTERD_GET_VOLUME_DIR (path, volinfo, priv); GLUSTERD_GET_BRICK_PIDFILE (pidfile, path, brickinfo->hostname, brickinfo->path); file = fopen (pidfile, "r+"); if (!file) { gf_log ("", GF_LOG_ERROR, "Unable to open pidfile: %s", pidfile); ret = -1; goto out; } ret = fscanf (file, "%d", &pid); if (ret <= 0) { gf_log ("", GF_LOG_ERROR, "Unable to read pidfile: %s", pidfile); ret = -1; goto out; } fclose (file); file = NULL; snprintf (logfile, PATH_MAX, "%s.%"PRIu64, brickinfo->logfile, key); ret = rename (brickinfo->logfile, logfile); if (ret) gf_log ("", GF_LOG_WARNING, "rename failed"); ret = kill (pid, SIGHUP); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to SIGHUP to %d", pid); goto out; } ret = 0; /* If request was for brick, only one iteration is enough */ if (brick) break; } if (ret && !valid_brick) ret = 0; out: if (dict) dict_unref (dict); if (tmpbrkinfo) glusterd_brickinfo_delete (tmpbrkinfo); return ret; } static int glusterd_op_stop_volume (gd1_mgmt_stage_op_req *req) { int ret = 0; int flags = 0; char *volname = NULL; glusterd_volinfo_t *volinfo = NULL; dict_t *dict = NULL; glusterd_brickinfo_t *brickinfo = NULL; dict = dict_new (); if (!dict) goto out; ret = glusterd_op_stop_volume_args_get (req, dict, &volname, &flags); if (ret) goto out; ret = glusterd_volinfo_find (volname, &volinfo); if (ret) goto out; list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { ret = glusterd_brick_stop (volinfo, brickinfo); if (ret) goto out; } glusterd_set_volume_status (volinfo, GLUSTERD_STATUS_STOPPED); ret = glusterd_store_update_volume (volinfo); if (ret) goto out; ret = glusterd_volume_compute_cksum (volinfo); if (glusterd_are_all_volumes_stopped ()) { if (glusterd_is_nfs_started ()) { ret = glusterd_nfs_server_stop (); if (ret) goto out; } } else { ret = glusterd_check_generate_start_nfs (volinfo); } out: if (dict) dict_unref (dict); return ret; } static int glusterd_op_sync_volume (gd1_mgmt_stage_op_req *req, char **op_errstr, dict_t *rsp_dict) { int ret = -1; dict_t *dict = NULL; char *volname = NULL; char *hostname = NULL; char msg[2048] = {0,}; int count = 1; int vol_count = 0; glusterd_conf_t *priv = NULL; glusterd_volinfo_t *volinfo = NULL; xlator_t *this = NULL; GF_ASSERT (req); this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); dict = dict_new (); if (!dict) goto out; ret = dict_unserialize (req->buf.buf_val, req->buf.buf_len, &dict); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to unserialize dict"); goto out; } ret = dict_get_str (dict, "hostname", &hostname); if (ret) { snprintf (msg, sizeof (msg), "hostname couldn't be " "retrieved from msg"); *op_errstr = gf_strdup (msg); goto out; } if (glusterd_is_local_addr (hostname)) { ret = 0; goto out; } //volname is not present in case of sync all ret = dict_get_str (dict, "volname", &volname); if (!ret) { ret = glusterd_volinfo_find (volname, &volinfo); if (ret) { gf_log ("", GF_LOG_ERROR, "Volume with name: %s " "not exists", volname); goto out; } } if (!rsp_dict) { //this should happen only on source ret = 0; goto out; } if (volname) { ret = glusterd_add_volume_to_dict (volinfo, rsp_dict, 1); vol_count = 1; } else { list_for_each_entry (volinfo, &priv->volumes, vol_list) { ret = glusterd_add_volume_to_dict (volinfo, rsp_dict, count); if (ret) goto out; vol_count = count++; } } ret = dict_set_int32 (rsp_dict, "count", vol_count); out: if (dict) dict_unref (dict); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_op_ac_none (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); return ret; } static int glusterd_op_ac_send_lock (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; rpc_clnt_procedure_t *proc = NULL; glusterd_conf_t *priv = NULL; xlator_t *this = NULL; this = THIS; priv = this->private; proc = &priv->mgmt->proctable[GD_MGMT_CLUSTER_LOCK]; if (proc->fn) { ret = proc->fn (NULL, this, NULL); if (ret) goto out; } if (!opinfo.pending_count) ret = glusterd_op_sm_inject_all_acc (); out: gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); return ret; } static int glusterd_op_ac_send_unlock (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; rpc_clnt_procedure_t *proc = NULL; glusterd_conf_t *priv = NULL; xlator_t *this = NULL; this = THIS; priv = this->private; /*ret = glusterd_unlock (priv->uuid); if (ret) goto out; */ proc = &priv->mgmt->proctable[GD_MGMT_CLUSTER_UNLOCK]; if (proc->fn) { ret = proc->fn (NULL, this, NULL); if (ret) goto out; } if (!opinfo.pending_count) ret = glusterd_op_sm_inject_all_acc (); out: gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); return ret; } static int glusterd_op_ac_lock (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; glusterd_op_lock_ctx_t *lock_ctx = NULL; int32_t status = 0; GF_ASSERT (event); GF_ASSERT (ctx); lock_ctx = (glusterd_op_lock_ctx_t *)ctx; status = glusterd_lock (lock_ctx->uuid); gf_log ("", GF_LOG_DEBUG, "Lock Returned %d", status); ret = glusterd_op_lock_send_resp (lock_ctx->req, status); gf_log ("", GF_LOG_DEBUG, "Returning with %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; GF_ASSERT (event); GF_ASSERT (ctx); lock_ctx = (glusterd_op_lock_ctx_t *)ctx; ret = glusterd_unlock (lock_ctx->uuid); gf_log ("", GF_LOG_DEBUG, "Unlock Returned %d", ret); ret = glusterd_op_unlock_send_resp (lock_ctx->req, ret); gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); return ret; } static int glusterd_op_ac_rcvd_lock_acc (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; GF_ASSERT (event); opinfo.pending_count--; if (opinfo.pending_count) goto out; ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACC, NULL); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); out: return ret; } static int glusterd_op_ac_send_stage_op (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; rpc_clnt_procedure_t *proc = NULL; glusterd_conf_t *priv = NULL; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); GF_ASSERT (priv->mgmt); proc = &priv->mgmt->proctable[GD_MGMT_STAGE_OP]; GF_ASSERT (proc); if (proc->fn) { ret = proc->fn (NULL, this, NULL); if (ret) goto out; } if (!opinfo.pending_count) ret = glusterd_op_sm_inject_all_acc (); out: gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); return ret; } static int32_t glusterd_op_start_rb_timer (dict_t *dict) { int32_t op = 0; struct timeval timeout = {0, }; glusterd_conf_t *priv = NULL; int32_t ret = -1; GF_ASSERT (dict); priv = THIS->private; ret = dict_get_int32 (dict, "operation", &op); if (ret) { gf_log ("", GF_LOG_DEBUG, "dict_get on operation failed"); goto out; } if (op == GF_REPLACE_OP_START || op == GF_REPLACE_OP_ABORT) timeout.tv_sec = 5; else timeout.tv_sec = 1; timeout.tv_usec = 0; priv->timer = gf_timer_call_after (THIS->ctx, timeout, glusterd_do_replace_brick, (void *) dict); ret = 0; out: return ret; } static int glusterd_op_ac_send_commit_op (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; rpc_clnt_procedure_t *proc = NULL; glusterd_conf_t *priv = NULL; xlator_t *this = NULL; dict_t *dict = NULL; this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); GF_ASSERT (priv->mgmt); proc = &priv->mgmt->proctable[GD_MGMT_COMMIT_OP]; GF_ASSERT (proc); if (proc->fn) { ret = proc->fn (NULL, this, NULL); if (ret) goto out; } if (!opinfo.pending_count) { dict = glusterd_op_get_ctx (GD_OP_REPLACE_BRICK); if (dict) { dict = dict_ref (dict); ret = glusterd_op_start_rb_timer (dict); if (ret) goto out; } else { ret = glusterd_op_sm_inject_all_acc (); } } out: gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); return ret; } static int glusterd_op_ac_rcvd_stage_op_acc (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; GF_ASSERT (event); opinfo.pending_count--; if (opinfo.pending_count) goto out; ret = glusterd_op_sm_inject_event (GD_OP_EVENT_STAGE_ACC, NULL); out: gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static gf_boolean_t rb_check_brick_signin (glusterd_brickinfo_t *brickinfo) { gf_boolean_t value; value = brickinfo->signed_in; if (value == _gf_true) { gf_log ("", GF_LOG_DEBUG, "Brick has signed in. Continuing..."); } return value; } void glusterd_do_replace_brick (void *data) { glusterd_volinfo_t *volinfo = NULL; int32_t op = 0; int32_t src_port = 0; int32_t dst_port = 0; dict_t *dict = NULL; char *src_brick = NULL; char *dst_brick = NULL; char *volname = NULL; gf_boolean_t brick_signin = _gf_false; glusterd_brickinfo_t *src_brickinfo = NULL; glusterd_brickinfo_t *dst_brickinfo = NULL; glusterd_conf_t *priv = NULL; int ret = 0; dict = data; GF_ASSERT (THIS); priv = THIS->private; if (priv->timer) { gf_timer_call_cancel (THIS->ctx, priv->timer); priv->timer = NULL; gf_log ("", GF_LOG_DEBUG, "Cancelled timer thread"); } gf_log ("", GF_LOG_DEBUG, "Replace brick operation detected"); ret = dict_get_int32 (dict, "operation", &op); if (ret) { gf_log ("", GF_LOG_DEBUG, "dict_get on operation failed"); goto out; } ret = dict_get_str (dict, "src-brick", &src_brick); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get src brick"); goto out; } gf_log ("", GF_LOG_DEBUG, "src brick=%s", src_brick); ret = dict_get_str (dict, "dst-brick", &dst_brick); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get dst brick"); goto out; } gf_log ("", GF_LOG_DEBUG, "dst brick=%s", dst_brick); 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 = glusterd_volume_brickinfo_get_by_brick (src_brick, volinfo, &src_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Unable to get src-brickinfo"); goto out; } ret = glusterd_brickinfo_from_brick (dst_brick, &dst_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Unable to get dst-brickinfo"); goto out; } ret = glusterd_resolve_brick (dst_brickinfo); if (ret) { gf_log ("", GF_LOG_DEBUG, "Unable to resolve dst-brickinfo"); goto out; } ret = dict_get_int32 (dict, "src-brick-port", &src_port); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get src-brick port"); goto out; } ret = dict_get_int32 (dict, "dst-brick-port", &dst_port); if (ret) { gf_log ("", GF_LOG_ERROR, "Unable to get dst-brick port"); goto out; } dst_brickinfo->port = dst_port; src_brickinfo->port = src_port; brick_signin = rb_check_brick_signin (src_brickinfo); if (brick_signin == _gf_false) { gf_log ("", GF_LOG_DEBUG, "Marking replace brick to fail due to brick " "not having signed-in in 10secs"); ret = -1; goto out; } switch (op) { case GF_REPLACE_OP_START: ret = rb_do_operation_start (volinfo, src_brickinfo, dst_brickinfo); break; case GF_REPLACE_OP_PAUSE: case GF_REPLACE_OP_ABORT: case GF_REPLACE_OP_COMMIT: case GF_REPLACE_OP_COMMIT_FORCE: case GF_REPLACE_OP_STATUS: break; default: ret = -1; goto out; } out: if (ret) ret = glusterd_op_sm_inject_event (GD_OP_EVENT_RCVD_RJT, NULL); else ret = glusterd_op_sm_inject_event (GD_OP_EVENT_COMMIT_ACC, NULL); glusterd_op_sm (); } static int glusterd_op_ac_rcvd_commit_op_acc (glusterd_op_sm_event_t *event, void *ctx) { glusterd_conf_t *priv = NULL; dict_t *dict = NULL; int ret = 0; gf_boolean_t commit_ack_inject = _gf_false; priv = THIS->private; GF_ASSERT (event); opinfo.pending_count--; if (opinfo.pending_count) goto out; dict = glusterd_op_get_ctx (GD_OP_REPLACE_BRICK); if (dict) { ret = glusterd_op_start_rb_timer (dict); if (ret) goto out; commit_ack_inject = _gf_false; goto out; } commit_ack_inject = _gf_true; out: if (commit_ack_inject) { if (ret) ret = glusterd_op_sm_inject_event (GD_OP_EVENT_RCVD_RJT, NULL); else ret = glusterd_op_sm_inject_event (GD_OP_EVENT_COMMIT_ACC, NULL); } return ret; } static int glusterd_op_ac_rcvd_unlock_acc (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; GF_ASSERT (event); opinfo.pending_count--; if (opinfo.pending_count) goto out; ret = glusterd_op_sm_inject_event (GD_OP_EVENT_ALL_ACC, NULL); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); out: return ret; } int32_t glusterd_op_send_cli_response (int32_t op, int32_t op_ret, int32_t op_errno, rpcsvc_request_t *req, void *op_ctx, char *op_errstr) { int32_t ret = -1; gd_serialize_t sfunc = NULL; void *cli_rsp = NULL; dict_t *ctx = NULL; switch (op) { case GD_MGMT_CLI_CREATE_VOLUME: { gf1_cli_create_vol_rsp rsp = {0,}; rsp.op_ret = op_ret; rsp.op_errno = op_errno; rsp.volname = ""; if (op_errstr) rsp.op_errstr = op_errstr; else rsp.op_errstr = ""; cli_rsp = &rsp; sfunc = gf_xdr_serialize_cli_create_vol_rsp; break; } case GD_MGMT_CLI_START_VOLUME: { gf1_cli_start_vol_rsp rsp = {0,}; rsp.op_ret = op_ret; rsp.op_errno = op_errno; rsp.volname = ""; if (op_errstr) rsp.op_errstr = op_errstr; else rsp.op_errstr = ""; cli_rsp = &rsp; sfunc = gf_xdr_serialize_cli_start_vol_rsp; break; } case GD_MGMT_CLI_STOP_VOLUME: { gf1_cli_stop_vol_rsp rsp = {0,}; rsp.op_ret = op_ret; rsp.op_errno = op_errno; rsp.volname = ""; cli_rsp = &rsp; sfunc = gf_xdr_serialize_cli_stop_vol_rsp; break; } case GD_MGMT_CLI_DELETE_VOLUME: { gf1_cli_delete_vol_rsp rsp = {0,}; rsp.op_ret = op_ret; rsp.op_errno = op_errno; rsp.volname = ""; cli_rsp = &rsp; sfunc = gf_xdr_serialize_cli_delete_vol_rsp; break; } case GD_MGMT_CLI_DEFRAG_VOLUME: { gf1_cli_defrag_vol_rsp rsp = {0,}; rsp.op_ret = op_ret; rsp.op_errno = op_errno; //rsp.volname = ""; cli_rsp = &rsp; sfunc = gf_xdr_serialize_cli_defrag_vol_rsp; break; } case GD_MGMT_CLI_ADD_BRICK: { gf1_cli_add_brick_rsp rsp = {0,}; rsp.op_ret = op_ret; rsp.op_errno = op_errno; rsp.volname = ""; if (op_errstr) rsp.op_errstr = op_errstr; else rsp.op_errstr = ""; cli_rsp = &rsp; sfunc = gf_xdr_serialize_cli_add_brick_rsp; break; } case GD_MGMT_CLI_REMOVE_BRICK: { gf1_cli_remove_brick_rsp rsp = {0,}; ctx = op_ctx; if (ctx && dict_get_str (ctx, "errstr", &rsp.op_errstr)) rsp.op_errstr = ""; rsp.op_ret = op_ret; rsp.op_errno = op_errno; rsp.volname = ""; cli_rsp = &rsp; sfunc = gf_xdr_serialize_cli_remove_brick_rsp; break; } case GD_MGMT_CLI_REPLACE_BRICK: { gf1_cli_replace_brick_rsp rsp = {0,}; ctx = op_ctx; if (ctx && dict_get_str (ctx, "status-reply", &rsp.status)) rsp.status = ""; rsp.op_ret = op_ret; rsp.op_errno = op_errno; if (op_errstr) rsp.op_errstr = op_errstr; else rsp.op_errstr = ""; rsp.volname = ""; cli_rsp = &rsp; sfunc = gf_xdr_serialize_cli_replace_brick_rsp; break; } case GD_MGMT_CLI_SET_VOLUME: { gf1_cli_set_vol_rsp rsp = {0,}; rsp.op_ret = op_ret; rsp.op_errno = op_errno; rsp.volname = ""; if (op_errstr) rsp.op_errstr = op_errstr; else rsp.op_errstr = ""; cli_rsp = &rsp; sfunc = gf_xdr_serialize_cli_set_vol_rsp; break; } case GD_MGMT_CLI_RESET_VOLUME: { gf_log ("", GF_LOG_DEBUG, "Return value to CLI"); gf1_cli_reset_vol_rsp rsp = {0,}; rsp.op_ret = op_ret; rsp.op_errno = 1; rsp.volname = ""; if (op_errstr) rsp.op_errstr = op_errstr; else rsp.op_errstr = "Error while resetting options"; cli_rsp = &rsp; sfunc = gf_xdr_serialize_cli_reset_vol_rsp; break; } case GD_MGMT_CLI_LOG_FILENAME: { gf1_cli_log_filename_rsp rsp = {0,}; rsp.op_ret = op_ret; rsp.op_errno = op_errno; rsp.errstr = ""; cli_rsp = &rsp; sfunc = gf_xdr_serialize_cli_log_filename_rsp; break; } case GD_MGMT_CLI_LOG_ROTATE: { gf1_cli_log_rotate_rsp rsp = {0,}; rsp.op_ret = op_ret; rsp.op_errno = op_errno; rsp.errstr = ""; cli_rsp = &rsp; sfunc = gf_xdr_serialize_cli_log_rotate_rsp; break; } case GD_MGMT_CLI_SYNC_VOLUME: { gf1_cli_sync_volume_rsp rsp = {0,}; rsp.op_ret = op_ret; rsp.op_errno = op_errno; if (op_errstr) rsp.op_errstr = op_errstr; else rsp.op_errstr = ""; cli_rsp = &rsp; sfunc = gf_xdr_from_cli_sync_volume_rsp; break; } } ret = glusterd_submit_reply (req, cli_rsp, NULL, 0, NULL, sfunc); if (ret) goto out; out: gf_log ("", GF_LOG_NORMAL, "Returning %d", ret); return ret; } int32_t glusterd_op_clear_errstr() { opinfo.op_errstr = NULL; return 0; } int32_t glusterd_op_txn_complete () { int32_t ret = -1; glusterd_conf_t *priv = NULL; int32_t op = -1; int32_t op_ret = 0; int32_t op_errno = 0; int32_t cli_op = 0; rpcsvc_request_t *req = NULL; void *ctx = NULL; gf_boolean_t ctx_free = _gf_false; char *op_errstr = NULL; priv = THIS->private; GF_ASSERT (priv); ret = glusterd_unlock (priv->uuid); if (ret) { gf_log ("glusterd", GF_LOG_CRITICAL, "Unable to clear local lock, ret: %d", ret); goto out; } gf_log ("glusterd", GF_LOG_NORMAL, "Cleared local lock"); op_ret = opinfo.op_ret; op_errno = opinfo.op_errno; cli_op = opinfo.cli_op; req = opinfo.req; if (opinfo.op_errstr) op_errstr = opinfo.op_errstr; opinfo.op_ret = 0; opinfo.op_errno = 0; op = glusterd_op_get_op (); if (op != -1) { glusterd_op_clear_pending_op (op); glusterd_op_clear_commit_op (op); glusterd_op_clear_op (op); ctx = glusterd_op_get_ctx (op); ctx_free = glusterd_op_get_ctx_free (op); glusterd_op_set_ctx (op, NULL); glusterd_op_clear_ctx_free (op); glusterd_op_clear_errstr (); } out: pthread_mutex_unlock (&opinfo.lock); ret = glusterd_op_send_cli_response (cli_op, op_ret, op_errno, req, ctx, op_errstr); if (ret) { gf_log ("", GF_LOG_ERROR, "Responding to cli failed, ret: %d", ret); //Ignore this error, else state machine blocks ret = 0; } if (ctx_free && ctx && (op != -1)) glusterd_op_free_ctx (op, ctx, ctx_free); if (op_errstr && (strcmp (op_errstr, ""))) GF_FREE (op_errstr); gf_log ("glusterd", GF_LOG_NORMAL, "Returning %d", ret); return ret; } static int glusterd_op_ac_unlocked_all (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; GF_ASSERT (event); ret = glusterd_op_txn_complete (); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int glusterd_op_ac_commit_error (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; //Log here with who failed the commit // ret = glusterd_op_sm_inject_event (GD_OP_EVENT_START_UNLOCK, NULL); return ret; } static int glusterd_op_ac_stage_op (glusterd_op_sm_event_t *event, void *ctx) { int ret = -1; gd1_mgmt_stage_op_req *req = NULL; glusterd_op_stage_ctx_t *stage_ctx = NULL; int32_t status = 0; char *op_errstr = NULL; GF_ASSERT (ctx); stage_ctx = ctx; req = &stage_ctx->stage_req; status = glusterd_op_stage_validate (req, &op_errstr); if (status) { gf_log ("", GF_LOG_ERROR, "Validate failed: %d", status); } ret = glusterd_op_stage_send_resp (stage_ctx->req, req->op, status, op_errstr); if (op_errstr && (strcmp (op_errstr, ""))) GF_FREE (op_errstr); gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); return ret; } static int glusterd_op_ac_commit_op (glusterd_op_sm_event_t *event, void *ctx) { int ret = 0; gd1_mgmt_stage_op_req *req = NULL; glusterd_op_commit_ctx_t *commit_ctx = NULL; int32_t status = 0; char *op_errstr = NULL; dict_t *rsp_dict = NULL; GF_ASSERT (ctx); commit_ctx = ctx; req = &commit_ctx->stage_req; rsp_dict = dict_new (); if (!rsp_dict) { gf_log ("", GF_LOG_DEBUG, "Out of memory"); ret = -1; goto out; } status = glusterd_op_commit_perform (req, &op_errstr, rsp_dict); if (status) { gf_log ("", GF_LOG_ERROR, "Commit failed: %d", status); } ret = glusterd_op_commit_send_resp (commit_ctx->req, req->op, status, op_errstr, rsp_dict); out: if (rsp_dict) dict_unref (rsp_dict); if (op_errstr && (strcmp (op_errstr, ""))) GF_FREE (op_errstr); gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); return ret; } static int glusterd_op_sm_transition_state (glusterd_op_info_t *opinfo, glusterd_op_sm_t *state, glusterd_op_sm_event_type_t event_type) { GF_ASSERT (state); GF_ASSERT (opinfo); gf_log ("", GF_LOG_NORMAL, "Transitioning from %d to %d due to event %d", opinfo->state.state, state[event_type].next_state, event_type); opinfo->state.state = state[event_type].next_state; return 0; } int32_t glusterd_op_stage_validate (gd1_mgmt_stage_op_req *req, char **op_errstr) { int ret = -1; GF_ASSERT (req); switch (req->op) { case GD_OP_CREATE_VOLUME: ret = glusterd_op_stage_create_volume (req, op_errstr); break; case GD_OP_START_VOLUME: ret = glusterd_op_stage_start_volume (req, op_errstr); break; case GD_OP_STOP_VOLUME: ret = glusterd_op_stage_stop_volume (req); break; case GD_OP_DELETE_VOLUME: ret = glusterd_op_stage_delete_volume (req); break; case GD_OP_ADD_BRICK: ret = glusterd_op_stage_add_brick (req, op_errstr); break; case GD_OP_REPLACE_BRICK: ret = glusterd_op_stage_replace_brick (req, op_errstr); break; case GD_OP_SET_VOLUME: ret = glusterd_op_stage_set_volume (req, op_errstr); break; case GD_OP_RESET_VOLUME: ret = glusterd_op_stage_reset_volume (req); case GD_OP_REMOVE_BRICK: ret = glusterd_op_stage_remove_brick (req); break; case GD_OP_LOG_FILENAME: ret = glusterd_op_stage_log_filename (req); break; case GD_OP_LOG_ROTATE: ret = glusterd_op_stage_log_rotate (req); break; case GD_OP_SYNC_VOLUME: ret = glusterd_op_stage_sync_volume (req, op_errstr); break; default: gf_log ("", GF_LOG_ERROR, "Unknown op %d", req->op); } gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } int32_t glusterd_op_commit_perform (gd1_mgmt_stage_op_req *req, char **op_errstr, dict_t *rsp_dict) { int ret = -1; GF_ASSERT (req); switch (req->op) { case GD_OP_CREATE_VOLUME: ret = glusterd_op_create_volume (req, op_errstr); break; case GD_OP_START_VOLUME: ret = glusterd_op_start_volume (req, op_errstr); break; case GD_OP_STOP_VOLUME: ret = glusterd_op_stop_volume (req); break; case GD_OP_DELETE_VOLUME: ret = glusterd_op_delete_volume (req); break; case GD_OP_ADD_BRICK: ret = glusterd_op_add_brick (req, op_errstr); break; case GD_OP_REPLACE_BRICK: ret = glusterd_op_replace_brick (req, rsp_dict); break; case GD_OP_SET_VOLUME: ret = glusterd_op_set_volume (req); break; case GD_OP_RESET_VOLUME: ret = glusterd_op_reset_volume (req); break; case GD_OP_REMOVE_BRICK: ret = glusterd_op_remove_brick (req); break; case GD_OP_LOG_FILENAME: ret = glusterd_op_log_filename (req); break; case GD_OP_LOG_ROTATE: ret = glusterd_op_log_rotate (req); break; case GD_OP_SYNC_VOLUME: ret = glusterd_op_sync_volume (req, op_errstr, rsp_dict); break; default: gf_log ("", GF_LOG_ERROR, "Unknown op %d", req->op); } gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } glusterd_op_sm_t glusterd_op_state_default [] = { {GD_OP_STATE_DEFAULT, glusterd_op_ac_none}, //EVENT_NONE {GD_OP_STATE_LOCK_SENT, glusterd_op_ac_send_lock},//EVENT_START_LOCK {GD_OP_STATE_LOCKED, glusterd_op_ac_lock}, //EVENT_LOCK {GD_OP_STATE_DEFAULT, glusterd_op_ac_none}, //EVENT_RCVD_ACC {GD_OP_STATE_DEFAULT, glusterd_op_ac_none}, //EVENT_ALL_ACC {GD_OP_STATE_DEFAULT, glusterd_op_ac_none}, //EVENT_STAGE_ACC {GD_OP_STATE_DEFAULT, glusterd_op_ac_none}, //EVENT_COMMIT_ACC {GD_OP_STATE_DEFAULT, glusterd_op_ac_none}, //EVENT_RCVD_RJT {GD_OP_STATE_DEFAULT, glusterd_op_ac_none}, //EVENT_STAGE_OP {GD_OP_STATE_DEFAULT, glusterd_op_ac_none}, //EVENT_COMMIT_OP {GD_OP_STATE_DEFAULT, glusterd_op_ac_unlock}, //EVENT_UNLOCK {GD_OP_STATE_DEFAULT, glusterd_op_ac_none}, //EVENT_START_UNLOCK {GD_OP_STATE_DEFAULT, glusterd_op_ac_none}, //EVENT_MAX }; glusterd_op_sm_t glusterd_op_state_lock_sent [] = { {GD_OP_STATE_LOCK_SENT, glusterd_op_ac_none}, //EVENT_NONE {GD_OP_STATE_LOCK_SENT, glusterd_op_ac_none},//EVENT_START_LOCK {GD_OP_STATE_LOCK_SENT, glusterd_op_ac_none}, //EVENT_LOCK {GD_OP_STATE_LOCK_SENT, glusterd_op_ac_rcvd_lock_acc}, //EVENT_RCVD_ACC {GD_OP_STATE_STAGE_OP_SENT, glusterd_op_ac_send_stage_op}, //EVENT_ALL_ACC {GD_OP_STATE_LOCK_SENT, glusterd_op_ac_none}, //EVENT_STAGE_ACC {GD_OP_STATE_LOCK_SENT, glusterd_op_ac_none}, //EVENT_COMMIT_ACC {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_send_unlock}, //EVENT_RCVD_RJT {GD_OP_STATE_LOCK_SENT, glusterd_op_ac_none}, //EVENT_STAGE_OP {GD_OP_STATE_LOCK_SENT, glusterd_op_ac_none}, //EVENT_COMMIT_OP {GD_OP_STATE_DEFAULT, glusterd_op_ac_unlock}, //EVENT_UNLOCK {GD_OP_STATE_LOCK_SENT, glusterd_op_ac_none}, //EVENT_START_UNLOCK {GD_OP_STATE_LOCK_SENT, glusterd_op_ac_none}, //EVENT_MAX }; glusterd_op_sm_t glusterd_op_state_locked [] = { {GD_OP_STATE_LOCKED, glusterd_op_ac_none}, //EVENT_NONE {GD_OP_STATE_LOCKED, glusterd_op_ac_none},//EVENT_START_LOCK {GD_OP_STATE_LOCKED, glusterd_op_ac_none}, //EVENT_LOCK {GD_OP_STATE_LOCKED, glusterd_op_ac_none}, //EVENT_RCVD_ACC {GD_OP_STATE_LOCKED, glusterd_op_ac_none}, //EVENT_ALL_ACC {GD_OP_STATE_LOCKED, glusterd_op_ac_none}, //EVENT_STAGE_ACC {GD_OP_STATE_LOCKED, glusterd_op_ac_none}, //EVENT_COMMIT_ACC {GD_OP_STATE_LOCKED, glusterd_op_ac_none}, //EVENT_RCVD_RJT {GD_OP_STATE_STAGED, glusterd_op_ac_stage_op}, //EVENT_STAGE_OP {GD_OP_STATE_LOCKED, glusterd_op_ac_none}, //EVENT_COMMIT_OP {GD_OP_STATE_DEFAULT, glusterd_op_ac_unlock}, //EVENT_UNLOCK {GD_OP_STATE_LOCKED, glusterd_op_ac_none}, //EVENT_START_UNLOCK {GD_OP_STATE_LOCKED, glusterd_op_ac_none}, //EVENT_MAX }; glusterd_op_sm_t glusterd_op_state_stage_op_sent [] = { {GD_OP_STATE_STAGE_OP_SENT, glusterd_op_ac_none}, //EVENT_NONE {GD_OP_STATE_STAGE_OP_SENT, glusterd_op_ac_none},//EVENT_START_LOCK {GD_OP_STATE_STAGE_OP_SENT, glusterd_op_ac_none}, //EVENT_LOCK {GD_OP_STATE_STAGE_OP_SENT, glusterd_op_ac_rcvd_stage_op_acc}, //EVENT_RCVD_ACC {GD_OP_STATE_STAGE_OP_SENT, glusterd_op_ac_send_stage_op}, //EVENT_ALL_ACC {GD_OP_STATE_COMMIT_OP_SENT, glusterd_op_ac_send_commit_op}, //EVENT_STAGE_ACC {GD_OP_STATE_STAGE_OP_SENT, glusterd_op_ac_none}, //EVENT_COMMIT_ACC {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_send_unlock}, //EVENT_RCVD_RJT {GD_OP_STATE_STAGE_OP_SENT, glusterd_op_ac_none}, //EVENT_STAGE_OP {GD_OP_STATE_STAGE_OP_SENT, glusterd_op_ac_none}, //EVENT_COMMIT_OP {GD_OP_STATE_STAGE_OP_SENT, glusterd_op_ac_unlock}, //EVENT_UNLOCK {GD_OP_STATE_STAGE_OP_SENT, glusterd_op_ac_none}, //EVENT_START_UNLOCK {GD_OP_STATE_STAGE_OP_SENT, glusterd_op_ac_none}, //EVENT_MAX }; glusterd_op_sm_t glusterd_op_state_staged [] = { {GD_OP_STATE_STAGED, glusterd_op_ac_none}, //EVENT_NONE {GD_OP_STATE_STAGED, glusterd_op_ac_none},//EVENT_START_LOCK {GD_OP_STATE_STAGED, glusterd_op_ac_none}, //EVENT_LOCK {GD_OP_STATE_STAGED, glusterd_op_ac_none}, //EVENT_RCVD_ACC {GD_OP_STATE_STAGED, glusterd_op_ac_none}, //EVENT_ALL_ACC {GD_OP_STATE_STAGED, glusterd_op_ac_none}, //EVENT_STAGE_ACC {GD_OP_STATE_STAGED, glusterd_op_ac_none}, //EVENT_COMMIT_ACC {GD_OP_STATE_STAGED, glusterd_op_ac_none}, //EVENT_RCVD_RJT {GD_OP_STATE_STAGED, glusterd_op_ac_none}, //EVENT_STAGE_OP {GD_OP_STATE_COMMITED, glusterd_op_ac_commit_op}, //EVENT_COMMIT_OP {GD_OP_STATE_DEFAULT, glusterd_op_ac_unlock}, //EVENT_UNLOCK {GD_OP_STATE_STAGED, glusterd_op_ac_none}, //EVENT_START_UNLOCK {GD_OP_STATE_STAGED, glusterd_op_ac_none}, //EVENT_MAX }; glusterd_op_sm_t glusterd_op_state_commit_op_sent [] = { {GD_OP_STATE_COMMIT_OP_SENT, glusterd_op_ac_none}, //EVENT_NONE {GD_OP_STATE_COMMIT_OP_SENT, glusterd_op_ac_none},//EVENT_START_LOCK {GD_OP_STATE_COMMIT_OP_SENT, glusterd_op_ac_none}, //EVENT_LOCK {GD_OP_STATE_COMMIT_OP_SENT, glusterd_op_ac_rcvd_commit_op_acc}, //EVENT_RCVD_ACC {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_send_unlock}, //EVENT_ALL_ACC {GD_OP_STATE_COMMIT_OP_SENT, glusterd_op_ac_none}, //EVENT_STAGE_ACC {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_send_unlock}, //EVENT_COMMIT_ACC {GD_OP_STATE_COMMIT_OP_SENT, glusterd_op_ac_commit_error}, //EVENT_RCVD_RJT {GD_OP_STATE_COMMIT_OP_SENT, glusterd_op_ac_none}, //EVENT_STAGE_OP {GD_OP_STATE_COMMIT_OP_SENT, glusterd_op_ac_none}, //EVENT_COMMIT_OP {GD_OP_STATE_COMMIT_OP_SENT, glusterd_op_ac_unlock}, //EVENT_UNLOCK {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_send_unlock}, //EVENT_START_UNLOCK {GD_OP_STATE_COMMIT_OP_SENT, glusterd_op_ac_none}, //EVENT_MAX }; glusterd_op_sm_t glusterd_op_state_commited [] = { {GD_OP_STATE_COMMITED, glusterd_op_ac_none}, //EVENT_NONE {GD_OP_STATE_COMMITED, glusterd_op_ac_none},//EVENT_START_LOCK {GD_OP_STATE_COMMITED, glusterd_op_ac_none}, //EVENT_LOCK {GD_OP_STATE_COMMITED, glusterd_op_ac_none}, //EVENT_RCVD_ACC {GD_OP_STATE_COMMITED, glusterd_op_ac_none}, //EVENT_ALL_ACC {GD_OP_STATE_COMMITED, glusterd_op_ac_none}, //EVENT_STAGE_ACC {GD_OP_STATE_COMMITED, glusterd_op_ac_none}, //EVENT_COMMIT_ACC {GD_OP_STATE_COMMITED, glusterd_op_ac_none}, //EVENT_RCVD_RJT {GD_OP_STATE_COMMITED, glusterd_op_ac_none}, //EVENT_STAGE_OP {GD_OP_STATE_COMMITED, glusterd_op_ac_none}, //EVENT_COMMIT_OP {GD_OP_STATE_DEFAULT, glusterd_op_ac_unlock}, //EVENT_UNLOCK {GD_OP_STATE_COMMITED, glusterd_op_ac_none}, //EVENT_START_UNLOCK {GD_OP_STATE_COMMITED, glusterd_op_ac_none}, //EVENT_MAX }; glusterd_op_sm_t glusterd_op_state_unlock_sent [] = { {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_none}, //EVENT_NONE {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_none},//EVENT_START_LOCK {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_none}, //EVENT_LOCK {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_rcvd_unlock_acc}, //EVENT_RCVD_ACC {GD_OP_STATE_DEFAULT, glusterd_op_ac_unlocked_all}, //EVENT_ALL_ACC {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_none}, //EVENT_STAGE_ACC {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_none}, //EVENT_COMMIT_ACC {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_none}, //EVENT_RCVD_RJT {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_none}, //EVENT_STAGE_OP {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_none}, //EVENT_COMMIT_OP {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_unlock}, //EVENT_UNLOCK {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_none}, //EVENT_START_UNLOCK {GD_OP_STATE_UNLOCK_SENT, glusterd_op_ac_none}, //EVENT_MAX }; glusterd_op_sm_t *glusterd_op_state_table [] = { glusterd_op_state_default, glusterd_op_state_lock_sent, glusterd_op_state_locked, glusterd_op_state_stage_op_sent, glusterd_op_state_staged, glusterd_op_state_commit_op_sent, glusterd_op_state_commited, glusterd_op_state_unlock_sent }; int glusterd_op_sm_new_event (glusterd_op_sm_event_type_t event_type, glusterd_op_sm_event_t **new_event) { glusterd_op_sm_event_t *event = NULL; GF_ASSERT (new_event); GF_ASSERT (GD_OP_EVENT_NONE <= event_type && GD_OP_EVENT_MAX > event_type); event = GF_CALLOC (1, sizeof (*event), gf_gld_mt_op_sm_event_t); if (!event) return -1; *new_event = event; event->event = event_type; INIT_LIST_HEAD (&event->list); return 0; } int glusterd_op_sm_inject_event (glusterd_op_sm_event_type_t event_type, void *ctx) { int32_t ret = -1; glusterd_op_sm_event_t *event = NULL; GF_ASSERT (event_type < GD_OP_EVENT_MAX && event_type >= GD_OP_EVENT_NONE); ret = glusterd_op_sm_new_event (event_type, &event); if (ret) goto out; event->ctx = ctx; gf_log ("glusterd", GF_LOG_NORMAL, "Enqueuing event: %d", event->event); list_add_tail (&event->list, &gd_op_sm_queue); out: return ret; } void glusterd_destroy_op_event_ctx (glusterd_op_sm_event_t *event) { if (!event) return; switch (event->event) { case GD_OP_EVENT_LOCK: case GD_OP_EVENT_UNLOCK: glusterd_destroy_lock_ctx (event->ctx); break; case GD_OP_EVENT_STAGE_OP: glusterd_destroy_stage_ctx (event->ctx); break; case GD_OP_EVENT_COMMIT_OP: glusterd_destroy_commit_ctx (event->ctx); break; default: break; } } int glusterd_op_sm () { glusterd_op_sm_event_t *event = NULL; glusterd_op_sm_event_t *tmp = NULL; int ret = -1; 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; (void ) pthread_mutex_lock (&gd_op_sm_lock); while (!list_empty (&gd_op_sm_queue)) { list_for_each_entry_safe (event, tmp, &gd_op_sm_queue, list) { list_del_init (&event->list); event_type = event->event; gf_log ("", GF_LOG_DEBUG, "Dequeued event of type: %d", event_type); state = glusterd_op_state_table[opinfo.state.state]; GF_ASSERT (state); handler = state[event_type].handler; GF_ASSERT (handler); ret = handler (event, event->ctx); if (ret) { gf_log ("glusterd", GF_LOG_ERROR, "handler returned: %d", ret); glusterd_destroy_op_event_ctx (event); GF_FREE (event); continue; } ret = glusterd_op_sm_transition_state (&opinfo, state, event_type); if (ret) { gf_log ("glusterd", GF_LOG_ERROR, "Unable to transition" "state from %d to %d", opinfo.state.state, state[event_type].next_state); (void ) pthread_mutex_unlock (&gd_op_sm_lock); return ret; } glusterd_destroy_op_event_ctx (event); GF_FREE (event); } } (void ) pthread_mutex_unlock (&gd_op_sm_lock); ret = 0; return ret; } int32_t glusterd_op_set_op (glusterd_op_t op) { GF_ASSERT (op < GD_OP_MAX); GF_ASSERT (op > GD_OP_NONE); opinfo.op[op] = 1; opinfo.pending_op[op] = 1; opinfo.commit_op[op] = 1; return 0; } int32_t glusterd_op_get_op () { int i = 0; int32_t ret = 0; for ( i = 0; i < GD_OP_MAX; i++) { if (opinfo.op[i]) break; } if ( i == GD_OP_MAX) ret = -1; else ret = i; return ret; } int32_t glusterd_op_set_cli_op (gf_mgmt_procnum op) { int32_t ret; ret = pthread_mutex_trylock (&opinfo.lock); if (ret) goto out; opinfo.cli_op = op; out: gf_log ("", GF_LOG_NORMAL, "Returning %d", ret); return ret; } int32_t glusterd_op_set_req (rpcsvc_request_t *req) { GF_ASSERT (req); opinfo.req = req; return 0; } int32_t glusterd_op_clear_pending_op (glusterd_op_t op) { GF_ASSERT (op < GD_OP_MAX); GF_ASSERT (op > GD_OP_NONE); opinfo.pending_op[op] = 0; return 0; } int32_t glusterd_op_clear_commit_op (glusterd_op_t op) { GF_ASSERT (op < GD_OP_MAX); GF_ASSERT (op > GD_OP_NONE); opinfo.commit_op[op] = 0; return 0; } int32_t glusterd_op_clear_op (glusterd_op_t op) { GF_ASSERT (op < GD_OP_MAX); GF_ASSERT (op > GD_OP_NONE); opinfo.op[op] = 0; return 0; } int32_t glusterd_op_set_ctx (glusterd_op_t op, void *ctx) { GF_ASSERT (op < GD_OP_MAX); GF_ASSERT (op > GD_OP_NONE); opinfo.op_ctx[op] = ctx; return 0; } int32_t glusterd_op_free_ctx (glusterd_op_t op, void *ctx, gf_boolean_t ctx_free) { GF_ASSERT (op < GD_OP_MAX); GF_ASSERT (op > GD_OP_NONE); if (ctx && ctx_free) { switch (op) { case GD_OP_CREATE_VOLUME: case GD_OP_STOP_VOLUME: case GD_OP_ADD_BRICK: case GD_OP_REMOVE_BRICK: case GD_OP_REPLACE_BRICK: case GD_OP_LOG_FILENAME: case GD_OP_LOG_ROTATE: case GD_OP_SYNC_VOLUME: case GD_OP_SET_VOLUME: case GD_OP_START_VOLUME: dict_unref (ctx); break; case GD_OP_DELETE_VOLUME: GF_FREE (ctx); break; default: break; } } return 0; } void * glusterd_op_get_ctx (glusterd_op_t op) { GF_ASSERT (op < GD_OP_MAX); GF_ASSERT (op > GD_OP_NONE); return opinfo.op_ctx[op]; } int32_t glusterd_op_set_ctx_free (glusterd_op_t op, gf_boolean_t ctx_free) { GF_ASSERT (op < GD_OP_MAX); GF_ASSERT (op > GD_OP_NONE); opinfo.ctx_free[op] = ctx_free; return 0; } int32_t glusterd_op_clear_ctx_free (glusterd_op_t op) { GF_ASSERT (op < GD_OP_MAX); GF_ASSERT (op > GD_OP_NONE); opinfo.ctx_free[op] = _gf_false; return 0; } gf_boolean_t glusterd_op_get_ctx_free (glusterd_op_t op) { GF_ASSERT (op < GD_OP_MAX); GF_ASSERT (op > GD_OP_NONE); return opinfo.ctx_free[op]; } int glusterd_op_sm_init () { INIT_LIST_HEAD (&gd_op_sm_queue); pthread_mutex_init (&gd_op_sm_lock, NULL); return 0; } int32_t glusterd_opinfo_unlock(){ return (pthread_mutex_unlock(&opinfo.lock)); }