diff options
Diffstat (limited to 'xlators/mgmt/glusterd/src/glusterd-store.c')
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-store.c | 6333 |
1 files changed, 4522 insertions, 1811 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-store.c b/xlators/mgmt/glusterd/src/glusterd-store.c index 823fb37cd71..d94dceb10b7 100644 --- a/xlators/mgmt/glusterd/src/glusterd-store.c +++ b/xlators/mgmt/glusterd/src/glusterd-store.c @@ -1,2414 +1,5125 @@ /* - Copyright (c) 2007-2011 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + Copyright (c) 2007-2013 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif #include "glusterd-op-sm.h" #include <inttypes.h> - -#include "globals.h" -#include "glusterfs.h" -#include "compat.h" -#include "dict.h" +#include <glusterfs/glusterfs.h> +#include <glusterfs/compat.h> +#include <glusterfs/dict.h> #include "protocol-common.h" -#include "xlator.h" -#include "logging.h" -#include "timer.h" -#include "defaults.h" -#include "compat.h" -#include "compat-errno.h" -#include "statedump.h" +#include <glusterfs/xlator.h> +#include <glusterfs/logging.h> +#include <glusterfs/timer.h> +#include <glusterfs/syscall.h> +#include <glusterfs/defaults.h> +#include <glusterfs/compat.h> +#include <glusterfs/compat-errno.h> +#include <glusterfs/statedump.h> #include "glusterd-mem-types.h" #include "glusterd.h" #include "glusterd-sm.h" #include "glusterd-op-sm.h" #include "glusterd-utils.h" +#include "glusterd-hooks.h" +#include <glusterfs/store.h> #include "glusterd-store.h" +#include "glusterd-snapshot-utils.h" +#include "glusterd-messages.h" #include "rpc-clnt.h" -#include "common-utils.h" +#include <glusterfs/common-utils.h> +#include <glusterfs/quota-common-utils.h> #include <sys/resource.h> #include <inttypes.h> #include <dirent.h> -static int32_t -glusterd_store_mkdir (char *path) -{ - int32_t ret = -1; - - ret = mkdir (path, 0777); - - if ((-1 == ret) && (EEXIST != errno)) { - gf_log ("", GF_LOG_ERROR, "mkdir() failed on path %s," - "errno: %s", path, strerror (errno)); - } else { - ret = 0; - } +#if defined(GF_LINUX_HOST_OS) +#include <mntent.h> +#else +#include "mntent_compat.h" +#endif - return ret; -} +#define GLUSTERD_GET_BRICK_DIR(path, volinfo, priv) \ + do { \ + int32_t _brick_len; \ + if (volinfo->is_snap_volume) { \ + _brick_len = snprintf(path, PATH_MAX, "%s/snaps/%s/%s/%s", \ + priv->workdir, volinfo->snapshot->snapname, \ + volinfo->volname, GLUSTERD_BRICK_INFO_DIR); \ + } else { \ + _brick_len = snprintf(path, PATH_MAX, "%s/%s/%s/%s", \ + priv->workdir, GLUSTERD_VOLUME_DIR_PREFIX, \ + volinfo->volname, GLUSTERD_BRICK_INFO_DIR); \ + } \ + if ((_brick_len < 0) || (_brick_len >= PATH_MAX)) { \ + path[0] = 0; \ + } \ + } while (0) -int32_t -glusterd_store_handle_create_on_absence (glusterd_store_handle_t **shandle, - char *path) +void +glusterd_replace_slash_with_hyphen(char *str) { - GF_ASSERT (shandle); - int32_t ret = 0; + char *ptr = NULL; - if (*shandle == NULL) { - ret = glusterd_store_handle_new (path, shandle); + ptr = strchr(str, '/'); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to create store" - " handle for path: %s", path); - } - } - return ret; + while (ptr) { + *ptr = '-'; + ptr = strchr(ptr, '/'); + } } int32_t -glusterd_store_mkstemp (glusterd_store_handle_t *shandle) +glusterd_store_create_brick_dir(glusterd_volinfo_t *volinfo) { - int fd = -1; - char tmppath[PATH_MAX] = {0,}; + int32_t ret = -1; + char brickdirpath[PATH_MAX] = { + 0, + }; + glusterd_conf_t *priv = NULL; - GF_ASSERT (shandle); - GF_ASSERT (shandle->path); + GF_ASSERT(volinfo); - snprintf (tmppath, sizeof (tmppath), "%s.tmp", shandle->path); - fd = open (tmppath, O_RDWR | O_CREAT | O_TRUNC, 0644); - if (fd <= 0) { - gf_log ("glusterd", GF_LOG_ERROR, "Failed to open %s, " - "error: %s", tmppath, strerror (errno)); - } - - return fd; -} + priv = THIS->private; + GF_ASSERT(priv); -int32_t -glusterd_store_rename_tmppath (glusterd_store_handle_t *shandle) -{ - int32_t ret = -1; - char tmppath[PATH_MAX] = {0,}; - - GF_ASSERT (shandle); - GF_ASSERT (shandle->path); - - snprintf (tmppath, sizeof (tmppath), "%s.tmp", shandle->path); - ret = rename (tmppath, shandle->path); - if (ret) { - gf_log ("glusterd", GF_LOG_ERROR, "Failed to mv %s to %s, " - "error: %s", tmppath, shandle->path, strerror (errno)); - } + GLUSTERD_GET_BRICK_DIR(brickdirpath, volinfo, priv); + ret = gf_store_mkdir(brickdirpath); - return ret; -} - -int32_t -glusterd_store_unlink_tmppath (glusterd_store_handle_t *shandle) -{ - int32_t ret = -1; - char tmppath[PATH_MAX] = {0,}; - - GF_ASSERT (shandle); - GF_ASSERT (shandle->path); - - snprintf (tmppath, sizeof (tmppath), "%s.tmp", shandle->path); - ret = unlink (tmppath); - if (ret && (errno != ENOENT)) { - gf_log ("glusterd", GF_LOG_ERROR, "Failed to mv %s to %s, " - "error: %s", tmppath, shandle->path, strerror (errno)); - } else { - ret = 0; - } - - return ret; + return ret; } static void -glusterd_replace_slash_with_hipen (char *str) +glusterd_store_key_vol_brick_set(glusterd_brickinfo_t *brickinfo, + char *key_vol_brick, size_t len) { - char *ptr = NULL; + GF_ASSERT(brickinfo); + GF_ASSERT(key_vol_brick); + GF_ASSERT(len >= PATH_MAX); - ptr = strchr (str, '/'); - - while (ptr) { - *ptr = '-'; - ptr = strchr (str, '/'); - } + snprintf(key_vol_brick, len, "%s", brickinfo->path); + glusterd_replace_slash_with_hyphen(key_vol_brick); } -int32_t -glusterd_store_create_brick_dir (glusterd_volinfo_t *volinfo) +static void +glusterd_store_brickinfofname_set(glusterd_brickinfo_t *brickinfo, + char *brickfname, size_t len) { - int32_t ret = -1; - char brickdirpath[PATH_MAX] = {0,}; - glusterd_conf_t *priv = NULL; - - GF_ASSERT (volinfo); - - priv = THIS->private; - GF_ASSERT (priv); + char key_vol_brick[PATH_MAX] = {0}; - GLUSTERD_GET_BRICK_DIR (brickdirpath, volinfo, priv); - ret = glusterd_store_mkdir (brickdirpath); + GF_ASSERT(brickfname); + GF_ASSERT(brickinfo); + GF_ASSERT(len >= PATH_MAX); - return ret; + glusterd_store_key_vol_brick_set(brickinfo, key_vol_brick, + sizeof(key_vol_brick)); + snprintf(brickfname, len, "%s:%s", brickinfo->hostname, key_vol_brick); } static void -glusterd_store_key_vol_brick_set (glusterd_brickinfo_t *brickinfo, - char *key_vol_brick, size_t len) +glusterd_store_brickinfopath_set(glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo, + char *brickpath, size_t len) { - GF_ASSERT (brickinfo); - GF_ASSERT (key_vol_brick); - GF_ASSERT (len >= PATH_MAX); - - snprintf (key_vol_brick, len, "%s", brickinfo->path); - glusterd_replace_slash_with_hipen (key_vol_brick); + char brickfname[PATH_MAX] = {0}; + char brickdirpath[PATH_MAX] = { + 0, + }; + glusterd_conf_t *priv = NULL; + + GF_ASSERT(brickpath); + GF_ASSERT(brickinfo); + GF_ASSERT(len >= PATH_MAX); + + priv = THIS->private; + GF_ASSERT(priv); + + GLUSTERD_GET_BRICK_DIR(brickdirpath, volinfo, priv); + glusterd_store_brickinfofname_set(brickinfo, brickfname, + sizeof(brickfname)); + snprintf(brickpath, len, "%s/%s", brickdirpath, brickfname); } static void -glusterd_store_brickinfofname_set (glusterd_brickinfo_t *brickinfo, - char *brickfname, size_t len) +glusterd_store_snapd_path_set(glusterd_volinfo_t *volinfo, char *snapd_path, + size_t len) { - char key_vol_brick[PATH_MAX] = {0}; - - GF_ASSERT (brickfname); - GF_ASSERT (brickinfo); - GF_ASSERT (len >= PATH_MAX); - - glusterd_store_key_vol_brick_set (brickinfo, key_vol_brick, - sizeof (key_vol_brick)); - snprintf (brickfname, len, "%s:%s", brickinfo->hostname, key_vol_brick); -} + char volpath[PATH_MAX] = { + 0, + }; + glusterd_conf_t *priv = NULL; -static void -glusterd_store_brickinfopath_set (glusterd_volinfo_t *volinfo, - glusterd_brickinfo_t *brickinfo, - char *brickpath, size_t len) -{ - char brickfname[PATH_MAX] = {0}; - char brickdirpath[PATH_MAX] = {0,}; - glusterd_conf_t *priv = NULL; + GF_ASSERT(volinfo); + GF_ASSERT(len >= PATH_MAX); - GF_ASSERT (brickpath); - GF_ASSERT (brickinfo); - GF_ASSERT (len >= PATH_MAX); + priv = THIS->private; + GF_ASSERT(priv); - priv = THIS->private; - GF_ASSERT (priv); + GLUSTERD_GET_VOLUME_DIR(volpath, volinfo, priv); - GLUSTERD_GET_BRICK_DIR (brickdirpath, volinfo, priv); - glusterd_store_brickinfofname_set (brickinfo, brickfname, - sizeof (brickfname)); - snprintf (brickpath, len, "%s/%s", brickdirpath, brickfname); + snprintf(snapd_path, len, "%s/snapd.info", volpath); } gf_boolean_t -glusterd_store_is_valid_brickpath (char *volname, char *brick) +glusterd_store_is_valid_brickpath(char *volname, char *brick) { - char brickpath[PATH_MAX] = {0}; - glusterd_brickinfo_t *brickinfo = NULL; - glusterd_volinfo_t *volinfo = NULL; - int32_t ret = 0; - - ret = glusterd_brickinfo_from_brick (brick, &brickinfo); - if (ret) { - gf_log ("", GF_LOG_WARNING, "brick path validation failed"); - ret = 0; - goto out; + glusterd_brickinfo_t *brickinfo = NULL; + glusterd_volinfo_t *volinfo = NULL; + int32_t ret = 0; + size_t volname_len = strlen(volname); + xlator_t *this = NULL; + int bpath_len = 0; + const char delim[2] = "/"; + char *sub_dir = NULL; + char *saveptr = NULL; + char *brickpath_ptr = NULL; + + this = THIS; + GF_ASSERT(this); + + ret = glusterd_brickinfo_new_from_brick(brick, &brickinfo, _gf_false, NULL); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_BRICK_CREATION_FAIL, + "Failed to create brick " + "info for brick %s", + brick); + ret = 0; + goto out; + } + ret = glusterd_volinfo_new(&volinfo); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_VOLFILE_CREATE_FAIL, + "Failed to create volinfo"); + ret = 0; + goto out; + } + if (volname_len >= sizeof(volinfo->volname)) { + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_NAME_TOO_LONG, + "volume name too long"); + ret = 0; + goto out; + } + memcpy(volinfo->volname, volname, volname_len + 1); + + /* Check whether brickpath is less than PATH_MAX */ + ret = 1; + bpath_len = strlen(brickinfo->path); + + if (brickinfo->path[bpath_len - 1] != '/') { + if (bpath_len >= PATH_MAX) { + ret = 0; + goto out; } - ret = glusterd_volinfo_new (&volinfo); - if (ret) { - gf_log ("", GF_LOG_WARNING, "brick path validation failed"); - ret = 0; - goto out; + } else { + /* Path has a trailing "/" which should not be considered in + * length check validation + */ + if (bpath_len >= PATH_MAX + 1) { + ret = 0; + goto out; } - strncpy (volinfo->volname, volname, sizeof (volinfo->volname)); - glusterd_store_brickinfopath_set (volinfo, brickinfo, brickpath, - sizeof (brickpath)); + } - ret = (strlen (brickpath) < _POSIX_PATH_MAX); + /* The following validation checks whether each sub directories in the + * brick path meets the POSIX max length validation + */ + + brickpath_ptr = brickinfo->path; + sub_dir = strtok_r(brickpath_ptr, delim, &saveptr); + + while (sub_dir != NULL) { + if (strlen(sub_dir) >= _POSIX_PATH_MAX) { + ret = 0; + goto out; + } + sub_dir = strtok_r(NULL, delim, &saveptr); + } out: - if (brickinfo) - glusterd_brickinfo_delete (brickinfo); - if (volinfo) - glusterd_volinfo_delete (volinfo); + if (brickinfo) + glusterd_brickinfo_delete(brickinfo); + if (volinfo) + glusterd_volinfo_unref(volinfo); - return ret; + return ret; } int32_t -glusterd_store_volinfo_brick_fname_write (int vol_fd, +glusterd_store_volinfo_brick_fname_write(int vol_fd, glusterd_brickinfo_t *brickinfo, - int32_t brick_count) + int32_t brick_count, + int is_thin_arbiter) { - char key[PATH_MAX] = {0,}; - char brickfname[PATH_MAX] = {0,}; - int32_t ret = -1; - - snprintf (key, sizeof (key), "%s-%d", GLUSTERD_STORE_KEY_VOL_BRICK, - brick_count); - glusterd_store_brickinfofname_set (brickinfo, brickfname, - sizeof (brickfname)); - ret = glusterd_store_save_value (vol_fd, key, brickfname); - return ret; + char key[64] = { + 0, + }; + char brickfname[PATH_MAX] = { + 0, + }; + int32_t ret = -1; + + if (!is_thin_arbiter) { + snprintf(key, sizeof(key), "%s-%d", GLUSTERD_STORE_KEY_VOL_BRICK, + brick_count); + } else { + snprintf(key, sizeof(key), "%s-%d", GLUSTERD_STORE_KEY_VOL_TA_BRICK, + brick_count); + } + glusterd_store_brickinfofname_set(brickinfo, brickfname, + sizeof(brickfname)); + ret = gf_store_save_value(vol_fd, key, brickfname); + return ret; } int32_t -glusterd_store_create_brick_shandle_on_absence (glusterd_volinfo_t *volinfo, - glusterd_brickinfo_t *brickinfo) +glusterd_store_create_brick_shandle_on_absence(glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo) { - char brickpath[PATH_MAX] = {0,}; - int32_t ret = 0; - - GF_ASSERT (volinfo); - GF_ASSERT (brickinfo); - - glusterd_store_brickinfopath_set (volinfo, brickinfo, brickpath, - sizeof (brickpath)); - ret = glusterd_store_handle_create_on_absence (&brickinfo->shandle, - brickpath); - return ret; + char brickpath[PATH_MAX] = { + 0, + }; + int32_t ret = 0; + + GF_ASSERT(volinfo); + GF_ASSERT(brickinfo); + + glusterd_store_brickinfopath_set(volinfo, brickinfo, brickpath, + sizeof(brickpath)); + ret = gf_store_handle_create_on_absence(&brickinfo->shandle, brickpath); + return ret; } int32_t -glusterd_store_brickinfo_write (int fd, glusterd_brickinfo_t *brickinfo) +glusterd_store_create_snapd_shandle_on_absence(glusterd_volinfo_t *volinfo) { - char value[256] = {0,}; - int32_t ret = 0; + char snapd_path[PATH_MAX] = { + 0, + }; + int32_t ret = 0; - GF_ASSERT (brickinfo); - GF_ASSERT (fd > 0); + GF_ASSERT(volinfo); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_BRICK_HOSTNAME, - brickinfo->hostname); - if (ret) - goto out; + glusterd_store_snapd_path_set(volinfo, snapd_path, sizeof(snapd_path)); + ret = gf_store_handle_create_on_absence(&volinfo->snapd.handle, snapd_path); + return ret; +} - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_BRICK_PATH, - brickinfo->path); - if (ret) - goto out; +/* Store the bricks snapshot details only if required + * + * The snapshot details will be stored only if the cluster op-version is + * greater than or equal to 4 + */ +static int +gd_store_brick_snap_details_write(int fd, glusterd_brickinfo_t *brickinfo) +{ + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + char value[5 * PATH_MAX]; + uint total_len = 0; - snprintf (value, sizeof(value), "%d", brickinfo->port); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_BRICK_PORT, - value); + this = THIS; + GF_ASSERT(this != NULL); + conf = this->private; + GF_VALIDATE_OR_GOTO(this->name, (conf != NULL), out); - snprintf (value, sizeof(value), "%d", brickinfo->rdma_port); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_BRICK_RDMA_PORT, - value); + GF_VALIDATE_OR_GOTO(this->name, (fd > 0), out); + GF_VALIDATE_OR_GOTO(this->name, (brickinfo != NULL), out); - snprintf (value, sizeof(value), "%d", brickinfo->decommissioned); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_BRICK_DECOMMISSIONED, - value); + if (conf->op_version < GD_OP_VERSION_3_6_0) { + ret = 0; + goto out; + } + + if (brickinfo->device_path[0] != '\0') { + ret = snprintf(value + total_len, sizeof(value) - total_len, "%s=%s\n", + GLUSTERD_STORE_KEY_BRICK_DEVICE_PATH, + brickinfo->device_path); + if (ret < 0 || ret >= sizeof(value) - total_len) { + ret = -1; + goto err; + } + total_len += ret; + } + + if (brickinfo->mount_dir[0] != '\0') { + ret = snprintf(value + total_len, sizeof(value) - total_len, "%s=%s\n", + GLUSTERD_STORE_KEY_BRICK_MOUNT_DIR, + brickinfo->mount_dir); + if (ret < 0 || ret >= sizeof(value) - total_len) { + ret = -1; + goto err; + } + total_len += ret; + } + + if (brickinfo->fstype[0] != '\0') { + ret = snprintf(value + total_len, sizeof(value) - total_len, "%s=%s\n", + GLUSTERD_STORE_KEY_BRICK_FSTYPE, brickinfo->fstype); + if (ret < 0 || ret >= sizeof(value) - total_len) { + ret = -1; + goto err; + } + total_len += ret; + } + + if (brickinfo->mnt_opts[0] != '\0') { + ret = snprintf(value + total_len, sizeof(value) - total_len, "%s=%s\n", + GLUSTERD_STORE_KEY_BRICK_MNTOPTS, brickinfo->mnt_opts); + if (ret < 0 || ret >= sizeof(value) - total_len) { + ret = -1; + goto err; + } + total_len += ret; + } + + ret = snprintf(value + total_len, sizeof(value) - total_len, "%s=%d\n", + GLUSTERD_STORE_KEY_BRICK_SNAP_STATUS, + brickinfo->snap_status); + if (ret < 0 || ret >= sizeof(value) - total_len) { + ret = -1; + goto err; + } + total_len += ret; + + ret = snprintf(value + total_len, sizeof(value) - total_len, + "%s=%" PRIu64 "\n", GLUSTERD_STORE_KEY_BRICK_FSID, + brickinfo->statfs_fsid); + if (ret < 0 || ret >= sizeof(value) - total_len) { + ret = -1; + goto err; + } + + ret = gf_store_save_items(fd, value); +err: + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_FS_LABEL_UPDATE_FAIL, + "Failed to save " + "snap detils of brick %s", + brickinfo->path); + } +out: + return ret; +} +static int32_t +glusterd_store_brickinfo_write(int fd, glusterd_brickinfo_t *brickinfo) +{ + char value[5 * PATH_MAX]; + int32_t ret = -1; + + GF_ASSERT(brickinfo); + GF_ASSERT(fd > 0); + + ret = snprintf(value, sizeof(value), + "%s=%s\n%s=%s\n%s=%s\n%s=%s\n%s=%d\n%s=%d\n%s=%d\n%s=%s\n", + GLUSTERD_STORE_KEY_BRICK_UUID, uuid_utoa(brickinfo->uuid), + GLUSTERD_STORE_KEY_BRICK_HOSTNAME, brickinfo->hostname, + GLUSTERD_STORE_KEY_BRICK_PATH, brickinfo->path, + GLUSTERD_STORE_KEY_BRICK_REAL_PATH, brickinfo->path, + GLUSTERD_STORE_KEY_BRICK_PORT, brickinfo->port, + GLUSTERD_STORE_KEY_BRICK_RDMA_PORT, brickinfo->rdma_port, + GLUSTERD_STORE_KEY_BRICK_DECOMMISSIONED, + brickinfo->decommissioned, GLUSTERD_STORE_KEY_BRICK_ID, + brickinfo->brick_id); + + if (ret < 0 || ret >= sizeof(value)) { + ret = -1; + goto out; + } + + ret = gf_store_save_items(fd, value); + if (ret) + goto out; + + ret = gd_store_brick_snap_details_write(fd, brickinfo); + if (ret) + goto out; + + if (!brickinfo->vg[0]) + goto out; + + ret = gf_store_save_value(fd, GLUSTERD_STORE_KEY_BRICK_VGNAME, + brickinfo->vg); out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; + gf_msg_debug(THIS->name, 0, "Returning %d", ret); + return ret; } int32_t -glusterd_store_perform_brick_store (glusterd_brickinfo_t *brickinfo) +glusterd_store_snapd_write(int fd, glusterd_volinfo_t *volinfo) { - int fd = -1; - int32_t ret = -1; - GF_ASSERT (brickinfo); - - fd = glusterd_store_mkstemp (brickinfo->shandle); - if (fd <= 0) { - ret = -1; - goto out; - } + char value[64] = { + 0, + }; + int32_t ret = 0; + xlator_t *this = NULL; + + GF_ASSERT(volinfo); + GF_ASSERT(fd > 0); + + this = THIS; + GF_ASSERT(this); + + snprintf(value, sizeof(value), "%d", volinfo->snapd.port); + ret = gf_store_save_value(fd, GLUSTERD_STORE_KEY_SNAPD_PORT, value); + if (ret) + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPD_PORT_STORE_FAIL, + "failed to store the snapd " + "port of volume %s", + volinfo->volname); + + gf_msg_debug(this->name, 0, "Returning %d", ret); + return ret; +} - ret = glusterd_store_brickinfo_write (fd, brickinfo); - if (ret) - goto out; +static int32_t +glusterd_store_perform_brick_store(glusterd_brickinfo_t *brickinfo) +{ + int fd = -1; + int32_t ret = -1; + GF_ASSERT(brickinfo); + + fd = gf_store_mkstemp(brickinfo->shandle); + if (fd <= 0) { + ret = -1; + goto out; + } + ret = glusterd_store_brickinfo_write(fd, brickinfo); + if (ret) + goto out; - ret = glusterd_store_rename_tmppath (brickinfo->shandle); out: - if (ret && (fd > 0)) - glusterd_store_unlink_tmppath (brickinfo->shandle); - if (fd > 0) - close (fd); - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; + if (ret && (fd > 0)) { + gf_store_unlink_tmppath(brickinfo->shandle); + } + gf_msg_debug(THIS->name, 0, "Returning %d", ret); + return ret; } int32_t -glusterd_store_brickinfo (glusterd_volinfo_t *volinfo, - glusterd_brickinfo_t *brickinfo, int32_t brick_count, - int vol_fd) +glusterd_store_perform_snapd_store(glusterd_volinfo_t *volinfo) { - int32_t ret = -1; + int fd = -1; + int32_t ret = -1; + xlator_t *this = NULL; + + GF_ASSERT(volinfo); + + this = THIS; + GF_ASSERT(this); + + fd = gf_store_mkstemp(volinfo->snapd.handle); + if (fd <= 0) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, + "failed to create the " + "temporary file for the snapd store handle of volume " + "%s", + volinfo->volname); + goto out; + } + + ret = glusterd_store_snapd_write(fd, volinfo); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPD_PORT_STORE_FAIL, + "failed to write snapd port " + "info to store handle (volume: %s", + volinfo->volname); + goto out; + } + + ret = gf_store_rename_tmppath(volinfo->snapd.handle); - GF_ASSERT (volinfo); - GF_ASSERT (brickinfo); +out: + if (ret && (fd > 0)) + gf_store_unlink_tmppath(volinfo->snapd.handle); + gf_msg_debug(THIS->name, 0, "Returning %d", ret); + return ret; +} - ret = glusterd_store_volinfo_brick_fname_write (vol_fd, brickinfo, - brick_count); - if (ret) - goto out; +static int32_t +glusterd_store_brickinfo(glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo, int32_t brick_count, + int vol_fd, int is_thin_arbiter) +{ + int32_t ret = -1; - ret = glusterd_store_create_brick_dir (volinfo); - if (ret) - goto out; + GF_ASSERT(volinfo); + GF_ASSERT(brickinfo); - ret = glusterd_store_create_brick_shandle_on_absence (volinfo, - brickinfo); - if (ret) - goto out; + ret = glusterd_store_volinfo_brick_fname_write( + vol_fd, brickinfo, brick_count, is_thin_arbiter); + if (ret) + goto out; - ret = glusterd_store_perform_brick_store (brickinfo); + ret = glusterd_store_create_brick_shandle_on_absence(volinfo, brickinfo); + if (ret) + goto out; + + ret = glusterd_store_perform_brick_store(brickinfo); out: - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); - return ret; + gf_msg_debug(THIS->name, 0, "Returning with %d", ret); + return ret; } int32_t -glusterd_store_delete_brick (glusterd_volinfo_t *volinfo, - glusterd_brickinfo_t *brickinfo) +glusterd_store_snapd_info(glusterd_volinfo_t *volinfo) { - int32_t ret = -1; - glusterd_conf_t *priv = NULL; - char path[PATH_MAX] = {0,}; - char brickpath[PATH_MAX] = {0,}; - char *ptr = NULL; - char *tmppath = NULL; + int32_t ret = -1; + xlator_t *this = NULL; + + GF_ASSERT(volinfo); + + this = THIS; + GF_ASSERT(this); + + ret = glusterd_store_create_snapd_shandle_on_absence(volinfo); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_HANDLE_CREATE_FAIL, + "failed to create store " + "handle for snapd (volume: %s)", + volinfo->volname); + goto out; + } + + ret = glusterd_store_perform_snapd_store(volinfo); + if (ret) + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPD_INFO_STORE_FAIL, + "failed to store snapd info " + "of the volume %s", + volinfo->volname); + +out: + if (ret) + gf_store_unlink_tmppath(volinfo->snapd.handle); - GF_ASSERT (volinfo); - GF_ASSERT (brickinfo); + gf_msg_debug(this->name, 0, "Returning with %d", ret); + return ret; +} - priv = THIS->private; +int32_t +glusterd_store_delete_brick(glusterd_brickinfo_t *brickinfo, char *delete_path) +{ + int32_t ret = -1; + glusterd_conf_t *priv = NULL; + char brickpath[PATH_MAX] = { + 0, + }; + char *ptr = NULL; + char *tmppath = NULL; + xlator_t *this = NULL; - GF_ASSERT (priv); + this = THIS; + GF_ASSERT(this); + GF_ASSERT(brickinfo); - GLUSTERD_GET_BRICK_DIR (path, volinfo, priv); + priv = this->private; + GF_ASSERT(priv); - tmppath = gf_strdup (brickinfo->path); + tmppath = gf_strdup(brickinfo->path); - ptr = strchr (tmppath, '/'); + ptr = strchr(tmppath, '/'); - while (ptr) { - *ptr = '-'; - ptr = strchr (tmppath, '/'); - } + while (ptr) { + *ptr = '-'; + ptr = strchr(tmppath, '/'); + } - snprintf (brickpath, sizeof (brickpath), "%s/%s:%s", - path, brickinfo->hostname, tmppath); + snprintf(brickpath, sizeof(brickpath), + "%s/" GLUSTERD_BRICK_INFO_DIR "/%s:%s", delete_path, + brickinfo->hostname, tmppath); - GF_FREE (tmppath); + GF_FREE(tmppath); - ret = unlink (brickpath); + ret = sys_unlink(brickpath); - if ((ret < 0) && (errno != ENOENT)) { - gf_log ("", GF_LOG_ERROR, "Unlink failed on %s, reason: %s", - brickpath, strerror(errno)); - ret = -1; - goto out; - } else { - ret = 0; - } + if ((ret < 0) && (errno != ENOENT)) { + gf_msg_debug(this->name, 0, "Unlink failed on %s", brickpath); + ret = -1; + goto out; + } else { + ret = 0; + } out: - if (brickinfo->shandle) { - glusterd_store_handle_destroy (brickinfo->shandle); - brickinfo->shandle = NULL; - } - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); - return ret; + if (brickinfo->shandle) { + gf_store_handle_destroy(brickinfo->shandle); + brickinfo->shandle = NULL; + } + gf_msg_debug(this->name, 0, "Returning with %d", ret); + return ret; } -int32_t -glusterd_store_remove_bricks (glusterd_volinfo_t *volinfo) +static int +_storeopts(dict_t *dict_value, char *key, data_t *value, void *data) { - int32_t ret = 0; - glusterd_brickinfo_t *tmp = NULL; - glusterd_conf_t *priv = NULL; - char brickdir [PATH_MAX] = {0,}; - DIR *dir = NULL; - struct dirent *entry = NULL; - char path[PATH_MAX] = {0,}; + int32_t ret = 0; + int32_t exists = 0; + int32_t option_len = 0; + gf_store_handle_t *shandle = NULL; + glusterd_volinfo_data_store_t *dict_data = NULL; + xlator_t *this = NULL; - GF_ASSERT (volinfo); + this = THIS; + GF_ASSERT(this); - list_for_each_entry (tmp, &volinfo->bricks, brick_list) { - ret = glusterd_store_delete_brick (volinfo, tmp); - if (ret) - goto out; - } + dict_data = (glusterd_volinfo_data_store_t *)data; + shandle = dict_data->shandle; - priv = THIS->private; - GF_ASSERT (priv); + GF_ASSERT(shandle); + GF_ASSERT(shandle->fd > 0); + GF_ASSERT(key); + GF_ASSERT(value); + GF_ASSERT(value->data); - GLUSTERD_GET_BRICK_DIR (brickdir, volinfo, priv); + if (dict_data->key_check == 1) { + if (is_key_glusterd_hooks_friendly(key)) { + exists = 1; - dir = opendir (brickdir); + } else { + exists = glusterd_check_option_exists(key, NULL); + } + } + if (exists == 1 || dict_data->key_check == 0) { + gf_msg_debug(this->name, 0, + "Storing in buffer for volinfo:key= %s, " + "val=%s", + key, value->data); + } else { + gf_msg_debug(this->name, 0, "Discarding:key= %s, val=%s", key, + value->data); + return 0; + } + + /* + * The option_len considers the length of the key value + * pair and along with that '=' and '\n', but as value->len + * already considers a NULL at the end of the data, adding + * just 1. + */ + option_len = strlen(key) + value->len + 1; + + if ((VOLINFO_BUFFER_SIZE - dict_data->buffer_len - 1) < option_len) { + ret = gf_store_save_items(shandle->fd, dict_data->buffer); + if (ret) { + gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_FILE_OP_FAILED, NULL); + return -1; + } + dict_data->buffer_len = 0; + dict_data->buffer[0] = '\0'; + } + ret = snprintf(dict_data->buffer + dict_data->buffer_len, option_len + 1, + "%s=%s\n", key, value->data); + if (ret < 0 || ret > option_len + 1) { + gf_smsg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_COPY_FAIL, NULL); + return -1; + } + + dict_data->buffer_len += ret; + + return 0; +} - glusterd_for_each_entry (entry, dir); +/* Store the volumes snapshot details only if required + * + * The snapshot details will be stored only if the cluster op-version is + * greater than or equal to 4 + */ +static int +glusterd_volume_write_snap_details(int fd, glusterd_volinfo_t *volinfo) +{ + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + char buf[PATH_MAX] = { + 0, + }; + + this = THIS; + GF_ASSERT(this != NULL); + conf = this->private; + GF_VALIDATE_OR_GOTO(this->name, (conf != NULL), out); + + GF_VALIDATE_OR_GOTO(this->name, (fd > 0), out); + GF_VALIDATE_OR_GOTO(this->name, (volinfo != NULL), out); + + if (conf->op_version < GD_OP_VERSION_3_6_0) { + ret = 0; + goto out; + } + + ret = snprintf(buf, sizeof(buf), "%s=%s\n%s=%s\n%s=%" PRIu64 "\n", + GLUSTERD_STORE_KEY_PARENT_VOLNAME, volinfo->parent_volname, + GLUSTERD_STORE_KEY_VOL_RESTORED_SNAP, + uuid_utoa(volinfo->restored_from_snap), + GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT, + volinfo->snap_max_hard_limit); + if (ret < 0 || ret >= sizeof(buf)) { + ret = -1; + goto err; + } + + ret = gf_store_save_items(fd, buf); + if (ret) { + goto err; + } + ret = glusterd_store_snapd_info(volinfo); +err: + if (ret) + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPINFO_WRITE_FAIL, + "Failed to write snap details" + " for volume %s", + volinfo->volname); +out: + return ret; +} - while (entry) { - snprintf (path, sizeof (path), "%s/%s", - brickdir, entry->d_name); - ret = unlink (path); - if (ret && errno != ENOENT) { - gf_log ("", GF_LOG_ERROR, "Unable to unlink %s, " - "reason: %s", path, strerror(errno)); - } - glusterd_for_each_entry (entry, dir); +static int32_t +glusterd_volume_exclude_options_write(int fd, glusterd_volinfo_t *volinfo) +{ + char *str = NULL; + char buf[PATH_MAX]; + uint total_len = 0; + int32_t ret = -1; + xlator_t *this = THIS; + glusterd_conf_t *conf = NULL; + + GF_ASSERT(this); + GF_ASSERT(fd > 0); + GF_ASSERT(volinfo); + conf = this->private; + GF_VALIDATE_OR_GOTO(this->name, (conf != NULL), out); + + ret = snprintf(buf + total_len, sizeof(buf) - total_len, + "%s=%d\n%s=%d\n%s=%d\n%s=%d\n%s=%d\n%s=%d\n", + GLUSTERD_STORE_KEY_VOL_TYPE, volinfo->type, + GLUSTERD_STORE_KEY_VOL_COUNT, volinfo->brick_count, + GLUSTERD_STORE_KEY_VOL_STATUS, volinfo->status, + GLUSTERD_STORE_KEY_VOL_SUB_COUNT, volinfo->sub_count, + GLUSTERD_STORE_KEY_VOL_STRIPE_CNT, volinfo->stripe_count, + GLUSTERD_STORE_KEY_VOL_REPLICA_CNT, volinfo->replica_count); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + total_len += ret; + + if ((conf->op_version >= GD_OP_VERSION_3_7_6) && volinfo->arbiter_count) { + ret = snprintf(buf + total_len, sizeof(buf) - total_len, "%s=%d\n", + GLUSTERD_STORE_KEY_VOL_ARBITER_CNT, + volinfo->arbiter_count); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; } + total_len += ret; + } + + if (conf->op_version >= GD_OP_VERSION_3_6_0) { + ret = snprintf( + buf + total_len, sizeof(buf) - total_len, "%s=%d\n%s=%d\n", + GLUSTERD_STORE_KEY_VOL_DISPERSE_CNT, volinfo->disperse_count, + GLUSTERD_STORE_KEY_VOL_REDUNDANCY_CNT, volinfo->redundancy_count); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + total_len += ret; + } + + ret = snprintf(buf + total_len, sizeof(buf) - total_len, + "%s=%d\n%s=%d\n%s=%s\n", GLUSTERD_STORE_KEY_VOL_VERSION, + volinfo->version, GLUSTERD_STORE_KEY_VOL_TRANSPORT, + volinfo->transport_type, GLUSTERD_STORE_KEY_VOL_ID, + uuid_utoa(volinfo->volume_id)); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + total_len += ret; + + str = glusterd_auth_get_username(volinfo); + if (str) { + ret = snprintf(buf + total_len, sizeof(buf) - total_len, "%s=%s\n", + GLUSTERD_STORE_KEY_USERNAME, str); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + total_len += ret; + } + + str = glusterd_auth_get_password(volinfo); + if (str) { + ret = snprintf(buf + total_len, sizeof(buf) - total_len, "%s=%s\n", + GLUSTERD_STORE_KEY_PASSWORD, str); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + total_len += ret; + } + + ret = snprintf(buf + total_len, sizeof(buf) - total_len, "%s=%d\n%s=%d\n", + GLUSTERD_STORE_KEY_VOL_OP_VERSION, volinfo->op_version, + GLUSTERD_STORE_KEY_VOL_CLIENT_OP_VERSION, + volinfo->client_op_version); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + total_len += ret; + + if (conf->op_version >= GD_OP_VERSION_3_7_6) { + ret = snprintf(buf + total_len, sizeof(buf) - total_len, "%s=%d\n", + GLUSTERD_STORE_KEY_VOL_QUOTA_VERSION, + volinfo->quota_xattr_version); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + total_len += ret; + } + if (conf->op_version >= GD_OP_VERSION_3_10_0) { + ret = snprintf(buf + total_len, sizeof(buf) - total_len, "%s=0\n", + GF_TIER_ENABLED); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + total_len += ret; + } + + if ((conf->op_version >= GD_OP_VERSION_7_0) && + volinfo->thin_arbiter_count) { + ret = snprintf(buf + total_len, sizeof(buf) - total_len, "%s=%d\n", + GLUSTERD_STORE_KEY_VOL_THIN_ARBITER_CNT, + volinfo->thin_arbiter_count); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + total_len += ret; + } - closedir (dir); + ret = gf_store_save_items(fd, buf); + if (ret) + goto out; - ret = rmdir (brickdir); + ret = glusterd_volume_write_snap_details(fd, volinfo); out: - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); - return ret; + if (ret) + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_VALS_WRITE_FAIL, + "Unable to write volume " + "values for %s", + volinfo->volname); + return ret; } static void -_storeslaves (dict_t *this, char *key, data_t *value, void *data) +glusterd_store_voldirpath_set(glusterd_volinfo_t *volinfo, char *voldirpath) { - int32_t ret = 0; - glusterd_store_handle_t *shandle = NULL; - - shandle = (glusterd_store_handle_t*)data; + glusterd_conf_t *priv = NULL; - GF_ASSERT (shandle); - GF_ASSERT (shandle->fd > 0); - GF_ASSERT (shandle->path); - GF_ASSERT (key); - GF_ASSERT (value && value->data); + GF_ASSERT(volinfo); + priv = THIS->private; + GF_ASSERT(priv); - if ((!shandle) || (shandle->fd <= 0) || (!shandle->path)) - return; + GLUSTERD_GET_VOLUME_DIR(voldirpath, volinfo, priv); +} - if (!key) - return; - if (!value || !value->data) - return; +static void +glusterd_store_piddirpath_set(glusterd_volinfo_t *volinfo, char *piddirpath) +{ + glusterd_conf_t *priv = NULL; - gf_log ("", GF_LOG_DEBUG, "Storing in volinfo:key= %s, val=%s", - key, value->data); + GF_ASSERT(volinfo); + priv = THIS->private; + GF_ASSERT(priv); - ret = glusterd_store_save_value (shandle->fd, key, (char*)value->data); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to write into store" - " handle for path: %s", shandle->path); - return; - } + GLUSTERD_GET_VOLUME_PID_DIR(piddirpath, volinfo, priv); } - -void _storeopts (dict_t *this, char *key, data_t *value, void *data) +static int32_t +glusterd_store_create_volume_dirs(glusterd_volinfo_t *volinfo) { - int32_t ret = 0; - int32_t exists = 0; - glusterd_store_handle_t *shandle = NULL; - - shandle = (glusterd_store_handle_t*)data; - - GF_ASSERT (shandle); - GF_ASSERT (shandle->fd > 0); - GF_ASSERT (shandle->path); - GF_ASSERT (key); - GF_ASSERT (value && value->data); + int32_t ret = -1; + char dirpath[PATH_MAX] = { + 0, + }; - if ((!shandle) || (shandle->fd <= 0) || (!shandle->path)) - return; + GF_ASSERT(volinfo); - if (!key) - return; - if (!value || !value->data) - return; + glusterd_store_voldirpath_set(volinfo, dirpath); + ret = gf_store_mkdir(dirpath); + if (ret) + goto out; - exists = glusterd_check_option_exists (key, NULL); - if (1 == exists) { - gf_log ("", GF_LOG_DEBUG, "Storing in volinfo:key= %s, val=%s", - key, value->data); - } else { - gf_log ("", GF_LOG_DEBUG, "Discarding:key= %s, val=%s", - key, value->data); - return; - } + glusterd_store_piddirpath_set(volinfo, dirpath); + ret = gf_store_mkdir(dirpath); + if (ret) + goto out; - ret = glusterd_store_save_value (shandle->fd, key, (char*)value->data); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to write into store" - " handle for path: %s", shandle->path); - return; - } +out: + gf_msg_debug(THIS->name, 0, "Returning with %d", ret); + return ret; } int32_t -glusterd_volume_exclude_options_write (int fd, glusterd_volinfo_t *volinfo) +glusterd_store_create_snap_dir(glusterd_snap_t *snap) { - GF_ASSERT (fd > 0); - GF_ASSERT (volinfo); + int32_t ret = -1; + char snapdirpath[PATH_MAX] = { + 0, + }; + glusterd_conf_t *priv = NULL; + + priv = THIS->private; + GF_ASSERT(priv); + GF_ASSERT(snap); + + GLUSTERD_GET_SNAP_DIR(snapdirpath, snap, priv); + + ret = mkdir_p(snapdirpath, 0755, _gf_true); + if (ret) { + gf_msg(THIS->name, GF_LOG_ERROR, errno, GD_MSG_CREATE_DIR_FAILED, + "Failed to create snaps dir " + "%s", + snapdirpath); + } + return ret; +} - char buf[PATH_MAX] = {0,}; - int32_t ret = -1; +static int32_t +glusterd_store_volinfo_write(int fd, glusterd_volinfo_t *volinfo) +{ + int32_t ret = -1; + gf_store_handle_t *shandle = NULL; + GF_ASSERT(fd > 0); + GF_ASSERT(volinfo); + GF_ASSERT(volinfo->shandle); + xlator_t *this = NULL; + glusterd_volinfo_data_store_t *dict_data = NULL; + + this = THIS; + GF_ASSERT(this); + + shandle = volinfo->shandle; + + dict_data = GF_CALLOC(1, sizeof(glusterd_volinfo_data_store_t), + gf_gld_mt_volinfo_dict_data_t); + if (dict_data == NULL) { + gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_NO_MEMORY, NULL); + return -1; + } + + ret = glusterd_volume_exclude_options_write(fd, volinfo); + if (ret) { + goto out; + } + + dict_data->shandle = shandle; + dict_data->key_check = 1; + + shandle->fd = fd; + dict_foreach(volinfo->dict, _storeopts, (void *)dict_data); + + dict_data->key_check = 0; + dict_foreach(volinfo->gsync_slaves, _storeopts, (void *)dict_data); + + if (dict_data->buffer_len > 0) { + ret = gf_store_save_items(fd, dict_data->buffer); + if (ret) { + gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_FILE_OP_FAILED, NULL); + goto out; + } + } - snprintf (buf, sizeof (buf), "%d", volinfo->type); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_VOL_TYPE, buf); - if (ret) - goto out; + shandle->fd = 0; +out: + GF_FREE(dict_data); + gf_msg_debug(this->name, 0, "Returning %d", ret); + return ret; +} - snprintf (buf, sizeof (buf), "%d", volinfo->brick_count); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_VOL_COUNT, buf); - if (ret) - goto out; +static int32_t +glusterd_store_snapinfo_write(glusterd_snap_t *snap) +{ + int32_t ret = -1; + int fd = 0; + char buf[PATH_MAX]; + uint total_len = 0; + + GF_ASSERT(snap); + + fd = gf_store_mkstemp(snap->shandle); + if (fd <= 0) + goto out; + + ret = snprintf(buf + total_len, sizeof(buf) - total_len, + "%s=%s\n%s=%d\n%s=%d\n", GLUSTERD_STORE_KEY_SNAP_ID, + uuid_utoa(snap->snap_id), GLUSTERD_STORE_KEY_SNAP_STATUS, + snap->snap_status, GLUSTERD_STORE_KEY_SNAP_RESTORED, + snap->snap_restored); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + total_len += ret; + + if (snap->description) { + ret = snprintf(buf + total_len, sizeof(buf) - total_len, "%s=%s\n", + GLUSTERD_STORE_KEY_SNAP_DESC, snap->description); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + total_len += ret; + } - snprintf (buf, sizeof (buf), "%d", volinfo->status); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_VOL_STATUS, buf); - if (ret) - goto out; + ret = snprintf(buf + total_len, sizeof(buf) - total_len, "%s=%ld\n", + GLUSTERD_STORE_KEY_SNAP_TIMESTAMP, snap->time_stamp); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + ret = gf_store_save_items(fd, buf); - snprintf (buf, sizeof (buf), "%d", volinfo->sub_count); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_VOL_SUB_COUNT, - buf); - if (ret) - goto out; +out: + gf_msg_debug(THIS->name, 0, "Returning %d", ret); + return ret; +} - snprintf (buf, sizeof (buf), "%d", volinfo->stripe_count); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_VOL_STRIPE_CNT, - buf); - if (ret) - goto out; +static void +glusterd_store_volfpath_set(glusterd_volinfo_t *volinfo, char *volfpath, + size_t len) +{ + char voldirpath[PATH_MAX] = { + 0, + }; + GF_ASSERT(volinfo); + GF_ASSERT(volfpath); + GF_ASSERT(len <= PATH_MAX); + + glusterd_store_voldirpath_set(volinfo, voldirpath); + snprintf(volfpath, len, "%s/%s", voldirpath, GLUSTERD_VOLUME_INFO_FILE); +} - snprintf (buf, sizeof (buf), "%d", volinfo->replica_count); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_VOL_REPLICA_CNT, - buf); - if (ret) - goto out; +static void +glusterd_store_node_state_path_set(glusterd_volinfo_t *volinfo, + char *node_statepath, size_t len) +{ + char voldirpath[PATH_MAX] = { + 0, + }; + GF_ASSERT(volinfo); + GF_ASSERT(node_statepath); + GF_ASSERT(len <= PATH_MAX); + + glusterd_store_voldirpath_set(volinfo, voldirpath); + snprintf(node_statepath, len, "%s/%s", voldirpath, + GLUSTERD_NODE_STATE_FILE); +} - snprintf (buf, sizeof (buf), "%d", volinfo->version); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_VOL_VERSION, - buf); - if (ret) - goto out; +static void +glusterd_store_quota_conf_path_set(glusterd_volinfo_t *volinfo, + char *quota_conf_path, size_t len) +{ + char voldirpath[PATH_MAX] = { + 0, + }; + GF_ASSERT(volinfo); + GF_ASSERT(quota_conf_path); + GF_ASSERT(len <= PATH_MAX); + + glusterd_store_voldirpath_set(volinfo, voldirpath); + snprintf(quota_conf_path, len, "%s/%s", voldirpath, + GLUSTERD_VOLUME_QUOTA_CONFIG); +} - snprintf (buf, sizeof (buf), "%d", volinfo->transport_type); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_VOL_TRANSPORT, - buf); - if (ret) - goto out; +static void +glusterd_store_missed_snaps_list_path_set(char *missed_snaps_list, size_t len) +{ + glusterd_conf_t *priv = NULL; - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_VOL_ID, - uuid_utoa (volinfo->volume_id)); - if (ret) - goto out; + priv = THIS->private; + GF_ASSERT(priv); + GF_ASSERT(missed_snaps_list); + GF_ASSERT(len <= PATH_MAX); -out: - if (ret) - gf_log ("", GF_LOG_ERROR, "Unable to write volume values" - " for %s", volinfo->volname); - return ret; + snprintf(missed_snaps_list, len, + "%s/snaps/" GLUSTERD_MISSED_SNAPS_LIST_FILE, priv->workdir); } static void -glusterd_store_voldirpath_set (glusterd_volinfo_t *volinfo, char *voldirpath, - size_t len) +glusterd_store_snapfpath_set(glusterd_snap_t *snap, char *snap_fpath, + size_t len) { - glusterd_conf_t *priv = NULL; - - GF_ASSERT (volinfo); - priv = THIS->private; - GF_ASSERT (priv); - - snprintf (voldirpath, len, "%s/%s/%s", priv->workdir, - GLUSTERD_VOLUME_DIR_PREFIX, volinfo->volname); + glusterd_conf_t *priv = NULL; + priv = THIS->private; + GF_ASSERT(priv); + GF_ASSERT(snap); + GF_ASSERT(snap_fpath); + GF_ASSERT(len <= PATH_MAX); + + snprintf(snap_fpath, len, "%s/snaps/%s/%s", priv->workdir, snap->snapname, + GLUSTERD_SNAP_INFO_FILE); } -static int32_t -glusterd_store_create_volume_dir (glusterd_volinfo_t *volinfo) +int32_t +glusterd_store_create_vol_shandle_on_absence(glusterd_volinfo_t *volinfo) { - int32_t ret = -1; - char voldirpath[PATH_MAX] = {0,}; + char volfpath[PATH_MAX] = {0}; + int32_t ret = 0; - GF_ASSERT (volinfo); + GF_ASSERT(volinfo); - glusterd_store_voldirpath_set (volinfo, voldirpath, - sizeof (voldirpath)); - ret = glusterd_store_mkdir (voldirpath); - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); - return ret; + glusterd_store_volfpath_set(volinfo, volfpath, sizeof(volfpath)); + ret = gf_store_handle_create_on_absence(&volinfo->shandle, volfpath); + return ret; } int32_t -glusterd_store_volinfo_write (int fd, glusterd_volinfo_t *volinfo) +glusterd_store_create_nodestate_sh_on_absence(glusterd_volinfo_t *volinfo) { - int32_t ret = -1; - glusterd_store_handle_t *shandle = NULL; - GF_ASSERT (fd > 0); - GF_ASSERT (volinfo); - GF_ASSERT (volinfo->shandle); + char node_state_path[PATH_MAX] = {0}; + int32_t ret = 0; - shandle = volinfo->shandle; - ret = glusterd_volume_exclude_options_write (fd, volinfo); - if (ret) - goto out; + GF_ASSERT(volinfo); - shandle->fd = fd; - dict_foreach (volinfo->dict, _storeopts, shandle); + glusterd_store_node_state_path_set(volinfo, node_state_path, + sizeof(node_state_path)); + ret = gf_store_handle_create_on_absence(&volinfo->node_state_shandle, + node_state_path); - dict_foreach (volinfo->gsync_slaves, _storeslaves, shandle); - shandle->fd = 0; -out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; + return ret; } -static void -glusterd_store_rbstatepath_set (glusterd_volinfo_t *volinfo, char *rbstatepath, - size_t len) +int32_t +glusterd_store_create_quota_conf_sh_on_absence(glusterd_volinfo_t *volinfo) { - char voldirpath[PATH_MAX] = {0,}; - GF_ASSERT (volinfo); - GF_ASSERT (rbstatepath); - GF_ASSERT (len >= PATH_MAX); + char quota_conf_path[PATH_MAX] = {0}; + int32_t ret = 0; - glusterd_store_voldirpath_set (volinfo, voldirpath, - sizeof (voldirpath)); - snprintf (rbstatepath, len, "%s/%s", voldirpath, - GLUSTERD_VOLUME_RBSTATE_FILE); -} + GF_ASSERT(volinfo); -static void -glusterd_store_volfpath_set (glusterd_volinfo_t *volinfo, char *volfpath, - size_t len) -{ - char voldirpath[PATH_MAX] = {0,}; - GF_ASSERT (volinfo); - GF_ASSERT (volfpath); - GF_ASSERT (len >= PATH_MAX); + glusterd_store_quota_conf_path_set(volinfo, quota_conf_path, + sizeof(quota_conf_path)); + ret = gf_store_handle_create_on_absence(&volinfo->quota_conf_shandle, + quota_conf_path); - glusterd_store_voldirpath_set (volinfo, voldirpath, - sizeof (voldirpath)); - snprintf (volfpath, len, "%s/%s", voldirpath, GLUSTERD_VOLUME_INFO_FILE); + return ret; } -int32_t -glusterd_store_create_rbstate_shandle_on_absence (glusterd_volinfo_t *volinfo) +static int32_t +glusterd_store_create_missed_snaps_list_shandle_on_absence() { - char rbstatepath[PATH_MAX] = {0}; - int32_t ret = 0; + char missed_snaps_list[PATH_MAX] = ""; + int32_t ret = -1; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; - GF_ASSERT (volinfo); + this = THIS; + GF_ASSERT(this); - glusterd_store_rbstatepath_set (volinfo, rbstatepath, sizeof (rbstatepath)); - ret = glusterd_store_handle_create_on_absence (&volinfo->rb_shandle, - rbstatepath); - return ret; + priv = this->private; + GF_ASSERT(priv); + + glusterd_store_missed_snaps_list_path_set(missed_snaps_list, + sizeof(missed_snaps_list)); + + ret = gf_store_handle_create_on_absence(&priv->missed_snaps_list_shandle, + missed_snaps_list); + return ret; } int32_t -glusterd_store_create_vol_shandle_on_absence (glusterd_volinfo_t *volinfo) +glusterd_store_create_snap_shandle_on_absence(glusterd_snap_t *snap) { - char volfpath[PATH_MAX] = {0}; - int32_t ret = 0; + char snapfpath[PATH_MAX] = {0}; + int32_t ret = 0; - GF_ASSERT (volinfo); + GF_ASSERT(snap); - glusterd_store_volfpath_set (volinfo, volfpath, sizeof (volfpath)); - ret = glusterd_store_handle_create_on_absence (&volinfo->shandle, - volfpath); - return ret; + glusterd_store_snapfpath_set(snap, snapfpath, sizeof(snapfpath)); + ret = gf_store_handle_create_on_absence(&snap->shandle, snapfpath); + return ret; } -int32_t -glusterd_store_brickinfos (glusterd_volinfo_t *volinfo, int vol_fd) +static int32_t +glusterd_store_brickinfos(glusterd_volinfo_t *volinfo, int vol_fd) { - int32_t ret = 0; - glusterd_brickinfo_t *brickinfo = NULL; - int32_t brick_count = 0; - - GF_ASSERT (volinfo); + int32_t ret = 0; + glusterd_brickinfo_t *brickinfo = NULL; + glusterd_brickinfo_t *ta_brickinfo = NULL; + int32_t brick_count = 0; + int32_t ta_brick_count = 0; + + GF_ASSERT(volinfo); + + cds_list_for_each_entry(brickinfo, &volinfo->bricks, brick_list) + { + ret = glusterd_store_brickinfo(volinfo, brickinfo, brick_count, vol_fd, + 0); + if (ret) + goto out; + brick_count++; + } + if (volinfo->thin_arbiter_count == 1) { + ta_brickinfo = list_first_entry(&volinfo->ta_bricks, + glusterd_brickinfo_t, brick_list); + ret = glusterd_store_brickinfo(volinfo, ta_brickinfo, ta_brick_count, + vol_fd, 1); + if (ret) + goto out; + } - list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { - ret = glusterd_store_brickinfo (volinfo, brickinfo, - brick_count, vol_fd); - if (ret) - goto out; - brick_count++; - } out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; + gf_msg_debug(THIS->name, 0, "Returning %d", ret); + return ret; } int32_t -glusterd_store_rbstate_write (int fd, glusterd_volinfo_t *volinfo) +glusterd_store_node_state_write(int fd, glusterd_volinfo_t *volinfo) { - int ret = -1; - char buf[PATH_MAX] = {0, }; + int ret = -1; + char buf[PATH_MAX]; + char uuid[UUID_SIZE + 1]; + uint total_len = 0; + glusterd_volinfo_data_store_t *dict_data = NULL; + gf_store_handle_t shandle; + xlator_t *this = NULL; - GF_ASSERT (fd > 0); - GF_ASSERT (volinfo); + this = THIS; + GF_ASSERT(this); - snprintf (buf, sizeof (buf), "%d", volinfo->rb_status); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_RB_STATUS, - buf); - if (ret) - goto out; + GF_ASSERT(fd > 0); + GF_ASSERT(volinfo); - if (volinfo->rb_status > GF_RB_STATUS_NONE) { - - snprintf (buf, sizeof (buf), "%s:%s", - volinfo->src_brick->hostname, - volinfo->src_brick->path); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_RB_SRC_BRICK, - buf); - if (ret) - goto out; - - snprintf (buf, sizeof (buf), "%s:%s", - volinfo->dst_brick->hostname, - volinfo->dst_brick->path); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_RB_DST_BRICK, - buf); - if (ret) - goto out; + if (volinfo->rebal.defrag_cmd == GF_DEFRAG_CMD_STATUS) { + ret = 0; + goto out; + } + + gf_uuid_unparse(volinfo->rebal.rebalance_id, uuid); + ret = snprintf(buf + total_len, sizeof(buf) - total_len, + "%s=%d\n%s=%d\n%s=%d\n%s=%s\n", + GLUSTERD_STORE_KEY_VOL_DEFRAG, volinfo->rebal.defrag_cmd, + GLUSTERD_STORE_KEY_VOL_DEFRAG_STATUS, + volinfo->rebal.defrag_status, GLUSTERD_STORE_KEY_DEFRAG_OP, + volinfo->rebal.op, GF_REBALANCE_TID_KEY, uuid); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + total_len += ret; + + ret = snprintf( + buf + total_len, sizeof(buf) - total_len, + "%s=%" PRIu64 "\n%s=%" PRIu64 "\n%s=%" PRIu64 "\n%s=%" PRIu64 + "\n%s=%" PRIu64 "\n%s=%lf\n", + GLUSTERD_STORE_KEY_VOL_DEFRAG_REB_FILES, volinfo->rebal.rebalance_files, + GLUSTERD_STORE_KEY_VOL_DEFRAG_SIZE, volinfo->rebal.rebalance_data, + GLUSTERD_STORE_KEY_VOL_DEFRAG_SCANNED, volinfo->rebal.lookedup_files, + GLUSTERD_STORE_KEY_VOL_DEFRAG_FAILURES, + volinfo->rebal.rebalance_failures, + GLUSTERD_STORE_KEY_VOL_DEFRAG_SKIPPED, volinfo->rebal.skipped_files, + GLUSTERD_STORE_KEY_VOL_DEFRAG_RUN_TIME, volinfo->rebal.rebalance_time); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + + ret = gf_store_save_items(fd, buf); + if (ret) { + goto out; + } + + if (volinfo->rebal.dict) { + dict_data = GF_CALLOC(1, sizeof(glusterd_volinfo_data_store_t), + gf_gld_mt_volinfo_dict_data_t); + if (dict_data == NULL) { + gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_NO_MEMORY, NULL); + return -1; } - + dict_data->shandle = &shandle; + shandle.fd = fd; + dict_foreach(volinfo->rebal.dict, _storeopts, (void *)dict_data); + if (dict_data->buffer_len > 0) { + ret = gf_store_save_items(fd, dict_data->buffer); + if (ret) { + gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_FILE_OP_FAILED, + NULL); + goto out; + ; + } + } + } out: - gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret); - return ret; + GF_FREE(dict_data); + gf_msg_debug(this->name, 0, "Returning %d", ret); + return ret; } int32_t -glusterd_store_perform_rbstate_store (glusterd_volinfo_t *volinfo) +glusterd_store_perform_node_state_store(glusterd_volinfo_t *volinfo) { - int fd = -1; - int32_t ret = -1; - GF_ASSERT (volinfo); + int fd = -1; + int32_t ret = -1; + GF_ASSERT(volinfo); - fd = glusterd_store_mkstemp (volinfo->rb_shandle); - if (fd <= 0) { - ret = -1; - goto out; - } + fd = gf_store_mkstemp(volinfo->node_state_shandle); + if (fd <= 0) { + ret = -1; + goto out; + } - ret = glusterd_store_rbstate_write (fd, volinfo); - if (ret) - goto out; + ret = glusterd_store_node_state_write(fd, volinfo); + if (ret) + goto out; - ret = glusterd_store_rename_tmppath (volinfo->rb_shandle); + ret = gf_store_rename_tmppath(volinfo->node_state_shandle); + if (ret) + goto out; out: - if (ret && (fd > 0)) - glusterd_store_unlink_tmppath (volinfo->rb_shandle); - if (fd > 0) - close (fd); - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; + if (ret && (fd > 0)) + gf_store_unlink_tmppath(volinfo->node_state_shandle); + gf_msg_debug(THIS->name, 0, "Returning %d", ret); + return ret; } -int32_t -glusterd_store_perform_volume_store (glusterd_volinfo_t *volinfo) +static int32_t +glusterd_store_perform_volume_store(glusterd_volinfo_t *volinfo) { - int fd = -1; - int32_t ret = -1; - GF_ASSERT (volinfo); + int fd = -1; + int32_t ret = -1; + GF_ASSERT(volinfo); - fd = glusterd_store_mkstemp (volinfo->shandle); - if (fd <= 0) { - ret = -1; - goto out; - } + fd = gf_store_mkstemp(volinfo->shandle); + if (fd <= 0) { + ret = -1; + goto out; + } - ret = glusterd_store_volinfo_write (fd, volinfo); - if (ret) - goto out; + ret = glusterd_store_volinfo_write(fd, volinfo); + if (ret) + goto out; - ret = glusterd_store_brickinfos (volinfo, fd); - if (ret) - goto out; + ret = glusterd_store_create_brick_dir(volinfo); + if (ret) + goto out; + + ret = glusterd_store_brickinfos(volinfo, fd); + if (ret) + goto out; - ret = glusterd_store_rename_tmppath (volinfo->shandle); out: - if (ret && (fd > 0)) - glusterd_store_unlink_tmppath (volinfo->shandle); - if (fd > 0) - close (fd); - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; + if (ret && (fd > 0)) + gf_store_unlink_tmppath(volinfo->shandle); + gf_msg_debug(THIS->name, 0, "Returning %d", ret); + return ret; } void -glusterd_perform_volinfo_version_action (glusterd_volinfo_t *volinfo, - glusterd_volinfo_ver_ac_t ac) +glusterd_perform_volinfo_version_action(glusterd_volinfo_t *volinfo, + glusterd_volinfo_ver_ac_t ac) { - GF_ASSERT (volinfo); + GF_ASSERT(volinfo); - switch (ac) { + switch (ac) { case GLUSTERD_VOLINFO_VER_AC_NONE: - break; + break; case GLUSTERD_VOLINFO_VER_AC_INCREMENT: - volinfo->version++; - break; - } + volinfo->version++; + break; + case GLUSTERD_VOLINFO_VER_AC_DECREMENT: + volinfo->version--; + break; + } } -int32_t -glusterd_store_volinfo (glusterd_volinfo_t *volinfo, glusterd_volinfo_ver_ac_t ac) +void +glusterd_store_bricks_cleanup_tmp(glusterd_volinfo_t *volinfo) { - int32_t ret = -1; - - GF_ASSERT (volinfo); + glusterd_brickinfo_t *brickinfo = NULL; - glusterd_perform_volinfo_version_action (volinfo, ac); - ret = glusterd_store_create_volume_dir (volinfo); - if (ret) - goto out; + GF_ASSERT(volinfo); - ret = glusterd_store_create_vol_shandle_on_absence (volinfo); - if (ret) - goto out; + cds_list_for_each_entry(brickinfo, &volinfo->bricks, brick_list) + { + gf_store_unlink_tmppath(brickinfo->shandle); + } +} - ret = glusterd_store_create_rbstate_shandle_on_absence (volinfo); - if (ret) - goto out; +void +glusterd_store_volume_cleanup_tmp(glusterd_volinfo_t *volinfo) +{ + GF_ASSERT(volinfo); - ret = glusterd_store_perform_volume_store (volinfo); - if (ret) - goto out; + glusterd_store_bricks_cleanup_tmp(volinfo); - ret = glusterd_store_perform_rbstate_store (volinfo); - if (ret) - goto out; + gf_store_unlink_tmppath(volinfo->shandle); - //checksum should be computed at the end - ret = glusterd_volume_compute_cksum (volinfo); - if (ret) - goto out; -out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + gf_store_unlink_tmppath(volinfo->node_state_shandle); - return ret; + gf_store_unlink_tmppath(volinfo->snapd.handle); } - int32_t -glusterd_store_delete_volume (glusterd_volinfo_t *volinfo) +glusterd_store_brickinfos_atomic_update(glusterd_volinfo_t *volinfo) { - char pathname[PATH_MAX] = {0,}; - int32_t ret = 0; - glusterd_conf_t *priv = NULL; - DIR *dir = NULL; - struct dirent *entry = NULL; - char path[PATH_MAX] = {0,}; - struct stat st = {0, }; - - GF_ASSERT (volinfo); - priv = THIS->private; - - GF_ASSERT (priv); - snprintf (pathname, sizeof (pathname), "%s/vols/%s", priv->workdir, - volinfo->volname); + int ret = -1; + glusterd_brickinfo_t *brickinfo = NULL; + glusterd_brickinfo_t *ta_brickinfo = NULL; - dir = opendir (pathname); - if (!dir) - goto out; - ret = glusterd_store_remove_bricks (volinfo); + GF_ASSERT(volinfo); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Remove bricks failed for %s", - volinfo->volname); - } + cds_list_for_each_entry(brickinfo, &volinfo->bricks, brick_list) + { + ret = gf_store_rename_tmppath(brickinfo->shandle); + if (ret) + goto out; + } - glusterd_for_each_entry (entry, dir); - while (entry) { + if (volinfo->thin_arbiter_count == 1) { + ta_brickinfo = list_first_entry(&volinfo->ta_bricks, + glusterd_brickinfo_t, brick_list); + ret = gf_store_rename_tmppath(ta_brickinfo->shandle); + if (ret) + goto out; + } - snprintf (path, PATH_MAX, "%s/%s", pathname, entry->d_name); - ret = stat (path, &st); - if (ret == -1) { - gf_log ("", GF_LOG_ERROR, "Failed to stat entry: %s:%s", - path, strerror (errno)); - goto stat_failed; - } +out: + return ret; +} - if (S_ISDIR (st.st_mode)) - ret = rmdir (path); - else - ret = unlink (path); +int32_t +glusterd_store_volinfo_atomic_update(glusterd_volinfo_t *volinfo) +{ + int ret = -1; + GF_ASSERT(volinfo); - if (ret) - gf_log ("", GF_LOG_INFO, "errno:%d (%s)", errno, - strerror (errno)); + ret = gf_store_rename_tmppath(volinfo->shandle); + if (ret) + goto out; - gf_log ("", GF_LOG_INFO, "%s %s", - ret?"Failed to remove":"Removed", - entry->d_name); -stat_failed: - memset (path, 0, sizeof(path)); - glusterd_for_each_entry (entry, dir); - } +out: + if (ret) + gf_msg(THIS->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, + "Couldn't rename " + "temporary file(s)"); + return ret; +} - ret = closedir (dir); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Failed to close dir, errno:%d", - errno); - } +int32_t +glusterd_store_volume_atomic_update(glusterd_volinfo_t *volinfo) +{ + int ret = -1; + GF_ASSERT(volinfo); - ret = rmdir (pathname); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Failed to rmdir: %s, err: %s", - pathname, strerror (errno)); - } + ret = glusterd_store_brickinfos_atomic_update(volinfo); + if (ret) + goto out; + ret = glusterd_store_volinfo_atomic_update(volinfo); out: - if (volinfo->shandle) { - glusterd_store_handle_destroy (volinfo->shandle); - volinfo->shandle = NULL; - } - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - - return ret; + return ret; } - -int -glusterd_store_read_and_tokenize (FILE *file, char *str, - char **iter_key, char **iter_val, - glusterd_store_op_errno_t *store_errno) +int32_t +glusterd_store_snap_atomic_update(glusterd_snap_t *snap) { - int32_t ret = -1; - - GF_ASSERT (file); - GF_ASSERT (str); - GF_ASSERT (iter_key); - GF_ASSERT (iter_val); - GF_ASSERT (store_errno); + int ret = -1; + GF_ASSERT(snap); - ret = fscanf (file, "%s", str); - if (ret <= 0 || feof (file)) { - ret = -1; - *store_errno = GD_STORE_EOF; - goto out; - } + ret = gf_store_rename_tmppath(snap->shandle); + if (ret) + gf_msg(THIS->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, + "Couldn't rename " + "temporary file(s)"); - *iter_key = strtok (str, "="); - if (*iter_key == NULL) { - ret = -1; - *store_errno = GD_STORE_KEY_NULL; - goto out; - } + return ret; +} - *iter_val = strtok (NULL, "="); - if (*iter_key == NULL) { - ret = -1; - *store_errno = GD_STORE_VALUE_NULL; - goto out; - } +int32_t +glusterd_store_snap(glusterd_snap_t *snap) +{ + int32_t ret = -1; + + GF_ASSERT(snap); + + ret = glusterd_store_create_snap_dir(snap); + if (ret) { + gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_SNAPDIR_CREATE_FAIL, + "Failed to create snap dir"); + goto out; + } + + ret = glusterd_store_create_snap_shandle_on_absence(snap); + if (ret) { + gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_SNAPINFO_CREATE_FAIL, + "Failed to create snap info " + "file"); + goto out; + } + + ret = glusterd_store_snapinfo_write(snap); + if (ret) { + gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_SNAPINFO_WRITE_FAIL, + "Failed to write snap info"); + goto out; + } + + ret = glusterd_store_snap_atomic_update(snap); + if (ret) { + gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_AUTOMIC_UPDATE_FAIL, + "Failed to do automic update"); + goto out; + } - *store_errno = GD_STORE_SUCCESS; - ret = 0; out: - return ret; + if (ret && snap->shandle) + gf_store_unlink_tmppath(snap->shandle); + + gf_msg_trace(THIS->name, 0, "Returning %d", ret); + return ret; } int32_t -glusterd_store_retrieve_value (glusterd_store_handle_t *handle, - char *key, char **value) +glusterd_store_volinfo(glusterd_volinfo_t *volinfo, + glusterd_volinfo_ver_ac_t ac) { - int32_t ret = -1; - char *scan_str = NULL; - char *iter_key = NULL; - char *iter_val = NULL; - char *free_str = NULL; - struct stat st = {0,}; - glusterd_store_op_errno_t store_errno = GD_STORE_SUCCESS; - - GF_ASSERT (handle); - - handle->fd = open (handle->path, O_RDWR); + int32_t ret = -1; + glusterfs_ctx_t *ctx = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT(this); + ctx = this->ctx; + GF_ASSERT(ctx); + GF_ASSERT(volinfo); + + pthread_mutex_lock(&ctx->cleanup_lock); + pthread_mutex_lock(&volinfo->store_volinfo_lock); + { + glusterd_perform_volinfo_version_action(volinfo, ac); + + ret = glusterd_store_create_volume_dirs(volinfo); + if (ret) + goto unlock; - if (!handle->read) - handle->read = fdopen (handle->fd, "r"); + ret = glusterd_store_create_vol_shandle_on_absence(volinfo); + if (ret) + goto unlock; - if (!handle->read) { - gf_log ("", GF_LOG_ERROR, "Unable to open file %s errno: %d", - handle->path, errno); - goto out; - } + ret = glusterd_store_create_nodestate_sh_on_absence(volinfo); + if (ret) + goto unlock; - ret = fstat (handle->fd, &st); - if (ret < 0) { - gf_log ("glusterd", GF_LOG_WARNING, - "stat on file failed"); - ret = -1; - store_errno = GD_STORE_STAT_FAILED; - goto out; - } + ret = glusterd_store_perform_volume_store(volinfo); + if (ret) + goto unlock; - scan_str = GF_CALLOC (1, st.st_size, - gf_gld_mt_char); - if (scan_str == NULL) { - ret = -1; - store_errno = GD_STORE_ENOMEM; - goto out; + ret = glusterd_store_volume_atomic_update(volinfo); + if (ret) { + glusterd_perform_volinfo_version_action( + volinfo, GLUSTERD_VOLINFO_VER_AC_DECREMENT); + goto unlock; } - free_str = scan_str; + ret = glusterd_store_perform_node_state_store(volinfo); + if (ret) + goto unlock; - do { - ret = glusterd_store_read_and_tokenize (handle->read, scan_str, - &iter_key, &iter_val, - &store_errno); - if (ret < 0) { - goto out; - } + /* checksum should be computed at the end */ + ret = glusterd_compute_cksum(volinfo, _gf_false); + if (ret) + goto unlock; + } +unlock: + pthread_mutex_unlock(&volinfo->store_volinfo_lock); + pthread_mutex_unlock(&ctx->cleanup_lock); - gf_log ("", GF_LOG_DEBUG, "key %s read", iter_key); + if (ret) + glusterd_store_volume_cleanup_tmp(volinfo); - if (!strcmp (key, iter_key)) { - gf_log ("", GF_LOG_DEBUG, "key %s found", key); - ret = 0; - if (iter_val) - *value = gf_strdup (iter_val); - goto out; - } - } while (1); -out: - if (handle->fd > 0) { - close (handle->fd); - handle->read = NULL; - } - - if (free_str) - GF_FREE (free_str); + gf_msg_debug(THIS->name, 0, "Returning %d", ret); - return ret; + return ret; } int32_t -glusterd_store_save_value (int fd, char *key, char *value) +glusterd_store_delete_volume(glusterd_volinfo_t *volinfo) { - int32_t ret = -1; - FILE *fp = NULL; + char pathname[PATH_MAX] = { + 0, + }; + int32_t ret = 0; + glusterd_conf_t *priv = NULL; + char delete_path[PATH_MAX] = { + 0, + }; + char trashdir[PATH_MAX] = { + 0, + }; + xlator_t *this = NULL; + gf_boolean_t rename_fail = _gf_false; + int32_t len = 0; + + this = THIS; + GF_ASSERT(this); + + GF_ASSERT(volinfo); + priv = this->private; + + GF_ASSERT(priv); + + GLUSTERD_GET_VOLUME_DIR(pathname, volinfo, priv); + + len = snprintf(delete_path, sizeof(delete_path), + "%s/" GLUSTERD_TRASH "/%s.deleted", priv->workdir, + uuid_utoa(volinfo->volume_id)); + if ((len < 0) || (len >= sizeof(delete_path))) { + goto out; + } + + len = snprintf(trashdir, sizeof(trashdir), "%s/" GLUSTERD_TRASH, + priv->workdir); + if ((len < 0) || (len >= sizeof(trashdir))) { + goto out; + } + + ret = sys_mkdir(trashdir, 0755); + if (ret && errno != EEXIST) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_CREATE_DIR_FAILED, + "Failed to create trash " + "directory"); + goto out; + } + + ret = sys_rename(pathname, delete_path); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED, + "Failed to rename volume " + "directory for volume %s", + volinfo->volname); + rename_fail = _gf_true; + goto out; + } + + ret = recursive_rmdir(trashdir); + if (ret) { + gf_msg_debug(this->name, 0, "Failed to rmdir: %s", trashdir); + } - GF_ASSERT (fd > 0); - GF_ASSERT (key); - GF_ASSERT (value); +out: + if (volinfo->shandle) { + gf_store_handle_destroy(volinfo->shandle); + volinfo->shandle = NULL; + } + ret = (rename_fail == _gf_true) ? -1 : 0; + + gf_msg_debug(this->name, 0, "Returning %d", ret); + return ret; +} - fp = fdopen (fd, "a+"); - if (fp == NULL) { - gf_log ("", GF_LOG_WARNING, "fdopen failed."); - ret = -1; - goto out; +/*TODO: cleanup the duplicate code and implement a generic function for + * deleting snap/volume depending on the parameter flag */ +int32_t +glusterd_store_delete_snap(glusterd_snap_t *snap) +{ + char pathname[PATH_MAX] = { + 0, + }; + int32_t ret = 0; + glusterd_conf_t *priv = NULL; + DIR *dir = NULL; + struct dirent *entry = NULL; + struct dirent scratch[2] = { + { + 0, + }, + }; + char path[PATH_MAX] = { + 0, + }; + char delete_path[PATH_MAX] = { + 0, + }; + char trashdir[PATH_MAX] = { + 0, + }; + struct stat st = { + 0, + }; + xlator_t *this = NULL; + gf_boolean_t rename_fail = _gf_false; + int32_t len = 0; + + this = THIS; + priv = this->private; + GF_ASSERT(priv); + + GF_ASSERT(snap); + GLUSTERD_GET_SNAP_DIR(pathname, snap, priv); + + len = snprintf(delete_path, sizeof(delete_path), + "%s/" GLUSTERD_TRASH "/snap-%s.deleted", priv->workdir, + uuid_utoa(snap->snap_id)); + if ((len < 0) || (len >= sizeof(delete_path))) { + goto out; + } + + len = snprintf(trashdir, sizeof(trashdir), "%s/" GLUSTERD_TRASH, + priv->workdir); + if ((len < 0) || (len >= sizeof(trashdir))) { + goto out; + } + + ret = sys_mkdir(trashdir, 0755); + if (ret && errno != EEXIST) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_CREATE_DIR_FAILED, + "Failed to create trash " + "directory"); + goto out; + } + + ret = sys_rename(pathname, delete_path); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED, + "Failed to rename snap " + "directory %s to %s", + pathname, delete_path); + rename_fail = _gf_true; + goto out; + } + + dir = sys_opendir(delete_path); + if (!dir) { + gf_msg_debug(this->name, 0, "Failed to open directory %s.", + delete_path); + goto out; + } + + while ((entry = sys_readdir(dir, scratch))) { + if (gf_irrelevant_entry(entry)) + continue; + len = snprintf(path, PATH_MAX, "%s/%s", delete_path, entry->d_name); + if ((len < 0) || (len >= PATH_MAX)) { + goto stat_failed; } - - ret = fprintf (fp, "%s=%s\n", key, value); - if (ret < 0) { - gf_log ("", GF_LOG_WARNING, "Unable to store key: %s," - "value: %s, error: %s", key, value, - strerror (errno)); - ret = -1; - goto out; + ret = sys_stat(path, &st); + if (ret == -1) { + gf_msg_debug(this->name, 0, + "Failed to stat " + "entry %s", + path); + goto stat_failed; } - ret = fflush (fp); - if (feof (fp)) { - gf_log ("", GF_LOG_WARNING, - "fflush failed, error: %s", - strerror (errno)); - ret = -1; - goto out; + if (S_ISDIR(st.st_mode)) + ret = sys_rmdir(path); + else + ret = sys_unlink(path); + + if (ret) { + gf_msg_debug(this->name, 0, + " Failed to remove " + "%s", + path); } - ret = 0; -out: + gf_msg_debug(this->name, 0, "%s %s", + ret ? "Failed to remove" : "Removed", entry->d_name); + stat_failed: + memset(path, 0, sizeof(path)); + } + + ret = sys_closedir(dir); + if (ret) { + gf_msg_debug(this->name, 0, "Failed to close dir %s.", delete_path); + } + + ret = sys_rmdir(delete_path); + if (ret) { + gf_msg_debug(this->name, 0, "Failed to rmdir: %s", delete_path); + } + ret = sys_rmdir(trashdir); + if (ret) { + gf_msg_debug(this->name, 0, "Failed to rmdir: %s", trashdir); + } - gf_log ("", GF_LOG_DEBUG, "returning: %d", ret); - return ret; +out: + if (snap->shandle) { + gf_store_handle_destroy(snap->shandle); + snap->shandle = NULL; + } + ret = (rename_fail == _gf_true) ? -1 : 0; + + gf_msg_debug(this->name, 0, "Returning %d", ret); + return ret; } -int32_t -glusterd_store_handle_new (char *path, glusterd_store_handle_t **handle) +int +glusterd_store_global_info(xlator_t *this) { - int32_t ret = -1; - glusterd_store_handle_t *shandle = NULL; - int fd = -1; - char *spath = NULL; - - shandle = GF_CALLOC (1, sizeof (*shandle), gf_gld_mt_store_handle_t); - if (!shandle) - goto out; - - spath = gf_strdup (path); - - if (!spath) - goto out; - - fd = open (path, O_RDWR | O_CREAT | O_APPEND, 0644); - if (fd <= 0) { - gf_log ("glusterd", GF_LOG_ERROR, "Failed to open file: %s, " - "error: %s", path, strerror (errno)); - goto out; + int ret = -1; + glusterd_conf_t *conf = NULL; + char buf[PATH_MAX]; + uint total_len = 0; + gf_store_handle_t *handle = NULL; + char *uuid_str = NULL; + + conf = this->private; + + uuid_str = gf_strdup(uuid_utoa(MY_UUID)); + if (!uuid_str) + goto out; + + if (!conf->handle) { + ret = snprintf(buf, sizeof(buf), "%s/%s", conf->workdir, + GLUSTERD_INFO_FILE); + if ((ret < 0) || (ret >= sizeof(buf))) { + ret = -1; + goto out; + } + ret = gf_store_handle_new(buf, &handle); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_HANDLE_GET_FAIL, + "Unable to get store handle"); + goto out; } - shandle->path = spath; - *handle = shandle; - - ret = 0; - + conf->handle = handle; + } else + handle = conf->handle; + + /* These options need to be available for all users */ + ret = sys_chmod(handle->path, 0644); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, + "chmod error for %s", GLUSTERD_INFO_FILE); + goto out; + } + + handle->fd = gf_store_mkstemp(handle); + if (handle->fd < 0) { + ret = -1; + goto out; + } + + ret = snprintf(buf, sizeof(buf), "%s=%s\n", GLUSTERD_STORE_UUID_KEY, + uuid_str); + if (ret < 0 || ret >= sizeof(buf)) { + ret = -1; + goto out; + } + total_len += ret; + + ret = snprintf(buf + total_len, sizeof(buf) - total_len, "%s=%d\n", + GD_OP_VERSION_KEY, conf->op_version); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + + ret = gf_store_save_items(handle->fd, buf); + if (ret) { + gf_msg(this->name, GF_LOG_CRITICAL, 0, GD_MSG_OP_VERS_STORE_FAIL, + "Storing glusterd global-info failed ret = %d", ret); + goto out; + } + + ret = gf_store_rename_tmppath(handle); out: - if (fd > 0) - close (fd); + if (handle) { + if (ret && (handle->fd >= 0)) + gf_store_unlink_tmppath(handle); + } - if (ret == -1) { - if (spath) - GF_FREE (spath); - if (shandle) { - GF_FREE (shandle); - } - } + if (uuid_str) + GF_FREE(uuid_str); + + if (ret) + gf_msg(this->name, GF_LOG_ERROR, 0, + GD_MSG_GLUSTERD_GLOBAL_INFO_STORE_FAIL, + "Failed to store glusterd global-info"); - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; + return ret; } int -glusterd_store_handle_retrieve (char *path, glusterd_store_handle_t **handle) +glusterd_store_max_op_version(xlator_t *this) { - int32_t ret = -1; - struct stat statbuf = {0}; + int ret = -1; + glusterd_conf_t *conf = NULL; + char op_version_str[15] = { + 0, + }; + char path[PATH_MAX] = { + 0, + }; + gf_store_handle_t *handle = NULL; + int32_t len = 0; + + conf = this->private; + + len = snprintf(path, PATH_MAX, "%s/%s", conf->workdir, + GLUSTERD_UPGRADE_FILE); + if ((len < 0) || (len >= PATH_MAX)) { + goto out; + } + ret = gf_store_handle_new(path, &handle); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_HANDLE_GET_FAIL, + "Unable to get store handle"); + goto out; + } + + /* These options need to be available for all users */ + ret = sys_chmod(handle->path, 0644); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, + "chmod error for %s", GLUSTERD_UPGRADE_FILE); + goto out; + } + + handle->fd = gf_store_mkstemp(handle); + if (handle->fd < 0) { + ret = -1; + goto out; + } + + snprintf(op_version_str, sizeof(op_version_str), "%d", GD_OP_VERSION_MAX); + ret = gf_store_save_value(handle->fd, GD_MAX_OP_VERSION_KEY, + op_version_str); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_OP_VERS_STORE_FAIL, + "Storing op-version failed ret = %d", ret); + goto out; + } + + ret = gf_store_rename_tmppath(handle); +out: + if (handle) { + if (ret && (handle->fd >= 0)) + gf_store_unlink_tmppath(handle); + } + + if (ret) + gf_msg(this->name, GF_LOG_ERROR, 0, + GD_MSG_GLUSTERD_GLOBAL_INFO_STORE_FAIL, + "Failed to store max op-version"); + if (handle) + gf_store_handle_destroy(handle); + return ret; +} - ret = stat (path, &statbuf); - if (ret) { - gf_log ("glusterd", GF_LOG_ERROR, "Unable to retrieve store " - "handle for %s, error: %s", path, strerror (errno)); - goto out; - } - ret = glusterd_store_handle_new (path, handle); +int +glusterd_retrieve_max_op_version(xlator_t *this, int *op_version) +{ + char *op_version_str = NULL; + glusterd_conf_t *priv = NULL; + int ret = -1; + int tmp_version = 0; + char *tmp = NULL; + char path[PATH_MAX] = { + 0, + }; + gf_store_handle_t *handle = NULL; + int32_t len = 0; + + priv = this->private; + + len = snprintf(path, PATH_MAX, "%s/%s", priv->workdir, + GLUSTERD_UPGRADE_FILE); + if ((len < 0) || (len >= PATH_MAX)) { + goto out; + } + ret = gf_store_handle_retrieve(path, &handle); + + if (ret) { + gf_msg_debug(this->name, 0, + "Unable to get store " + "handle!"); + goto out; + } + + ret = gf_store_retrieve_value(handle, GD_MAX_OP_VERSION_KEY, + &op_version_str); + if (ret) { + gf_msg_debug(this->name, 0, "No previous op_version present"); + goto out; + } + + tmp_version = strtol(op_version_str, &tmp, 10); + if ((tmp_version <= 0) || (tmp && strlen(tmp) > 1)) { + gf_msg(this->name, GF_LOG_WARNING, EINVAL, GD_MSG_UNSUPPORTED_VERSION, + "invalid version number"); + goto out; + } + + *op_version = tmp_version; + + ret = 0; out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; + if (op_version_str) + GF_FREE(op_version_str); + if (handle) + gf_store_handle_destroy(handle); + return ret; } -int32_t -glusterd_store_handle_destroy (glusterd_store_handle_t *handle) +int +glusterd_retrieve_op_version(xlator_t *this, int *op_version) { - int32_t ret = -1; + char *op_version_str = NULL; + glusterd_conf_t *priv = NULL; + int ret = -1; + int tmp_version = 0; + char *tmp = NULL; + char path[PATH_MAX] = { + 0, + }; + gf_store_handle_t *handle = NULL; + int32_t len = 0; + + priv = this->private; + + if (!priv->handle) { + len = snprintf(path, PATH_MAX, "%s/%s", priv->workdir, + GLUSTERD_INFO_FILE); + if ((len < 0) || (len >= PATH_MAX)) { + goto out; + } + ret = gf_store_handle_retrieve(path, &handle); - if (!handle) { - ret = 0; - goto out; + if (ret) { + gf_msg_debug(this->name, 0, + "Unable to get store " + "handle!"); + goto out; } - GF_FREE (handle->path); + priv->handle = handle; + } - GF_FREE (handle); + ret = gf_store_retrieve_value(priv->handle, GD_OP_VERSION_KEY, + &op_version_str); + if (ret) { + gf_msg_debug(this->name, 0, "No previous op_version present"); + goto out; + } - ret = 0; + tmp_version = strtol(op_version_str, &tmp, 10); + if ((tmp_version <= 0) || (tmp && strlen(tmp) > 1)) { + gf_msg(this->name, GF_LOG_WARNING, EINVAL, GD_MSG_UNSUPPORTED_VERSION, + "invalid version number"); + goto out; + } + + *op_version = tmp_version; + ret = 0; out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + if (op_version_str) + GF_FREE(op_version_str); - return ret; + return ret; } -int32_t -glusterd_store_uuid () +int +glusterd_restore_op_version(xlator_t *this) { - glusterd_conf_t *priv = NULL; - char path[PATH_MAX] = {0,}; - int32_t ret = -1; - glusterd_store_handle_t *handle = NULL; - - priv = THIS->private; - - snprintf (path, PATH_MAX, "%s/%s", priv->workdir, - GLUSTERD_INFO_FILE); - - if (!priv->handle) { - ret = glusterd_store_handle_new (path, &handle); - - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to get store" - " handle!"); - goto out; - } - - priv->handle = handle; - } else { - handle = priv->handle; + glusterd_conf_t *conf = NULL; + int ret = 0; + int op_version = 0; + + conf = this->private; + + ret = glusterd_retrieve_op_version(this, &op_version); + if (!ret) { + if ((op_version < GD_OP_VERSION_MIN) || + (op_version > GD_OP_VERSION_MAX)) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_UNSUPPORTED_VERSION, + "wrong op-version (%d) retrieved", op_version); + ret = -1; + goto out; } + conf->op_version = op_version; + gf_msg("glusterd", GF_LOG_INFO, 0, GD_MSG_OP_VERS_INFO, + "retrieved op-version: %d", conf->op_version); + goto out; + } + + /* op-version can be missing from the store file in 2 cases, + * 1. This is a new install of glusterfs + * 2. This is an upgrade of glusterfs from a version without op-version + * to a version with op-version (eg. 3.3 -> 3.4) + * + * Detection of a new install or an upgrade from an older install can be + * done by checking for the presence of the its peer-id in the store + * file. If peer-id is present, the installation is an upgrade else, it + * is a new install. + * + * For case 1, set op-version to GD_OP_VERSION_MAX. + * For case 2, set op-version to GD_OP_VERSION_MIN. + */ + ret = glusterd_retrieve_uuid(); + if (ret) { + gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_OP_VERS_SET_INFO, + "Detected new install. Setting" + " op-version to maximum : %d", + GD_OP_VERSION_MAX); + conf->op_version = GD_OP_VERSION_MAX; + } else { + gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_OP_VERS_SET_INFO, + "Upgrade detected. Setting" + " op-version to minimum : %d", + GD_OP_VERSION_MIN); + conf->op_version = GD_OP_VERSION_MIN; + } + ret = 0; +out: + return ret; +} - handle->fd = open (handle->path, O_RDWR | O_CREAT | O_TRUNC, 0644); - if (handle->fd <= 0) { - ret = -1; - goto out; +int32_t +glusterd_retrieve_uuid() +{ + char *uuid_str = NULL; + int32_t ret = -1; + gf_store_handle_t *handle = NULL; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + char path[PATH_MAX] = { + 0, + }; + int32_t len = 0; + + this = THIS; + priv = this->private; + + if (!priv->handle) { + len = snprintf(path, PATH_MAX, "%s/%s", priv->workdir, + GLUSTERD_INFO_FILE); + if ((len < 0) || (len >= PATH_MAX)) { + goto out; } - ret = glusterd_store_save_value (handle->fd, GLUSTERD_STORE_UUID_KEY, - uuid_utoa (priv->uuid)); + ret = gf_store_handle_retrieve(path, &handle); if (ret) { - gf_log ("", GF_LOG_CRITICAL, "Storing uuid failed" - "ret = %d", ret); - goto out; + gf_msg_debug(this->name, 0, + "Unable to get store" + "handle!"); + goto out; } + priv->handle = handle; + } + pthread_mutex_lock(&priv->mutex); + { + ret = gf_store_retrieve_value(priv->handle, GLUSTERD_STORE_UUID_KEY, + &uuid_str); + } + pthread_mutex_unlock(&priv->mutex); + if (ret) { + gf_msg_debug(this->name, 0, "No previous uuid is present"); + goto out; + } + + gf_uuid_parse(uuid_str, priv->uuid); out: - if (handle->fd > 0) { - close (handle->fd); - handle->fd = 0; - } - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; + GF_FREE(uuid_str); + gf_msg_debug(this->name, 0, "Returning %d", ret); + return ret; } -int32_t -glusterd_retrieve_uuid () +int +glusterd_store_retrieve_snapd(glusterd_volinfo_t *volinfo) { - char *uuid_str = NULL; - int32_t ret = -1; - glusterd_store_handle_t *handle = NULL; - glusterd_conf_t *priv = NULL; - char path[PATH_MAX] = {0,}; - - priv = THIS->private; - - - if (!priv->handle) { - snprintf (path, PATH_MAX, "%s/%s", priv->workdir, - GLUSTERD_INFO_FILE); - ret = glusterd_store_handle_retrieve (path, &handle); - - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to get store " - "handle!"); - goto out; - } - - priv->handle = handle; + int ret = -1; + char *key = NULL; + char *value = NULL; + char volpath[PATH_MAX] = { + 0, + }; + char path[PATH_MAX] = { + 0, + }; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + gf_store_iter_t *iter = NULL; + gf_store_op_errno_t op_errno = GD_STORE_SUCCESS; + int32_t len = 0; + + this = THIS; + GF_ASSERT(this); + conf = THIS->private; + GF_ASSERT(volinfo); + + if (conf->op_version < GD_OP_VERSION_3_6_0) { + ret = 0; + goto out; + } + + /* + * This is needed for upgrade situations. Say a volume is created with + * older version of glusterfs and upgraded to a glusterfs version equal + * to or greater than GD_OP_VERSION_3_6_0. The older glusterd would not + * have created the snapd.info file related to snapshot daemon for user + * serviceable snapshots. So as part of upgrade when the new glusterd + * starts, as part of restore (restoring the volume to be precise), it + * tries to snapd related info from snapd.info file. But since there was + * no such file till now, the restore operation fails. Thus, to prevent + * it from happening check whether user serviceable snapshots features + * is enabled before restoring snapd. If its disabled, then simply + * exit by returning success (without even checking for the snapd.info). + */ + + if (!dict_get_str_boolean(volinfo->dict, "features.uss", _gf_false)) { + ret = 0; + goto out; + } + + GLUSTERD_GET_VOLUME_DIR(volpath, volinfo, conf); + + len = snprintf(path, sizeof(path), "%s/%s", volpath, + GLUSTERD_VOLUME_SNAPD_INFO_FILE); + if ((len < 0) || (len >= sizeof(path))) { + goto out; + } + + ret = gf_store_handle_retrieve(path, &volinfo->snapd.handle); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_HANDLE_NULL, + "volinfo handle is NULL"); + goto out; + } + + ret = gf_store_iter_new(volinfo->snapd.handle, &iter); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_ITER_GET_FAIL, + "Failed to get new store " + "iter"); + goto out; + } + + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_ITER_GET_FAIL, + "Failed to get next store " + "iter"); + goto out; + } + + while (!ret) { + if (!strncmp(key, GLUSTERD_STORE_KEY_SNAPD_PORT, + SLEN(GLUSTERD_STORE_KEY_SNAPD_PORT))) { + volinfo->snapd.port = atoi(value); } - ret = glusterd_store_retrieve_value (priv->handle, - GLUSTERD_STORE_UUID_KEY, - &uuid_str); + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + } - if (ret) { - gf_log ("", GF_LOG_INFO, "No previous uuid is present"); - goto out; - } + if (op_errno != GD_STORE_EOF) + goto out; - uuid_parse (uuid_str, priv->uuid); + ret = 0; out: - if (uuid_str) - GF_FREE (uuid_str); - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; + if (gf_store_iter_destroy(&iter)) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_ITER_DESTROY_FAIL, + "Failed to destroy store iter"); + ret = -1; + } + + return ret; } int32_t -glusterd_store_iter_new (glusterd_store_handle_t *shandle, - glusterd_store_iter_t **iter) +glusterd_store_retrieve_bricks(glusterd_volinfo_t *volinfo) { - int32_t ret = -1; - glusterd_store_iter_t *tmp_iter = NULL; - int fd = -1; + int32_t ret = 0; + glusterd_brickinfo_t *brickinfo = NULL; + glusterd_brickinfo_t *ta_brickinfo = NULL; + gf_store_iter_t *iter = NULL; + char *key = NULL; + char *value = NULL; + char brickdir[PATH_MAX] = { + 0, + }; + char path[PATH_MAX] = { + 0, + }; + glusterd_conf_t *priv = NULL; + int32_t brick_count = 0; + int32_t ta_brick_count = 0; + char tmpkey[32] = { + 0, + }; + gf_store_iter_t *tmpiter = NULL; + char *tmpvalue = NULL; + char abspath[PATH_MAX] = {0}; + struct pmap_registry *pmap = NULL; + xlator_t *this = NULL; + int brickid = 0; + /* ta_brick_id initialization with 2 since ta-brick id starts with + * volname-ta-2 + */ + int ta_brick_id = 2; + gf_store_op_errno_t op_errno = GD_STORE_SUCCESS; + int32_t len = 0; + + GF_ASSERT(volinfo); + GF_ASSERT(volinfo->volname); + + this = THIS; + priv = this->private; + + GLUSTERD_GET_BRICK_DIR(brickdir, volinfo, priv); + + ret = gf_store_iter_new(volinfo->shandle, &tmpiter); + + if (ret) + goto out; + + while (brick_count < volinfo->brick_count) { + ret = glusterd_brickinfo_new(&brickinfo); - GF_ASSERT (shandle); - GF_ASSERT (iter); + if (ret) + goto out; + snprintf(tmpkey, sizeof(tmpkey), "%s-%d", GLUSTERD_STORE_KEY_VOL_BRICK, + brick_count); + ret = gf_store_iter_get_matching(tmpiter, tmpkey, &tmpvalue); + len = snprintf(path, sizeof(path), "%s/%s", brickdir, tmpvalue); + GF_FREE(tmpvalue); + tmpvalue = NULL; + if ((len < 0) || (len >= sizeof(path))) { + ret = -1; + goto out; + } - tmp_iter = GF_CALLOC (1, sizeof (*tmp_iter), - gf_gld_mt_store_iter_t); + ret = gf_store_handle_retrieve(path, &brickinfo->shandle); - if (!tmp_iter) { - gf_log ("", GF_LOG_ERROR, "Out of Memory"); - goto out; - } + if (ret) + goto out; - fd = open (shandle->path, O_RDWR); + ret = gf_store_iter_new(brickinfo->shandle, &iter); - if (fd < 0) { - gf_log ("", GF_LOG_ERROR, "Unable to open %s, errno: %d", - shandle->path, errno); - goto out; + if (ret) + goto out; + + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + if (ret) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_STORE_ITER_GET_FAIL, + "Unable to iterate " + "the store for brick: %s", + path); + goto out; } + while (!ret) { + if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_HOSTNAME, + SLEN(GLUSTERD_STORE_KEY_BRICK_HOSTNAME))) { + if (snprintf(brickinfo->hostname, sizeof(brickinfo->hostname), + "%s", value) >= sizeof(brickinfo->hostname)) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, + "brick hostname truncated: %s", brickinfo->hostname); + goto out; + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_PATH, + SLEN(GLUSTERD_STORE_KEY_BRICK_PATH))) { + if (snprintf(brickinfo->path, sizeof(brickinfo->path), "%s", + value) >= sizeof(brickinfo->path)) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, + "brick path truncated: %s", brickinfo->path); + goto out; + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_REAL_PATH, + SLEN(GLUSTERD_STORE_KEY_BRICK_REAL_PATH))) { + if (snprintf(brickinfo->real_path, sizeof(brickinfo->real_path), + "%s", value) >= sizeof(brickinfo->real_path)) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, + "real_path truncated: %s", brickinfo->real_path); + goto out; + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_PORT, + SLEN(GLUSTERD_STORE_KEY_BRICK_PORT))) { + ret = gf_string2int(value, &brickinfo->port); + if (ret == -1) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, + GD_MSG_INCOMPATIBLE_VALUE, + "Failed to convert " + "string to integer"); + } - tmp_iter->fd = fd; + if (brickinfo->port < priv->base_port) { + /* This is required to adhere to the + IANA standards */ + brickinfo->port = 0; + } else { + /* This is required to have proper ports + assigned to bricks after restart */ + pmap = pmap_registry_get(THIS); + if (pmap->last_alloc <= brickinfo->port) + pmap->last_alloc = brickinfo->port + 1; + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_RDMA_PORT, + SLEN(GLUSTERD_STORE_KEY_BRICK_RDMA_PORT))) { + ret = gf_string2int(value, &brickinfo->rdma_port); + if (ret == -1) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, + GD_MSG_INCOMPATIBLE_VALUE, + "Failed to convert " + "string to integer"); + } - tmp_iter->file = fdopen (tmp_iter->fd, "r"); + if (brickinfo->rdma_port < priv->base_port) { + /* This is required to adhere to the + IANA standards */ + brickinfo->rdma_port = 0; + } else { + /* This is required to have proper ports + assigned to bricks after restart */ + pmap = pmap_registry_get(THIS); + if (pmap->last_alloc <= brickinfo->rdma_port) + pmap->last_alloc = brickinfo->rdma_port + 1; + } - if (!tmp_iter->file) { - gf_log ("", GF_LOG_ERROR, "Unable to open file %s errno: %d", - shandle->path, errno); - goto out; - } + } else if (!strncmp( + key, GLUSTERD_STORE_KEY_BRICK_DECOMMISSIONED, + SLEN(GLUSTERD_STORE_KEY_BRICK_DECOMMISSIONED))) { + ret = gf_string2int(value, &brickinfo->decommissioned); + if (ret == -1) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, + GD_MSG_INCOMPATIBLE_VALUE, + "Failed to convert " + "string to integer"); + } - strncpy (tmp_iter->filepath, shandle->path, sizeof (tmp_iter->filepath)); - *iter = tmp_iter; - ret = 0; + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_DEVICE_PATH, + SLEN(GLUSTERD_STORE_KEY_BRICK_DEVICE_PATH))) { + if (snprintf(brickinfo->device_path, + sizeof(brickinfo->device_path), "%s", + value) >= sizeof(brickinfo->device_path)) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, + "device_path truncated: %s", brickinfo->device_path); + goto out; + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_MOUNT_DIR, + SLEN(GLUSTERD_STORE_KEY_BRICK_MOUNT_DIR))) { + if (snprintf(brickinfo->mount_dir, sizeof(brickinfo->mount_dir), + "%s", value) >= sizeof(brickinfo->mount_dir)) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, + "mount_dir truncated: %s", brickinfo->mount_dir); + goto out; + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_SNAP_STATUS, + SLEN(GLUSTERD_STORE_KEY_BRICK_SNAP_STATUS))) { + ret = gf_string2int(value, &brickinfo->snap_status); + if (ret == -1) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, + GD_MSG_INCOMPATIBLE_VALUE, + "Failed to convert " + "string to integer"); + } -out: - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); - return ret; -} + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_FSTYPE, + SLEN(GLUSTERD_STORE_KEY_BRICK_FSTYPE))) { + if (snprintf(brickinfo->fstype, sizeof(brickinfo->fstype), "%s", + value) >= sizeof(brickinfo->fstype)) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, "fstype truncated: %s", + brickinfo->fstype); + goto out; + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_MNTOPTS, + SLEN(GLUSTERD_STORE_KEY_BRICK_MNTOPTS))) { + if (snprintf(brickinfo->mnt_opts, sizeof(brickinfo->mnt_opts), + "%s", value) >= sizeof(brickinfo->mnt_opts)) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, + "mnt_opts truncated: %s", brickinfo->mnt_opts); + goto out; + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_VGNAME, + SLEN(GLUSTERD_STORE_KEY_BRICK_VGNAME))) { + if (snprintf(brickinfo->vg, sizeof(brickinfo->vg), "%s", + value) >= sizeof(brickinfo->vg)) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, + "brickinfo->vg truncated: %s", brickinfo->vg); + goto out; + } + } else if (!strcmp(key, GLUSTERD_STORE_KEY_BRICK_ID)) { + if (snprintf(brickinfo->brick_id, sizeof(brickinfo->brick_id), + "%s", value) >= sizeof(brickinfo->brick_id)) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, + "brick_id truncated: %s", brickinfo->brick_id); + goto out; + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_FSID, + SLEN(GLUSTERD_STORE_KEY_BRICK_FSID))) { + ret = gf_string2uint64(value, &brickinfo->statfs_fsid); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY, + "%s " + "is not a valid uint64_t value", + value); + } -int32_t -glusterd_store_validate_key_value (char *storepath, char *key, char*val, - glusterd_store_op_errno_t *op_errno) -{ - int ret = 0; + } else if (!strcmp(key, GLUSTERD_STORE_KEY_BRICK_UUID)) { + gf_uuid_parse(value, brickinfo->uuid); + } else { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_UNKNOWN_KEY, + "Unknown key: %s", key); + } - GF_ASSERT (op_errno); - GF_ASSERT (storepath); + GF_FREE(key); + GF_FREE(value); + key = NULL; + value = NULL; - if ((key == NULL) && (val == NULL)) { - ret = -1; - gf_log ("glusterd", GF_LOG_ERROR, "Glusterd store may be " - "corrupted, Invalid key and value (null) in %s", - storepath); - *op_errno = GD_STORE_KEY_VALUE_NULL; - } else if (key == NULL) { - ret = -1; - gf_log ("glusterd", GF_LOG_ERROR, "Glusterd store may be " - "corrupted, Invalid key (null) in %s", storepath); - *op_errno = GD_STORE_KEY_NULL; - } else if (val == NULL) { - ret = -1; - gf_log ("glusterd", GF_LOG_ERROR, "Glusterd store may be " - "corrupted, Invalid value (null) for key %s in %s", - key, storepath); - *op_errno = GD_STORE_VALUE_NULL; - } else { - ret = 0; - *op_errno = GD_STORE_SUCCESS; + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); } - return ret; -} + if (op_errno != GD_STORE_EOF) { + gf_msg(this->name, GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, + "Error parsing brickinfo: " + "op_errno=%d", + op_errno); + goto out; + } -int32_t -glusterd_store_iter_get_next (glusterd_store_iter_t *iter, - char **key, char **value, - glusterd_store_op_errno_t *op_errno) -{ - int32_t ret = -1; - char *scan_str = NULL; - char *free_str = NULL; - char *iter_key = NULL; - char *iter_val = NULL; - struct stat st = {0,}; - glusterd_store_op_errno_t store_errno = GD_STORE_SUCCESS; - - GF_ASSERT (iter); - GF_ASSERT (iter->file); - GF_ASSERT (key); - GF_ASSERT (value); - - ret = fstat (iter->fd, &st); - if (ret < 0) { - gf_log ("glusterd", GF_LOG_WARNING, - "stat on file failed"); - ret = -1; - store_errno = GD_STORE_STAT_FAILED; - goto out; + if (brickinfo->brick_id[0] == '\0') { + /* This is an old volume upgraded to op_version 4 */ + GLUSTERD_ASSIGN_BRICKID_TO_BRICKINFO(brickinfo, volinfo, brickid++); + } + /* Populate brickinfo->real_path for normal volumes, for + * snapshot or snapshot restored volume this would be done post + * creating the brick mounts + */ + if (gf_uuid_is_null(brickinfo->uuid)) + (void)glusterd_resolve_brick(brickinfo); + if (brickinfo->real_path[0] == '\0' && !volinfo->is_snap_volume && + gf_uuid_is_null(volinfo->restored_from_snap)) { + /* By now if the brick is a local brick then it will be + * able to resolve which is the only thing we want now + * for checking whether the brickinfo->uuid matches + * with MY_UUID for realpath check. Hence do not handle + * error + */ + if (!gf_uuid_compare(brickinfo->uuid, MY_UUID)) { + if (!realpath(brickinfo->path, abspath)) { + gf_msg(this->name, GF_LOG_CRITICAL, errno, + GD_MSG_BRICKINFO_CREATE_FAIL, + "realpath() failed for brick %s" + ". The underlying file system " + "may be in bad state", + brickinfo->path); + ret = -1; + goto out; + } + if (strlen(abspath) >= sizeof(brickinfo->real_path)) { + ret = -1; + goto out; + } + (void)strncpy(brickinfo->real_path, abspath, + sizeof(brickinfo->real_path)); + } } - scan_str = GF_CALLOC (1, st.st_size, - gf_gld_mt_char); - if (scan_str == NULL) { - ret = -1; - store_errno = GD_STORE_ENOMEM; - goto out; + /* Handle upgrade case of shared_brick_count 'fsid' */ + /* Ideally statfs_fsid should never be 0 if done right */ + if (!gf_uuid_compare(brickinfo->uuid, MY_UUID) && + brickinfo->statfs_fsid == 0) { + struct statvfs brickstat = { + 0, + }; + ret = sys_statvfs(brickinfo->path, &brickstat); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, errno, + GD_MSG_BRICKINFO_CREATE_FAIL, + "failed to get statfs() call on brick %s", + brickinfo->path); + /* No need for treating it as an error, lets continue + with just a message */ + } else { + brickinfo->statfs_fsid = brickstat.f_fsid; + } } - *key = NULL; - *value = NULL; + cds_list_add_tail(&brickinfo->brick_list, &volinfo->bricks); + brick_count++; + } - free_str = scan_str; + if (gf_store_iter_destroy(&tmpiter)) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_ITER_DESTROY_FAIL, + "Failed to destroy store iter"); + ret = -1; + goto out; + } - ret = glusterd_store_read_and_tokenize (iter->file, scan_str, - &iter_key, &iter_val, - &store_errno); - if (ret < 0) { - goto out; - } + ret = gf_store_iter_new(volinfo->shandle, &tmpiter); + if (ret) + goto out; - ret = glusterd_store_validate_key_value (iter->filepath, iter_key, - iter_val, &store_errno); - if (ret) + if (volinfo->thin_arbiter_count == 1) { + snprintf(tmpkey, sizeof(tmpkey), "%s-%d", + GLUSTERD_STORE_KEY_VOL_TA_BRICK, 0); + while (ta_brick_count < volinfo->subvol_count) { + ret = glusterd_brickinfo_new(&ta_brickinfo); + if (ret) goto out; - *value = gf_strdup (iter_val); + ret = gf_store_iter_get_matching(tmpiter, tmpkey, &tmpvalue); - *key = gf_strdup (iter_key); - if (!iter_key || !iter_val) { + len = snprintf(path, sizeof(path), "%s/%s", brickdir, tmpvalue); + GF_FREE(tmpvalue); + tmpvalue = NULL; + if ((len < 0) || (len >= sizeof(path))) { ret = -1; - store_errno = GD_STORE_ENOMEM; goto out; - } + } - ret = 0; + ret = gf_store_handle_retrieve(path, &ta_brickinfo->shandle); -out: - if (ret) { - if (*key) { - GF_FREE (*key); - *key = NULL; - } - if (*value) { - GF_FREE (*value); - *value = NULL; - } - } - if (free_str) - GF_FREE (free_str); - if (op_errno) - *op_errno = store_errno; + if (ret) + goto out; - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); - return ret; -} + ret = gf_store_iter_new(ta_brickinfo->shandle, &iter); -int32_t -glusterd_store_iter_get_matching (glusterd_store_iter_t *iter, - char *key, char **value) -{ - int32_t ret = -1; - char *tmp_key = NULL; - char *tmp_value = NULL; + if (ret) + goto out; - ret = glusterd_store_iter_get_next (iter, &tmp_key, &tmp_value, - NULL); - while (!ret) { - if (!strncmp (key, tmp_key, strlen (key))){ - *value = tmp_value; - GF_FREE (tmp_key); + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + if (ret) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_STORE_ITER_GET_FAIL, + "Unable to iterate " + "the store for brick: %s", + path); + goto out; + } + + while (!ret) { + if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_HOSTNAME, + SLEN(GLUSTERD_STORE_KEY_BRICK_HOSTNAME))) { + if (snprintf(ta_brickinfo->hostname, + sizeof(ta_brickinfo->hostname), "%s", + value) >= sizeof(ta_brickinfo->hostname)) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, + "brick hostname truncated: %s", + ta_brickinfo->hostname); goto out; - } - GF_FREE (tmp_key); - GF_FREE (tmp_value); - ret = glusterd_store_iter_get_next (iter, &tmp_key, - &tmp_value, NULL); - } -out: - return ret; -} + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_PATH, + SLEN(GLUSTERD_STORE_KEY_BRICK_PATH))) { + if (snprintf(ta_brickinfo->path, sizeof(ta_brickinfo->path), + "%s", value) >= sizeof(ta_brickinfo->path)) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, + "brick path truncated: %s", ta_brickinfo->path); + goto out; + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_REAL_PATH, + SLEN(GLUSTERD_STORE_KEY_BRICK_REAL_PATH))) { + if (snprintf(ta_brickinfo->real_path, + sizeof(ta_brickinfo->real_path), "%s", + value) >= sizeof(ta_brickinfo->real_path)) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, + "real_path truncated: %s", + ta_brickinfo->real_path); + goto out; + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_PORT, + SLEN(GLUSTERD_STORE_KEY_BRICK_PORT))) { + ret = gf_string2int(value, &ta_brickinfo->port); + if (ret == -1) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, + GD_MSG_INCOMPATIBLE_VALUE, + "Failed to convert " + "string to integer"); + } + + if (ta_brickinfo->port < priv->base_port) { + /* This is required to adhere to the + IANA standards */ + ta_brickinfo->port = 0; + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_RDMA_PORT, + SLEN(GLUSTERD_STORE_KEY_BRICK_RDMA_PORT))) { + ret = gf_string2int(value, &ta_brickinfo->rdma_port); + if (ret == -1) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, + GD_MSG_INCOMPATIBLE_VALUE, + "Failed to convert " + "string to integer"); + } + + if (ta_brickinfo->rdma_port < priv->base_port) { + /* This is required to adhere to the + IANA standards */ + ta_brickinfo->rdma_port = 0; + } + } else if (!strncmp( + key, GLUSTERD_STORE_KEY_BRICK_DECOMMISSIONED, + SLEN(GLUSTERD_STORE_KEY_BRICK_DECOMMISSIONED))) { + ret = gf_string2int(value, &ta_brickinfo->decommissioned); + if (ret == -1) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, + GD_MSG_INCOMPATIBLE_VALUE, + "Failed to convert " + "string to integer"); + } + + } else if (!strcmp(key, GLUSTERD_STORE_KEY_BRICK_ID)) { + if (snprintf(ta_brickinfo->brick_id, + sizeof(ta_brickinfo->brick_id), "%s", + value) >= sizeof(ta_brickinfo->brick_id)) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, + "brick_id truncated: %s", + ta_brickinfo->brick_id); + goto out; + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_BRICK_FSID, + SLEN(GLUSTERD_STORE_KEY_BRICK_FSID))) { + ret = gf_string2uint64(value, &ta_brickinfo->statfs_fsid); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, + GD_MSG_INVALID_ENTRY, + "%s " + "is not a valid uint64_t value", + value); + } + } else if (!strcmp(key, GLUSTERD_STORE_KEY_BRICK_UUID)) { + gf_uuid_parse(value, brickinfo->uuid); + } else if (!strncmp( + key, GLUSTERD_STORE_KEY_BRICK_SNAP_STATUS, + SLEN(GLUSTERD_STORE_KEY_BRICK_SNAP_STATUS))) { + ret = gf_string2int(value, &ta_brickinfo->snap_status); + if (ret == -1) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, + GD_MSG_INCOMPATIBLE_VALUE, + "Failed to convert " + "string to integer"); + } -int32_t -glusterd_store_iter_destroy (glusterd_store_iter_t *iter) -{ - int32_t ret = -1; + } else { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_UNKNOWN_KEY, + "Unknown key: %s", key); + } - GF_ASSERT (iter); - GF_ASSERT (iter->fd > 0); + GF_FREE(key); + GF_FREE(value); + key = NULL; + value = NULL; + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + } - ret = fclose (iter->file); + GLUSTERD_ASSIGN_BRICKID_TO_TA_BRICKINFO(ta_brickinfo, volinfo, + ta_brick_id); + ta_brick_id += 3; - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to close fd: %d, ret: %d, " - "errno: %d" ,iter->fd, ret, errno); + cds_list_add_tail(&ta_brickinfo->brick_list, &volinfo->ta_bricks); + ta_brick_count++; } + } - GF_FREE (iter); + assign_brick_groups(volinfo); + ret = 0; - return ret; -} +out: + if (gf_store_iter_destroy(&tmpiter)) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_ITER_DESTROY_FAIL, + "Failed to destroy store iter"); + ret = -1; + } -char* -glusterd_store_strerror (glusterd_store_op_errno_t op_errno) -{ - switch (op_errno) { - case GD_STORE_SUCCESS: - return "Success"; - case GD_STORE_KEY_NULL: - return "Invalid Key"; - case GD_STORE_VALUE_NULL: - return "Invalid Value"; - case GD_STORE_KEY_VALUE_NULL: - return "Invalid Key and Value"; - case GD_STORE_EOF: - return "No data"; - case GD_STORE_ENOMEM: - return "No memory"; - default: - return "Invalid errno"; - } - return "Invalid errno"; + if (gf_store_iter_destroy(&iter)) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_ITER_DESTROY_FAIL, + "Failed to destroy store iter"); + ret = -1; + } + + gf_msg_debug(this->name, 0, "Returning with %d", ret); + + return ret; } int32_t -glusterd_store_retrieve_bricks (glusterd_volinfo_t *volinfo) +glusterd_store_retrieve_node_state(glusterd_volinfo_t *volinfo) { + int32_t ret = -1; + gf_store_iter_t *iter = NULL; + char *key = NULL; + char *value = NULL; + char *dup_value = NULL; + char volpath[PATH_MAX] = { + 0, + }; + glusterd_conf_t *priv = NULL; + char path[PATH_MAX] = { + 0, + }; + gf_store_op_errno_t op_errno = GD_STORE_SUCCESS; + dict_t *tmp_dict = NULL; + xlator_t *this = NULL; + int32_t len = 0; + + this = THIS; + GF_ASSERT(this); + priv = this->private; + GF_ASSERT(priv); + GF_ASSERT(volinfo); + + GLUSTERD_GET_VOLUME_DIR(volpath, volinfo, priv); + len = snprintf(path, sizeof(path), "%s/%s", volpath, + GLUSTERD_NODE_STATE_FILE); + if ((len < 0) || (len >= PATH_MAX)) { + goto out; + } + + ret = gf_store_handle_retrieve(path, &volinfo->node_state_shandle); + if (ret) + goto out; + + ret = gf_store_iter_new(volinfo->node_state_shandle, &iter); + + if (ret) + goto out; + + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + + if (ret) + goto out; + + while (ret == 0) { + if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_DEFRAG, + SLEN(GLUSTERD_STORE_KEY_VOL_DEFRAG))) { + volinfo->rebal.defrag_cmd = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_DEFRAG_STATUS, + SLEN(GLUSTERD_STORE_KEY_VOL_DEFRAG_STATUS))) { + volinfo->rebal.defrag_status = atoi(value); + } else if (!strncmp(key, GF_REBALANCE_TID_KEY, + SLEN(GF_REBALANCE_TID_KEY))) { + gf_uuid_parse(value, volinfo->rebal.rebalance_id); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_DEFRAG_OP, + SLEN(GLUSTERD_STORE_KEY_DEFRAG_OP))) { + volinfo->rebal.op = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_DEFRAG_REB_FILES, + SLEN(GLUSTERD_STORE_KEY_VOL_DEFRAG_REB_FILES))) { + sscanf(value, "%" PRIu64, &volinfo->rebal.rebalance_files); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_DEFRAG_SIZE, + SLEN(GLUSTERD_STORE_KEY_VOL_DEFRAG_SIZE))) { + sscanf(value, "%" PRIu64, &volinfo->rebal.rebalance_data); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_DEFRAG_SCANNED, + SLEN(GLUSTERD_STORE_KEY_VOL_DEFRAG_SCANNED))) { + sscanf(value, "%" PRIu64, &volinfo->rebal.lookedup_files); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_DEFRAG_FAILURES, + SLEN(GLUSTERD_STORE_KEY_VOL_DEFRAG_FAILURES))) { + sscanf(value, "%" PRIu64, &volinfo->rebal.rebalance_failures); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_DEFRAG_SKIPPED, + SLEN(GLUSTERD_STORE_KEY_VOL_DEFRAG_SKIPPED))) { + sscanf(value, "%" PRIu64, &volinfo->rebal.skipped_files); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_DEFRAG_RUN_TIME, + SLEN(GLUSTERD_STORE_KEY_VOL_DEFRAG_RUN_TIME))) { + volinfo->rebal.rebalance_time = atoi(value); + } else { + if (!tmp_dict) { + tmp_dict = dict_new(); + if (!tmp_dict) { + ret = -1; + goto out; + } + } + dup_value = gf_strdup(value); + if (!dup_value) { + ret = -1; + gf_msg(this->name, GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY, + "Failed to strdup value string"); + goto out; + } + ret = dict_set_str(tmp_dict, key, dup_value); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED, + "Error setting data in rebal " + "dict."); + goto out; + } + dup_value = NULL; + } - int32_t ret = 0; - glusterd_brickinfo_t *brickinfo = NULL; - glusterd_store_iter_t *iter = NULL; - char *key = NULL; - char *value = NULL; - char brickdir[PATH_MAX] = {0,}; - char path[PATH_MAX] = {0,}; - glusterd_conf_t *priv = NULL; - int32_t brick_count = 0; - char tmpkey[4096] = {0,}; - glusterd_store_iter_t *tmpiter = NULL; - char *tmpvalue = NULL; - struct pmap_registry *pmap = NULL; - glusterd_store_op_errno_t op_errno = GD_STORE_SUCCESS; + GF_FREE(key); + GF_FREE(value); + key = NULL; + value = NULL; - GF_ASSERT (volinfo); - GF_ASSERT (volinfo->volname); + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + } + if (tmp_dict) { + volinfo->rebal.dict = dict_ref(tmp_dict); + } - priv = THIS->private; + if (op_errno != GD_STORE_EOF) { + ret = -1; + goto out; + } - GLUSTERD_GET_BRICK_DIR (brickdir, volinfo, priv) + ret = 0; - ret = glusterd_store_iter_new (volinfo->shandle, &tmpiter); +out: + if (gf_store_iter_destroy(&iter)) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_ITER_DESTROY_FAIL, + "Failed to destroy store iter"); + ret = -1; + } + + if (dup_value) + GF_FREE(dup_value); + if (ret) { + if (volinfo->rebal.dict) + dict_unref(volinfo->rebal.dict); + } + if (tmp_dict) + dict_unref(tmp_dict); + + gf_msg_trace(this->name, 0, "Returning with %d", ret); + + return ret; +} - if (ret) +int +glusterd_store_update_volinfo(glusterd_volinfo_t *volinfo) +{ + int ret = -1; + int exists = 0; + char *key = NULL; + char *value = NULL; + char volpath[PATH_MAX] = { + 0, + }; + char path[PATH_MAX] = { + 0, + }; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + gf_store_iter_t *iter = NULL; + gf_store_op_errno_t op_errno = GD_STORE_SUCCESS; + int32_t len = 0; + + this = THIS; + GF_ASSERT(this); + conf = THIS->private; + GF_ASSERT(volinfo); + + GLUSTERD_GET_VOLUME_DIR(volpath, volinfo, conf); + + len = snprintf(path, sizeof(path), "%s/%s", volpath, + GLUSTERD_VOLUME_INFO_FILE); + if ((len < 0) || (len >= sizeof(path))) { + goto out; + } + + ret = gf_store_handle_retrieve(path, &volinfo->shandle); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_HANDLE_NULL, + "volinfo handle is NULL"); + goto out; + } + + ret = gf_store_iter_new(volinfo->shandle, &iter); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_ITER_GET_FAIL, + "Failed to get new store " + "iter"); + goto out; + } + + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_ITER_GET_FAIL, + "Failed to get next store " + "iter"); + goto out; + } + + while (!ret) { + gf_msg_debug(this->name, 0, "key = %s value = %s", key, value); + if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_TYPE, + SLEN(GLUSTERD_STORE_KEY_VOL_TYPE))) { + volinfo->type = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_COUNT, + SLEN(GLUSTERD_STORE_KEY_VOL_COUNT))) { + volinfo->brick_count = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_STATUS, + SLEN(GLUSTERD_STORE_KEY_VOL_STATUS))) { + volinfo->status = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_VERSION, + SLEN(GLUSTERD_STORE_KEY_VOL_VERSION))) { + volinfo->version = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_PORT, + SLEN(GLUSTERD_STORE_KEY_VOL_PORT))) { + volinfo->port = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_SUB_COUNT, + SLEN(GLUSTERD_STORE_KEY_VOL_SUB_COUNT))) { + volinfo->sub_count = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_STRIPE_CNT, + SLEN(GLUSTERD_STORE_KEY_VOL_STRIPE_CNT))) { + volinfo->stripe_count = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_REPLICA_CNT, + SLEN(GLUSTERD_STORE_KEY_VOL_REPLICA_CNT))) { + volinfo->replica_count = atoi(value); + } else if (!strcmp(key, GLUSTERD_STORE_KEY_VOL_ARBITER_CNT)) { + volinfo->arbiter_count = atoi(value); + } else if (!strcmp(key, GLUSTERD_STORE_KEY_VOL_THIN_ARBITER_CNT)) { + volinfo->thin_arbiter_count = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_DISPERSE_CNT, + SLEN(GLUSTERD_STORE_KEY_VOL_DISPERSE_CNT))) { + volinfo->disperse_count = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_REDUNDANCY_CNT, + SLEN(GLUSTERD_STORE_KEY_VOL_REDUNDANCY_CNT))) { + volinfo->redundancy_count = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_TRANSPORT, + SLEN(GLUSTERD_STORE_KEY_VOL_TRANSPORT))) { + volinfo->transport_type = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_ID, + SLEN(GLUSTERD_STORE_KEY_VOL_ID))) { + ret = gf_uuid_parse(value, volinfo->volume_id); + if (ret) + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_UUID_PARSE_FAIL, + "failed to parse uuid"); + + } else if (!strncmp(key, GLUSTERD_STORE_KEY_USERNAME, + SLEN(GLUSTERD_STORE_KEY_USERNAME))) { + glusterd_auth_set_username(volinfo, value); + + } else if (!strncmp(key, GLUSTERD_STORE_KEY_PASSWORD, + SLEN(GLUSTERD_STORE_KEY_PASSWORD))) { + glusterd_auth_set_password(volinfo, value); + + } else if (strstr(key, "slave")) { + ret = dict_set_dynstr(volinfo->gsync_slaves, key, gf_strdup(value)); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED, + "Error in " + "dict_set_str"); goto out; - - while (brick_count < volinfo->brick_count) { - ret = glusterd_brickinfo_new (&brickinfo); - - if (ret) + } + gf_msg_debug(this->name, 0, + "Parsed as " GEOREP + " " + " slave:key=%s,value:%s", + key, value); + + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_OP_VERSION, + SLEN(GLUSTERD_STORE_KEY_VOL_OP_VERSION))) { + volinfo->op_version = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_CLIENT_OP_VERSION, + SLEN(GLUSTERD_STORE_KEY_VOL_CLIENT_OP_VERSION))) { + volinfo->client_op_version = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT, + SLEN(GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT))) { + volinfo->snap_max_hard_limit = (uint64_t)atoll(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_RESTORED_SNAP, + SLEN(GLUSTERD_STORE_KEY_VOL_RESTORED_SNAP))) { + ret = gf_uuid_parse(value, volinfo->restored_from_snap); + if (ret) + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_UUID_PARSE_FAIL, + "failed to parse restored snap's uuid"); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_PARENT_VOLNAME, + SLEN(GLUSTERD_STORE_KEY_PARENT_VOLNAME))) { + if (snprintf(volinfo->parent_volname, + sizeof(volinfo->parent_volname), "%s", + value) >= sizeof(volinfo->parent_volname)) { + gf_msg("glusterd", GF_LOG_ERROR, op_errno, + GD_MSG_PARSE_BRICKINFO_FAIL, + "parent_volname truncated: %s", volinfo->parent_volname); + goto out; + } + } else if (!strncmp(key, GLUSTERD_STORE_KEY_VOL_QUOTA_VERSION, + SLEN(GLUSTERD_STORE_KEY_VOL_QUOTA_VERSION))) { + volinfo->quota_xattr_version = atoi(value); + } else { + if (is_key_glusterd_hooks_friendly(key)) { + exists = 1; + + } else { + exists = glusterd_check_option_exists(key, NULL); + } + + switch (exists) { + case -1: + ret = -1; + goto out; + + case 0: + /*Ignore GLUSTERD_STORE_KEY_VOL_BRICK since + glusterd_store_retrieve_bricks gets it later. + also, ignore tier-enabled key as we deprecated + tier xlator*/ + if (!strstr(key, GLUSTERD_STORE_KEY_VOL_BRICK) || + !strstr(key, GF_TIER_ENABLED)) + gf_msg(this->name, GF_LOG_WARNING, 0, + GD_MSG_UNKNOWN_KEY, "Unknown key: %s", key); + break; + + case 1: + /*The following strcmp check is to ensure that + * glusterd does not restore the quota limits + * into volinfo->dict post upgradation from 3.3 + * to 3.4 as the same limits will now be stored + * in xattrs on the respective directories. + */ + if (!strcmp(key, "features.limit-usage")) + break; + ret = dict_set_str(volinfo->dict, key, gf_strdup(value)); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, + GD_MSG_DICT_SET_FAILED, + "Error in " + "dict_set_str"); goto out; - snprintf (tmpkey, sizeof (tmpkey), "%s-%d", - GLUSTERD_STORE_KEY_VOL_BRICK,brick_count); - ret = glusterd_store_iter_get_matching (tmpiter, tmpkey, - &tmpvalue); - snprintf (path, sizeof (path), "%s/%s", brickdir, tmpvalue); - - GF_FREE (tmpvalue); + } + gf_msg_debug(this->name, 0, + "Parsed as Volume-" + "set:key=%s,value:%s", + key, value); + break; + } + } - tmpvalue = NULL; + GF_FREE(key); + GF_FREE(value); + key = NULL; + value = NULL; + + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + } + + /* backward compatibility */ + { + switch (volinfo->type) { + case GF_CLUSTER_TYPE_NONE: + volinfo->stripe_count = 1; + volinfo->replica_count = 1; + break; + + case GF_CLUSTER_TYPE_REPLICATE: + volinfo->stripe_count = 1; + volinfo->replica_count = volinfo->sub_count; + break; + + case GF_CLUSTER_TYPE_DISPERSE: + GF_ASSERT(volinfo->disperse_count > 0); + GF_ASSERT(volinfo->redundancy_count > 0); + break; + + case GF_CLUSTER_TYPE_STRIPE: + case GF_CLUSTER_TYPE_STRIPE_REPLICATE: + gf_msg(this->name, GF_LOG_CRITICAL, ENOTSUP, + GD_MSG_VOLINFO_STORE_FAIL, + "The volume type is no more supported. Please refer to " + "glusterfs-6.0 release-notes for how to migrate from " + "this volume type"); + break; + + default: + GF_ASSERT(0); + break; + } - ret = glusterd_store_handle_retrieve (path, &brickinfo->shandle); + volinfo->dist_leaf_count = glusterd_get_dist_leaf_count(volinfo); - if (ret) - goto out; + volinfo->subvol_count = (volinfo->brick_count / + volinfo->dist_leaf_count); - ret = glusterd_store_iter_new (brickinfo->shandle, &iter); + /* Only calculate volume op-versions if they are not found */ + if (!volinfo->op_version && !volinfo->client_op_version) + gd_update_volume_op_versions(volinfo); + } - if (ret) - goto out; + if (op_errno != GD_STORE_EOF) + goto out; - ret = glusterd_store_iter_get_next (iter, &key, &value, - &op_errno); - if (ret) { - gf_log ("glusterd", GF_LOG_ERROR, "Unable to iterate " - "the store for brick: %s, reason: %s", path, - glusterd_store_strerror (op_errno)); - goto out; - } - while (!ret) { - if (!strncmp (key, GLUSTERD_STORE_KEY_BRICK_HOSTNAME, - strlen (GLUSTERD_STORE_KEY_BRICK_HOSTNAME))) { - strncpy (brickinfo->hostname, value, 1024); - } else if (!strncmp (key, GLUSTERD_STORE_KEY_BRICK_PATH, - strlen (GLUSTERD_STORE_KEY_BRICK_PATH))) { - strncpy (brickinfo->path, value, - sizeof (brickinfo->path)); - } else if (!strncmp (key, GLUSTERD_STORE_KEY_BRICK_PORT, - strlen (GLUSTERD_STORE_KEY_BRICK_PORT))) { - gf_string2int (value, &brickinfo->port); - /* This is required to have proper ports - assigned to bricks after restart */ - pmap = pmap_registry_get (THIS); - if (pmap->last_alloc <= brickinfo->port) - pmap->last_alloc = brickinfo->port + 1; - } else if (!strncmp (key, GLUSTERD_STORE_KEY_BRICK_RDMA_PORT, - strlen (GLUSTERD_STORE_KEY_BRICK_RDMA_PORT))) { - gf_string2int (value, &brickinfo->rdma_port); - /* This is required to have proper ports - assigned to bricks after restart */ - pmap = pmap_registry_get (THIS); - if (pmap->last_alloc <= brickinfo->rdma_port) - pmap->last_alloc = brickinfo->rdma_port + 1; - } else if (!strncmp (key, GLUSTERD_STORE_KEY_BRICK_DECOMMISSIONED, - strlen (GLUSTERD_STORE_KEY_BRICK_DECOMMISSIONED))) { - gf_string2int (value, &brickinfo->decommissioned); - } else { - gf_log ("", GF_LOG_ERROR, "Unknown key: %s", - key); - } - - GF_FREE (key); - GF_FREE (value); - key = NULL; - value = NULL; - - ret = glusterd_store_iter_get_next (iter, &key, &value, - &op_errno); - } + ret = 0; - if (op_errno != GD_STORE_EOF) - goto out; - ret = glusterd_store_iter_destroy (iter); +out: + if (gf_store_iter_destroy(&iter)) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_ITER_DESTROY_FAIL, + "Failed to destroy store iter"); + ret = -1; + } - if (ret) - goto out; + return ret; +} - list_add_tail (&brickinfo->brick_list, &volinfo->bricks); - brick_count++; +glusterd_volinfo_t * +glusterd_store_retrieve_volume(char *volname, glusterd_snap_t *snap) +{ + int32_t ret = -1; + glusterd_volinfo_t *volinfo = NULL; + glusterd_volinfo_t *origin_volinfo = NULL; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT(this); + priv = this->private; + GF_ASSERT(priv); + GF_ASSERT(volname); + + ret = glusterd_volinfo_new(&volinfo); + if (ret) + goto out; + + if (snprintf(volinfo->volname, NAME_MAX + 1, "%s", volname) >= NAME_MAX + 1) + goto out; + volinfo->snapshot = snap; + if (snap) + volinfo->is_snap_volume = _gf_true; + + ret = glusterd_store_update_volinfo(volinfo); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_UPDATE_FAIL, + "Failed to update volinfo " + "for %s volume", + volname); + goto out; + } + + ret = glusterd_store_retrieve_bricks(volinfo); + if (ret) + goto out; + + ret = glusterd_store_retrieve_snapd(volinfo); + if (ret) + goto out; + + ret = glusterd_compute_cksum(volinfo, _gf_false); + if (ret) + goto out; + + ret = glusterd_store_retrieve_quota_version(volinfo); + if (ret) + goto out; + + ret = glusterd_store_create_quota_conf_sh_on_absence(volinfo); + if (ret) + goto out; + + ret = glusterd_compute_cksum(volinfo, _gf_true); + if (ret) + goto out; + + ret = glusterd_store_save_quota_version_and_cksum(volinfo); + if (ret) + goto out; + + if (!snap) { + glusterd_list_add_order(&volinfo->vol_list, &priv->volumes, + glusterd_compare_volume_name); + + } else { + ret = glusterd_volinfo_find(volinfo->parent_volname, &origin_volinfo); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_GET_FAIL, + "Parent volinfo " + "not found for %s volume", + volname); + goto out; } + glusterd_list_add_snapvol(origin_volinfo, volinfo); + } - ret = glusterd_store_iter_destroy (tmpiter); - if (ret) - goto out; out: - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + if (ret) { + if (volinfo) + glusterd_volinfo_unref(volinfo); + volinfo = NULL; + } - return ret; + gf_msg_trace(this->name, 0, "Returning with %d", ret); + + return volinfo; } +static void +glusterd_store_set_options_path(glusterd_conf_t *conf, char *path, size_t len) +{ + snprintf(path, len, "%s/options", conf->workdir); +} int32_t -glusterd_store_retrieve_rbstate (char *volname) +glusterd_store_options(xlator_t *this, dict_t *opts) { - int32_t ret = -1; - glusterd_volinfo_t *volinfo = NULL; - glusterd_store_iter_t *iter = NULL; - char *key = NULL; - char *value = NULL; - char volpath[PATH_MAX] = {0,}; - glusterd_conf_t *priv = NULL; - char path[PATH_MAX] = {0,}; - glusterd_store_op_errno_t op_errno = GD_STORE_SUCCESS; - - priv = THIS->private; - - ret = glusterd_volinfo_find (volname, &volinfo); + gf_store_handle_t *shandle = NULL; + glusterd_conf_t *conf = NULL; + char path[PATH_MAX] = {0}; + int fd = -1; + int32_t ret = -1; + glusterd_volinfo_data_store_t *dict_data = NULL; + + conf = this->private; + glusterd_store_set_options_path(conf, path, sizeof(path)); + + ret = gf_store_handle_new(path, &shandle); + if (ret) { + goto out; + } + + fd = gf_store_mkstemp(shandle); + if (fd <= 0) { + ret = -1; + goto out; + } + + dict_data = GF_CALLOC(1, sizeof(glusterd_volinfo_data_store_t), + gf_gld_mt_volinfo_dict_data_t); + if (dict_data == NULL) { + gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_NO_MEMORY, NULL); + return -1; + } + dict_data->shandle = shandle; + shandle->fd = fd; + dict_foreach(opts, _storeopts, (void *)dict_data); + if (dict_data->buffer_len > 0) { + ret = gf_store_save_items(fd, dict_data->buffer); if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, "Couldn't get" - "volinfo for %s.", volname); - goto out; + gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_FILE_OP_FAILED, NULL); + goto out; } + } - GLUSTERD_GET_VOLUME_DIR(volpath, volinfo, priv); - snprintf (path, sizeof (path), "%s/%s", volpath, - GLUSTERD_VOLUME_RBSTATE_FILE); - - ret = glusterd_store_handle_retrieve (path, &volinfo->rb_shandle); - - if (ret) - goto out; - - ret = glusterd_store_iter_new (volinfo->rb_shandle, &iter); - - if (ret) - goto out; - - ret = glusterd_store_iter_get_next (iter, &key, &value, &op_errno); - if (ret) - goto out; - - while (!ret) { - if (!strncmp (key, GLUSTERD_STORE_KEY_RB_STATUS, - strlen (GLUSTERD_STORE_KEY_RB_STATUS))) { - volinfo->rb_status = atoi (value); - } + ret = gf_store_rename_tmppath(shandle); +out: + shandle->fd = 0; + GF_FREE(dict_data); + if ((ret < 0) && (fd > 0)) { + gf_store_unlink_tmppath(shandle); + } + gf_store_handle_destroy(shandle); + return ret; +} - if (volinfo->rb_status > GF_RB_STATUS_NONE) { - if (!strncmp (key, GLUSTERD_STORE_KEY_RB_SRC_BRICK, - strlen (GLUSTERD_STORE_KEY_RB_SRC_BRICK))) { - ret = glusterd_brickinfo_from_brick (value, - &volinfo->src_brick); - if (ret) - goto out; - } else if (!strncmp (key, GLUSTERD_STORE_KEY_RB_DST_BRICK, - strlen (GLUSTERD_STORE_KEY_RB_DST_BRICK))) { - ret = glusterd_brickinfo_from_brick (value, - &volinfo->dst_brick); - if (ret) - goto out; - } - } +int32_t +glusterd_store_retrieve_options(xlator_t *this) +{ + char path[PATH_MAX] = {0}; + glusterd_conf_t *conf = NULL; + gf_store_handle_t *shandle = NULL; + gf_store_iter_t *iter = NULL; + char *key = NULL; + char *value = NULL; + gf_store_op_errno_t op_errno = 0; + int ret = -1; + + conf = this->private; + glusterd_store_set_options_path(conf, path, sizeof(path)); + + ret = gf_store_handle_retrieve(path, &shandle); + if (ret) + goto out; + + ret = gf_store_iter_new(shandle, &iter); + if (ret) + goto out; + + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + while (!ret) { + ret = dict_set_dynstr(conf->opts, key, value); + if (ret) { + GF_FREE(key); + GF_FREE(value); + goto out; + } + GF_FREE(key); + key = NULL; + value = NULL; + + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + } + if (op_errno != GD_STORE_EOF) + goto out; + ret = 0; +out: + (void)gf_store_iter_destroy(&iter); + gf_store_handle_destroy(shandle); + return ret; +} - GF_FREE (key); - GF_FREE (value); - key = NULL; - value = NULL; +int32_t +glusterd_store_retrieve_volumes(xlator_t *this, glusterd_snap_t *snap) +{ + int32_t ret = -1; + char path[PATH_MAX] = { + 0, + }; + glusterd_conf_t *priv = NULL; + DIR *dir = NULL; + struct dirent *entry = NULL; + struct dirent scratch[2] = { + { + 0, + }, + }; + glusterd_volinfo_t *volinfo = NULL; + struct stat st = { + 0, + }; + char entry_path[PATH_MAX] = { + 0, + }; + int32_t len = 0; + + GF_ASSERT(this); + priv = this->private; + + GF_ASSERT(priv); + + if (snap) + len = snprintf(path, PATH_MAX, "%s/snaps/%s", priv->workdir, + snap->snapname); + else + len = snprintf(path, PATH_MAX, "%s/%s", priv->workdir, + GLUSTERD_VOLUME_DIR_PREFIX); + if ((len < 0) || (len >= PATH_MAX)) { + goto out; + } + + dir = sys_opendir(path); + + if (!dir) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED, + "Unable to open dir %s", path); + goto out; + } + + while ((entry = sys_readdir(dir, scratch))) { + if (gf_irrelevant_entry(entry)) + continue; + if (snap && ((!strcmp(entry->d_name, "geo-replication")) || + (!strcmp(entry->d_name, "info")))) + continue; + + len = snprintf(entry_path, PATH_MAX, "%s/%s", path, entry->d_name); + if ((len < 0) || (len >= PATH_MAX)) + continue; + + ret = sys_lstat(entry_path, &st); + if (ret == -1) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY, + "Failed to stat entry %s : %s", path, strerror(errno)); + continue; + } - ret = glusterd_store_iter_get_next (iter, &key, &value, - &op_errno); + if (!S_ISDIR(st.st_mode)) { + gf_msg_debug(this->name, 0, "%s is not a valid volume", + entry->d_name); + continue; } - if (op_errno != GD_STORE_EOF) - goto out; + volinfo = glusterd_store_retrieve_volume(entry->d_name, snap); + if (!volinfo) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_RESTORE_FAIL, + "Unable to restore " + "volume: %s", + entry->d_name); + ret = -1; + goto out; + } - ret = glusterd_store_iter_destroy (iter); + ret = glusterd_store_retrieve_node_state(volinfo); + if (ret) { + /* Backward compatibility */ + gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_NEW_NODE_STATE_CREATION, + "Creating a new node_state " + "for volume: %s.", + entry->d_name); + glusterd_store_create_nodestate_sh_on_absence(volinfo); + glusterd_store_perform_node_state_store(volinfo); + } + } - if (ret) - goto out; + ret = 0; out: - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + if (dir) + sys_closedir(dir); + gf_msg_debug(this->name, 0, "Returning with %d", ret); - return ret; + return ret; } +/* Figure out the brick mount path, from the brick path */ int32_t -glusterd_store_retrieve_volume (char *volname) +glusterd_find_brick_mount_path(char *brick_path, char **brick_mount_path) { - int32_t ret = -1; - glusterd_volinfo_t *volinfo = NULL; - glusterd_store_iter_t *iter = NULL; - char *key = NULL; - char *value = NULL; - char volpath[PATH_MAX] = {0,}; - glusterd_conf_t *priv = NULL; - char path[PATH_MAX] = {0,}; - int exists = 0; - glusterd_store_op_errno_t op_errno = GD_STORE_SUCCESS; - - ret = glusterd_volinfo_new (&volinfo); - - if (ret) - goto out; - - strncpy (volinfo->volname, volname, GLUSTERD_MAX_VOLUME_NAME); - - priv = THIS->private; - - GLUSTERD_GET_VOLUME_DIR(volpath, volinfo, priv); - snprintf (path, sizeof (path), "%s/%s", volpath, - GLUSTERD_VOLUME_INFO_FILE); - - ret = glusterd_store_handle_retrieve (path, &volinfo->shandle); + char *ptr = NULL; + int32_t ret = -1; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT(this); + GF_ASSERT(brick_path); + GF_ASSERT(brick_mount_path); + + *brick_mount_path = gf_strdup(brick_path); + if (!*brick_mount_path) { + ret = -1; + goto out; + } + + /* Finding the pointer to the end of + * /var/run/gluster/snaps/<snap-uuid> + */ + ptr = strstr(*brick_mount_path, "brick"); + if (!ptr) { + /* Snapshot bricks must have brick num as part + * of the brickpath + */ + gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY, + "Invalid brick path(%s)", brick_path); + ret = -1; + goto out; + } + + /* Moving the pointer to the end of + * /var/run/gluster/snaps/<snap-uuid>/<brick_num> + * and assigning '\0' to it. + */ + while ((*ptr != '\0') && (*ptr != '/')) + ptr++; + + if (*ptr == '/') { + *ptr = '\0'; + } + + ret = 0; +out: + if (ret && *brick_mount_path) { + GF_FREE(*brick_mount_path); + *brick_mount_path = NULL; + } + gf_msg_trace(this->name, 0, "Returning with %d", ret); + return ret; +} - if (ret) - goto out; +/* Check if brick_mount_path is already mounted. If not, mount the device_path + * at the brick_mount_path + */ +int32_t +glusterd_mount_brick_paths(char *brick_mount_path, + glusterd_brickinfo_t *brickinfo) +{ + int32_t ret = -1; + runner_t runner = { + 0, + }; + char buff[PATH_MAX] = { + 0, + }; + struct mntent save_entry = { + 0, + }; + struct mntent *entry = NULL; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + + this = THIS; + GF_ASSERT(this); + GF_ASSERT(brick_mount_path); + GF_ASSERT(brickinfo); + + priv = this->private; + GF_ASSERT(priv); + + /* Check if the brick_mount_path is already mounted */ + entry = glusterd_get_mnt_entry_info(brick_mount_path, buff, sizeof(buff), + &save_entry); + if (entry) { + gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_ALREADY_MOUNTED, + "brick_mount_path (%s) already mounted.", brick_mount_path); + ret = 0; + goto out; + } + + /* TODO RHEL 6.5 has the logical volumes inactive by default + * on reboot. Hence activating the logical vol. Check behaviour + * on other systems + */ + /* Activate the snapshot */ + runinit(&runner); + runner_add_args(&runner, "lvchange", "-ay", brickinfo->device_path, NULL); + ret = runner_run(&runner); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_SNAP_ACTIVATE_FAIL, + "Failed to activate %s.", brickinfo->device_path); + goto out; + } else + gf_msg_debug(this->name, 0, "Activating %s successful", + brickinfo->device_path); + + /* Mount the snapshot */ + ret = glusterd_mount_lvm_snapshot(brickinfo, brick_mount_path); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_MOUNT_FAIL, + "Failed to mount lvm snapshot."); + goto out; + } - ret = glusterd_store_iter_new (volinfo->shandle, &iter); +out: + gf_msg_trace(this->name, 0, "Returning with %d", ret); + return ret; +} - if (ret) - goto out; +int32_t +glusterd_recreate_vol_brick_mounts(xlator_t *this, glusterd_volinfo_t *volinfo) +{ + char *brick_mount_path = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + int32_t ret = -1; + struct stat st_buf = { + 0, + }; + char abspath[PATH_MAX] = {0}; + + GF_ASSERT(this); + GF_ASSERT(volinfo); + + cds_list_for_each_entry(brickinfo, &volinfo->bricks, brick_list) + { + /* If the brick is not of this node, or its + * snapshot is pending, or the brick is not + * a snapshotted brick, we continue + */ + if ((gf_uuid_compare(brickinfo->uuid, MY_UUID)) || + (brickinfo->snap_status == -1) || + (strlen(brickinfo->device_path) == 0)) + continue; + + /* Fetch the brick mount path from the brickinfo->path */ + ret = glusterd_find_brick_mount_path(brickinfo->path, + &brick_mount_path); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRK_MNTPATH_GET_FAIL, + "Failed to find brick_mount_path for %s", brickinfo->path); + goto out; + } - ret = glusterd_store_iter_get_next (iter, &key, &value, &op_errno); - if (ret) + /* Check if the brickinfo path is present. + * If not create the brick_mount_path */ + ret = sys_lstat(brickinfo->path, &st_buf); + if (ret) { + if (errno == ENOENT) { + ret = mkdir_p(brick_mount_path, 0755, _gf_true); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, errno, + GD_MSG_CREATE_DIR_FAILED, "Failed to create %s. ", + brick_mount_path); + goto out; + } + } else { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, + "Brick Path(%s) not valid. ", brickinfo->path); goto out; + } + } - while (!ret) { - if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_TYPE, - strlen (GLUSTERD_STORE_KEY_VOL_TYPE))) { - volinfo->type = atoi (value); - } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_COUNT, - strlen (GLUSTERD_STORE_KEY_VOL_COUNT))) { - volinfo->brick_count = atoi (value); - } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_STATUS, - strlen (GLUSTERD_STORE_KEY_VOL_STATUS))) { - volinfo->status = atoi (value); - } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_VERSION, - strlen (GLUSTERD_STORE_KEY_VOL_VERSION))) { - volinfo->version = atoi (value); - } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_PORT, - strlen (GLUSTERD_STORE_KEY_VOL_PORT))) { - volinfo->port = atoi (value); - } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_SUB_COUNT, - strlen (GLUSTERD_STORE_KEY_VOL_SUB_COUNT))) { - volinfo->sub_count = atoi (value); - } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_STRIPE_CNT, - strlen (GLUSTERD_STORE_KEY_VOL_STRIPE_CNT))) { - volinfo->stripe_count = atoi (value); - } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_REPLICA_CNT, - strlen (GLUSTERD_STORE_KEY_VOL_REPLICA_CNT))) { - volinfo->replica_count = atoi (value); - } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_TRANSPORT, - strlen (GLUSTERD_STORE_KEY_VOL_TRANSPORT))) { - volinfo->transport_type = atoi (value); - volinfo->nfs_transport_type = volinfo->transport_type; - if (volinfo->transport_type == GF_TRANSPORT_BOTH_TCP_RDMA) { - volinfo->nfs_transport_type = GF_DEFAULT_NFS_TRANSPORT; - } - } else if (!strncmp (key, GLUSTERD_STORE_KEY_VOL_ID, - strlen (GLUSTERD_STORE_KEY_VOL_ID))) { - ret = uuid_parse (value, volinfo->volume_id); - if (ret) - gf_log ("", GF_LOG_WARNING, - "failed to parse uuid"); - - } else if (strstr (key, "slave")) { - ret = dict_set_dynstr (volinfo->gsync_slaves, key, - gf_strdup (value)); - if (ret) { - gf_log ("",GF_LOG_ERROR, "Error in " - "dict_set_str"); - goto out; - } - gf_log ("", GF_LOG_DEBUG, "Parsed as "GEOREP" " - " slave:key=%s,value:%s", key, value); + /* Check if brick_mount_path is already mounted. + * If not, mount the device_path at the brick_mount_path */ + ret = glusterd_mount_brick_paths(brick_mount_path, brickinfo); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRK_MNTPATH_MOUNT_FAIL, + "Failed to mount brick_mount_path"); + } + if (!gf_uuid_compare(brickinfo->uuid, MY_UUID)) { + if (brickinfo->real_path[0] == '\0') { + if (!realpath(brickinfo->path, abspath)) { + gf_msg(this->name, GF_LOG_CRITICAL, errno, + GD_MSG_BRICKINFO_CREATE_FAIL, + "realpath() failed for brick %s" + ". The underlying file system " + "may be in bad state", + brickinfo->path); + ret = -1; + goto out; } - else { - exists = glusterd_check_option_exists (key, NULL); - if (exists == -1) { - ret = -1; - goto out; - } - if (exists) { - ret = dict_set_str(volinfo->dict, key, - gf_strdup (value)); - if (ret) { - gf_log ("",GF_LOG_ERROR, "Error in " - "dict_set_str"); - goto out; - } - gf_log ("", GF_LOG_DEBUG, "Parsed as Volume-" - "set:key=%s,value:%s", - key, value); - } - else - gf_log ("", GF_LOG_ERROR, "Unknown key: %s", - key); + if (strlen(abspath) >= sizeof(brickinfo->real_path)) { + ret = -1; + goto out; } - - GF_FREE (key); - GF_FREE (value); - key = NULL; - value = NULL; - - ret = glusterd_store_iter_get_next (iter, &key, &value, - &op_errno); + (void)strncpy(brickinfo->real_path, abspath, + sizeof(brickinfo->real_path)); + } } - /* backward compatibility */ - { + if (brick_mount_path) { + GF_FREE(brick_mount_path); + brick_mount_path = NULL; + } + } - switch (volinfo->type) { + ret = 0; +out: + if (ret && brick_mount_path) + GF_FREE(brick_mount_path); - case GF_CLUSTER_TYPE_NONE: - volinfo->stripe_count = 1; - volinfo->replica_count = 1; - break; + gf_msg_trace(this->name, 0, "Returning with %d", ret); + return ret; +} - case GF_CLUSTER_TYPE_STRIPE: - volinfo->stripe_count = volinfo->sub_count; - volinfo->replica_count = 1; - break; +int32_t +glusterd_resolve_snap_bricks(xlator_t *this, glusterd_snap_t *snap) +{ + int32_t ret = -1; + glusterd_volinfo_t *volinfo = NULL; + glusterd_brickinfo_t *brickinfo = NULL; - case GF_CLUSTER_TYPE_REPLICATE: - volinfo->stripe_count = 1; - volinfo->replica_count = volinfo->sub_count; - break; + GF_ASSERT(this); + GF_VALIDATE_OR_GOTO(this->name, snap, out); - case GF_CLUSTER_TYPE_STRIPE_REPLICATE: - /* Introduced in 3.3 */ - GF_ASSERT (volinfo->stripe_count > 0); - GF_ASSERT (volinfo->replica_count > 0); - break; + cds_list_for_each_entry(volinfo, &snap->volumes, vol_list) + { + cds_list_for_each_entry(brickinfo, &volinfo->bricks, brick_list) + { + ret = glusterd_resolve_brick(brickinfo); + if (ret) { + gf_event(EVENT_BRICKPATH_RESOLVE_FAILED, + "peer=%s;volume=%s;brick=%s", brickinfo->hostname, + volinfo->volname, brickinfo->path); + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_RESOLVE_BRICK_FAIL, + "resolve brick failed in restore"); + goto out; + } + } + } - default: - GF_ASSERT (0); - break; - } + ret = 0; - volinfo->dist_leaf_count = (volinfo->stripe_count * - volinfo->replica_count); - } +out: + gf_msg_trace(this->name, 0, "Returning with %d", ret); - if (op_errno != GD_STORE_EOF) - goto out; + return ret; +} - ret = glusterd_store_iter_destroy (iter); +int +glusterd_store_update_snap(glusterd_snap_t *snap) +{ + int ret = -1; + char *key = NULL; + char *value = NULL; + char snappath[PATH_MAX] = { + 0, + }; + char path[PATH_MAX] = { + 0, + }; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + gf_store_iter_t *iter = NULL; + gf_store_op_errno_t op_errno = GD_STORE_SUCCESS; + int32_t len = 0; + + this = THIS; + conf = this->private; + GF_ASSERT(snap); + + GLUSTERD_GET_SNAP_DIR(snappath, snap, conf); + + len = snprintf(path, sizeof(path), "%s/%s", snappath, + GLUSTERD_SNAP_INFO_FILE); + if ((len < 0) || (len >= sizeof(path))) { + goto out; + } + + ret = gf_store_handle_retrieve(path, &snap->shandle); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_HANDLE_NULL, + "snap handle is NULL"); + goto out; + } + + ret = gf_store_iter_new(snap->shandle, &iter); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_ITER_GET_FAIL, + "Failed to get new store " + "iter"); + goto out; + } + + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_ITER_GET_FAIL, + "Failed to get next store " + "iter"); + goto out; + } + + while (!ret) { + gf_msg_debug(this->name, 0, "key = %s value = %s", key, value); + + if (!strncmp(key, GLUSTERD_STORE_KEY_SNAP_ID, + SLEN(GLUSTERD_STORE_KEY_SNAP_ID))) { + ret = gf_uuid_parse(value, snap->snap_id); + if (ret) + gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_UUID_PARSE_FAIL, + "Failed to parse uuid"); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_SNAP_RESTORED, + SLEN(GLUSTERD_STORE_KEY_SNAP_RESTORED))) { + snap->snap_restored = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_SNAP_STATUS, + SLEN(GLUSTERD_STORE_KEY_SNAP_STATUS))) { + snap->snap_status = atoi(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_SNAP_DESC, + SLEN(GLUSTERD_STORE_KEY_SNAP_DESC))) { + snap->description = gf_strdup(value); + } else if (!strncmp(key, GLUSTERD_STORE_KEY_SNAP_TIMESTAMP, + SLEN(GLUSTERD_STORE_KEY_SNAP_TIMESTAMP))) { + snap->time_stamp = atoi(value); + } - if (ret) - goto out; + GF_FREE(key); + GF_FREE(value); + key = NULL; + value = NULL; - ret = glusterd_store_retrieve_bricks (volinfo); - if (ret) - goto out; + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + } - ret = glusterd_volume_compute_cksum (volinfo); - if (ret) - goto out; + if (op_errno != GD_STORE_EOF) + goto out; - list_add_tail (&volinfo->vol_list, &priv->volumes); + ret = 0; out: - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + if (gf_store_iter_destroy(&iter)) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_ITER_DESTROY_FAIL, + "Failed to destroy store iter"); + ret = -1; + } - return ret; + return ret; } - int32_t -glusterd_store_retrieve_volumes (xlator_t *this) +glusterd_store_retrieve_snap(char *snapname) { - int32_t ret = 0; - char path[PATH_MAX] = {0,}; - glusterd_conf_t *priv = NULL; - DIR *dir = NULL; - struct dirent *entry = NULL; - glusterd_volinfo_t *volinfo = NULL; + int32_t ret = -1; + glusterd_snap_t *snap = NULL; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + + this = THIS; + priv = this->private; + GF_ASSERT(priv); + GF_ASSERT(snapname); + + snap = glusterd_new_snap_object(); + if (!snap) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_OBJECT_STORE_FAIL, + "Failed to create " + " snap object"); + goto out; + } + + if (snprintf(snap->snapname, sizeof(snap->snapname), "%s", snapname) >= + sizeof(snap->snapname)) + goto out; + ret = glusterd_store_update_snap(snap); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAPSHOT_UPDATE_FAIL, + "Failed to update snapshot " + "for %s snap", + snapname); + goto out; + } + + ret = glusterd_store_retrieve_volumes(this, snap); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_VOL_RETRIEVE_FAIL, + "Failed to retrieve " + "snap volumes for snap %s", + snapname); + goto out; + } + + /* TODO: list_add_order can do 'N-square' comparisons and + is not efficient. Find a better solution to store the snap + in order */ + glusterd_list_add_order(&snap->snap_list, &priv->snapshots, + glusterd_compare_snap_time); - GF_ASSERT (this); - priv = this->private; +out: + gf_msg_trace(this->name, 0, "Returning with %d", ret); + return ret; +} - GF_ASSERT (priv); +/* Read the missed_snap_list and update the in-memory structs */ +int32_t +glusterd_store_retrieve_missed_snaps_list(xlator_t *this) +{ + char path[PATH_MAX] = ""; + char *snap_vol_id = NULL; + char *missed_node_info = NULL; + char *brick_path = NULL; + char *value = NULL; + char *save_ptr = NULL; + FILE *fp = NULL; + int32_t brick_num = -1; + int32_t snap_op = -1; + int32_t snap_status = -1; + int32_t ret = -1; + glusterd_conf_t *priv = NULL; + gf_store_op_errno_t store_errno = GD_STORE_SUCCESS; + + GF_ASSERT(this); + priv = this->private; + GF_ASSERT(priv); + + /* Get the path of the missed_snap_list */ + glusterd_store_missed_snaps_list_path_set(path, sizeof(path)); + + fp = fopen(path, "r"); + if (!fp) { + /* If errno is ENOENT then there are no missed snaps yet */ + if (errno != ENOENT) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, + "Failed to open %s. ", path); + } else { + gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_MISSED_SNAP_LIST_EMPTY, + "No missed snaps list."); + ret = 0; + } + goto out; + } - snprintf (path, PATH_MAX, "%s/%s", priv->workdir, - GLUSTERD_VOLUME_DIR_PREFIX); + do { + ret = gf_store_read_and_tokenize(fp, &missed_node_info, &value, + &store_errno); + if (ret) { + if (store_errno == GD_STORE_EOF) { + gf_msg_debug(this->name, 0, "EOF for missed_snap_list"); + ret = 0; + break; + } + gf_msg(this->name, GF_LOG_ERROR, store_errno, + GD_MSG_MISSED_SNAP_GET_FAIL, + "Failed to fetch data from " + "missed_snaps_list."); + goto out; + } - dir = opendir (path); + /* Fetch the brick_num, brick_path, snap_op and snap status */ + snap_vol_id = strtok_r(value, ":", &save_ptr); + brick_num = atoi(strtok_r(NULL, ":", &save_ptr)); + brick_path = strtok_r(NULL, ":", &save_ptr); + snap_op = atoi(strtok_r(NULL, ":", &save_ptr)); + snap_status = atoi(strtok_r(NULL, ":", &save_ptr)); + + if (!missed_node_info || !brick_path || !snap_vol_id || brick_num < 1 || + snap_op < 1 || snap_status < 1) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, + GD_MSG_INVALID_MISSED_SNAP_ENTRY, + "Invalid missed_snap_entry"); + ret = -1; + goto out; + } - if (!dir) { - gf_log ("", GF_LOG_ERROR, "Unable to open dir %s", path); - ret = -1; - goto out; + ret = glusterd_add_new_entry_to_list(missed_node_info, snap_vol_id, + brick_num, brick_path, snap_op, + snap_status); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, + GD_MSG_MISSED_SNAP_LIST_STORE_FAIL, + "Failed to store missed snaps_list"); + goto out; } - glusterd_for_each_entry (entry, dir); + } while (store_errno == GD_STORE_SUCCESS); - while (entry) { - ret = glusterd_store_retrieve_volume (entry->d_name); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to restore " - "volume: %s", entry->d_name); - goto out; - } + ret = 0; +out: + if (fp) + fclose(fp); - ret = glusterd_store_retrieve_rbstate (entry->d_name); - if (ret) { - /* Backward compatibility */ - gf_log ("", GF_LOG_INFO, "Creating a new rbstate " - "for volume: %s.", entry->d_name); - ret = glusterd_volinfo_find (entry->d_name, &volinfo); - ret = glusterd_store_create_rbstate_shandle_on_absence (volinfo); - ret = glusterd_store_perform_rbstate_store (volinfo); - } - glusterd_for_each_entry (entry, dir); + gf_msg_trace(this->name, 0, "Returning with %d", ret); + return ret; +} + +int32_t +glusterd_store_retrieve_snaps(xlator_t *this) +{ + int32_t ret = 0; + char path[PATH_MAX] = { + 0, + }; + glusterd_conf_t *priv = NULL; + DIR *dir = NULL; + struct dirent *entry = NULL; + struct dirent scratch[2] = { + { + 0, + }, + }; + int32_t len = 0; + + GF_ASSERT(this); + priv = this->private; + + GF_ASSERT(priv); + + len = snprintf(path, PATH_MAX, "%s/snaps", priv->workdir); + if ((len < 0) || (len >= PATH_MAX)) { + ret = -1; + goto out; + } + + dir = sys_opendir(path); + + if (!dir) { + /* If snaps dir doesn't exists ignore the error for + backward compatibility */ + if (errno != ENOENT) { + ret = -1; + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED, + "Unable to open dir %s", path); + } + goto out; + } + + while ((entry = sys_readdir(dir, scratch))) { + if (gf_irrelevant_entry(entry)) + continue; + if (strcmp(entry->d_name, GLUSTERD_MISSED_SNAPS_LIST_FILE)) { + ret = glusterd_store_retrieve_snap(entry->d_name); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESTORE_FAIL, + "Unable to restore snapshot: %s", entry->d_name); + goto out; + } } + } + + /* Retrieve missed_snaps_list */ + ret = glusterd_store_retrieve_missed_snaps_list(this); + if (ret) { + gf_msg_debug(this->name, 0, "Failed to retrieve missed_snaps_list"); + goto out; + } out: - if (dir) - closedir (dir); - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + if (dir) + sys_closedir(dir); + gf_msg_debug(this->name, 0, "Returning with %d", ret); - return ret; + return ret; } +/* Writes all the contents of conf->missed_snap_list */ int32_t -glusterd_store_delete_peerinfo (glusterd_peerinfo_t *peerinfo) +glusterd_store_write_missed_snapinfo(int32_t fd) { - int32_t ret = -1; - glusterd_conf_t *priv = NULL; - char peerdir[PATH_MAX] = {0,}; - char filepath[PATH_MAX] = {0,}; - char hostname_path[PATH_MAX] = {0,}; - - - if (!peerinfo) { - ret = 0; + char key[(UUID_SIZE * 2) + 2]; + char value[PATH_MAX]; + int32_t ret = -1; + glusterd_conf_t *priv = NULL; + glusterd_missed_snap_info *missed_snapinfo = NULL; + glusterd_snap_op_t *snap_opinfo = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT(this); + + priv = this->private; + GF_ASSERT(priv); + + /* Write the missed_snap_entry */ + cds_list_for_each_entry(missed_snapinfo, &priv->missed_snaps_list, + missed_snaps) + { + cds_list_for_each_entry(snap_opinfo, &missed_snapinfo->snap_ops, + snap_ops_list) + { + snprintf(key, sizeof(key), "%s:%s", missed_snapinfo->node_uuid, + missed_snapinfo->snap_uuid); + snprintf(value, sizeof(value), "%s:%d:%s:%d:%d", + snap_opinfo->snap_vol_id, snap_opinfo->brick_num, + snap_opinfo->brick_path, snap_opinfo->op, + snap_opinfo->status); + ret = gf_store_save_value(fd, key, value); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, + GD_MSG_MISSEDSNAP_INFO_SET_FAIL, + "Failed to write missed snapinfo"); goto out; + } } + } - priv = THIS->private; - - snprintf (peerdir, PATH_MAX, "%s/peers", priv->workdir); + ret = 0; +out: + gf_msg_trace(this->name, 0, "Returning %d", ret); + return ret; +} +/* Adds the missed snap entries to the in-memory conf->missed_snap_list * + * and writes them to disk */ +int32_t +glusterd_store_update_missed_snaps() +{ + int32_t fd = -1; + int32_t ret = -1; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT(this); + + priv = this->private; + GF_ASSERT(priv); + + ret = glusterd_store_create_missed_snaps_list_shandle_on_absence(); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, + GD_MSG_MISSED_SNAP_LIST_STORE_HANDLE_GET_FAIL, + "Unable to obtain " + "missed_snaps_list store handle."); + goto out; + } + + fd = gf_store_mkstemp(priv->missed_snaps_list_shandle); + if (fd <= 0) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, + "Failed to create tmp file"); + ret = -1; + goto out; + } + + ret = glusterd_store_write_missed_snapinfo(fd); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_MISSED_SNAP_CREATE_FAIL, + "Failed to write missed snaps to disk"); + goto out; + } + + ret = gf_store_rename_tmppath(priv->missed_snaps_list_shandle); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED, + "Failed to rename the tmp file"); + goto out; + } +out: + if (ret && (fd > 0)) { + ret = gf_store_unlink_tmppath(priv->missed_snaps_list_shandle); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_TMP_FILE_UNLINK_FAIL, + "Failed to unlink the tmp file"); + } + ret = -1; + } - if (uuid_is_null (peerinfo->uuid)) { + gf_msg_trace(this->name, 0, "Returning %d", ret); + return ret; +} - if (peerinfo->hostname) { - snprintf (filepath, PATH_MAX, "%s/%s", peerdir, - peerinfo->hostname); - } else { - ret = 0; - goto out; - } +int32_t +glusterd_store_delete_peerinfo(glusterd_peerinfo_t *peerinfo) +{ + int32_t ret = -1; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + char peerdir[PATH_MAX] = { + 0, + }; + char filepath[PATH_MAX] = { + 0, + }; + char hostname_path[PATH_MAX] = { + 0, + }; + int32_t len = 0; + + if (!peerinfo) { + ret = 0; + goto out; + } + + this = THIS; + priv = this->private; + + len = snprintf(peerdir, PATH_MAX, "%s/peers", priv->workdir); + if ((len < 0) || (len >= PATH_MAX)) { + goto out; + } + + if (gf_uuid_is_null(peerinfo->uuid)) { + if (peerinfo->hostname) { + len = snprintf(filepath, PATH_MAX, "%s/%s", peerdir, + peerinfo->hostname); + if ((len < 0) || (len >= PATH_MAX)) { + goto out; + } } else { + ret = 0; + goto out; + } + } else { + len = snprintf(filepath, PATH_MAX, "%s/%s", peerdir, + uuid_utoa(peerinfo->uuid)); + if ((len < 0) || (len >= PATH_MAX)) { + goto out; + } + len = snprintf(hostname_path, PATH_MAX, "%s/%s", peerdir, + peerinfo->hostname); + if ((len < 0) || (len >= PATH_MAX)) { + goto out; + } - snprintf (filepath, PATH_MAX, "%s/%s", peerdir, - uuid_utoa (peerinfo->uuid)); - snprintf (hostname_path, PATH_MAX, "%s/%s", - peerdir, peerinfo->hostname); - - ret = unlink (hostname_path); + ret = sys_unlink(hostname_path); - if (!ret) - goto out; - } + if (!ret) + goto out; + } - ret = unlink (filepath); - if (ret && (errno == ENOENT)) - ret = 0; + ret = sys_unlink(filepath); + if (ret && (errno == ENOENT)) + ret = 0; out: - if (peerinfo->shandle) { - glusterd_store_handle_destroy (peerinfo->shandle); - peerinfo->shandle = NULL; - } - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + if (peerinfo && peerinfo->shandle) { + gf_store_handle_destroy(peerinfo->shandle); + peerinfo->shandle = NULL; + } + gf_msg_debug((this ? this->name : "glusterd"), 0, "Returning with %d", ret); - return ret; + return ret; } void -glusterd_store_peerinfo_dirpath_set (char *path, size_t len) +glusterd_store_peerinfo_dirpath_set(char *path, size_t len) { - glusterd_conf_t *priv = NULL; - GF_ASSERT (path); - GF_ASSERT (len >= PATH_MAX); + glusterd_conf_t *priv = NULL; + GF_ASSERT(path); + GF_ASSERT(len >= PATH_MAX); - priv = THIS->private; - snprintf (path, len, "%s/peers", priv->workdir); + priv = THIS->private; + snprintf(path, len, "%s/peers", priv->workdir); } int32_t -glusterd_store_create_peer_dir () +glusterd_store_create_peer_dir() { - int32_t ret = 0; - char path[PATH_MAX]; + int32_t ret = 0; + char path[PATH_MAX]; - glusterd_store_peerinfo_dirpath_set (path, sizeof (path)); - ret = glusterd_store_mkdir (path); + glusterd_store_peerinfo_dirpath_set(path, sizeof(path)); + ret = gf_store_mkdir(path); - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); - return ret; + gf_msg_debug("glusterd", 0, "Returning with %d", ret); + return ret; } static void -glusterd_store_uuid_peerpath_set (glusterd_peerinfo_t *peerinfo, char *peerfpath, - size_t len) +glusterd_store_uuid_peerpath_set(glusterd_peerinfo_t *peerinfo, char *peerfpath, + size_t len) { - char peerdir[PATH_MAX]; - char str[50] = {0}; + char peerdir[PATH_MAX]; + char str[50] = {0}; - GF_ASSERT (peerinfo); - GF_ASSERT (peerfpath); - GF_ASSERT (len >= PATH_MAX); + GF_ASSERT(peerinfo); + GF_ASSERT(peerfpath); + GF_ASSERT(len >= PATH_MAX); - glusterd_store_peerinfo_dirpath_set (peerdir, sizeof (peerdir)); - uuid_unparse (peerinfo->uuid, str); - snprintf (peerfpath, len, "%s/%s", peerdir, str); + glusterd_store_peerinfo_dirpath_set(peerdir, sizeof(peerdir)); + gf_uuid_unparse(peerinfo->uuid, str); + snprintf(peerfpath, len, "%s/%s", peerdir, str); } static void -glusterd_store_hostname_peerpath_set (glusterd_peerinfo_t *peerinfo, - char *peerfpath, size_t len) +glusterd_store_hostname_peerpath_set(glusterd_peerinfo_t *peerinfo, + char *peerfpath, size_t len) { - char peerdir[PATH_MAX]; + char peerdir[PATH_MAX]; - GF_ASSERT (peerinfo); - GF_ASSERT (peerfpath); - GF_ASSERT (len >= PATH_MAX); + GF_ASSERT(peerinfo); + GF_ASSERT(peerfpath); + GF_ASSERT(len >= PATH_MAX); - glusterd_store_peerinfo_dirpath_set (peerdir, sizeof (peerdir)); - snprintf (peerfpath, len, "%s/%s", peerdir, peerinfo->hostname); + glusterd_store_peerinfo_dirpath_set(peerdir, sizeof(peerdir)); + snprintf(peerfpath, len, "%s/%s", peerdir, peerinfo->hostname); } int32_t -glusterd_store_peerinfo_hostname_shandle_create (glusterd_peerinfo_t *peerinfo) +glusterd_store_peerinfo_hostname_shandle_create(glusterd_peerinfo_t *peerinfo) { - char peerfpath[PATH_MAX]; - int32_t ret = -1; + char peerfpath[PATH_MAX]; + int32_t ret = -1; - glusterd_store_hostname_peerpath_set (peerinfo, peerfpath, - sizeof (peerfpath)); - ret = glusterd_store_handle_create_on_absence (&peerinfo->shandle, - peerfpath); - return ret; + glusterd_store_hostname_peerpath_set(peerinfo, peerfpath, + sizeof(peerfpath)); + ret = gf_store_handle_create_on_absence(&peerinfo->shandle, peerfpath); + return ret; } int32_t -glusterd_store_peerinfo_uuid_shandle_create (glusterd_peerinfo_t *peerinfo) +glusterd_store_peerinfo_uuid_shandle_create(glusterd_peerinfo_t *peerinfo) { - char peerfpath[PATH_MAX]; - int32_t ret = -1; + char peerfpath[PATH_MAX]; + int32_t ret = -1; - glusterd_store_uuid_peerpath_set (peerinfo, peerfpath, - sizeof (peerfpath)); - ret = glusterd_store_handle_create_on_absence (&peerinfo->shandle, - peerfpath); - return ret; + glusterd_store_uuid_peerpath_set(peerinfo, peerfpath, sizeof(peerfpath)); + ret = gf_store_handle_create_on_absence(&peerinfo->shandle, peerfpath); + return ret; } int32_t -glusterd_peerinfo_hostname_shandle_check_destroy (glusterd_peerinfo_t *peerinfo) +glusterd_peerinfo_hostname_shandle_check_destroy(glusterd_peerinfo_t *peerinfo) { - char peerfpath[PATH_MAX]; - int32_t ret = -1; - struct stat stbuf = {0,}; - - glusterd_store_hostname_peerpath_set (peerinfo, peerfpath, - sizeof (peerfpath)); - ret = stat (peerfpath, &stbuf); - if (!ret) { - if (peerinfo->shandle) - glusterd_store_handle_destroy (peerinfo->shandle); - peerinfo->shandle = NULL; - ret = unlink (peerfpath); - } - return ret; + char peerfpath[PATH_MAX]; + int32_t ret = -1; + struct stat stbuf = { + 0, + }; + + glusterd_store_hostname_peerpath_set(peerinfo, peerfpath, + sizeof(peerfpath)); + ret = sys_stat(peerfpath, &stbuf); + if (!ret) { + if (peerinfo->shandle) + gf_store_handle_destroy(peerinfo->shandle); + peerinfo->shandle = NULL; + ret = sys_unlink(peerfpath); + } + return ret; } int32_t -glusterd_store_create_peer_shandle (glusterd_peerinfo_t *peerinfo) +glusterd_store_create_peer_shandle(glusterd_peerinfo_t *peerinfo) { - int32_t ret = 0; + int32_t ret = 0; - GF_ASSERT (peerinfo); + GF_ASSERT(peerinfo); - if (glusterd_peerinfo_is_uuid_unknown (peerinfo)) { - ret = glusterd_store_peerinfo_hostname_shandle_create (peerinfo); - } else { - ret = glusterd_peerinfo_hostname_shandle_check_destroy (peerinfo); - ret = glusterd_store_peerinfo_uuid_shandle_create (peerinfo); + if (gf_uuid_is_null(peerinfo->uuid)) { + ret = glusterd_store_peerinfo_hostname_shandle_create(peerinfo); + } else { + ret = glusterd_peerinfo_hostname_shandle_check_destroy(peerinfo); + ret = glusterd_store_peerinfo_uuid_shandle_create(peerinfo); + } + return ret; +} + +static int32_t +glusterd_store_peer_write(int fd, glusterd_peerinfo_t *peerinfo) +{ + char buf[PATH_MAX]; + uint total_len = 0; + int32_t ret = 0; + int32_t i = 1; + glusterd_peer_hostname_t *hostname = NULL; + + ret = snprintf(buf + total_len, sizeof(buf) - total_len, "%s=%s\n%s=%d\n", + GLUSTERD_STORE_KEY_PEER_UUID, uuid_utoa(peerinfo->uuid), + GLUSTERD_STORE_KEY_PEER_STATE, peerinfo->state.state); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; + } + total_len += ret; + + cds_list_for_each_entry(hostname, &peerinfo->hostnames, hostname_list) + { + ret = snprintf(buf + total_len, sizeof(buf) - total_len, + GLUSTERD_STORE_KEY_PEER_HOSTNAME "%d=%s\n", i, + hostname->hostname); + if (ret < 0 || ret >= sizeof(buf) - total_len) { + ret = -1; + goto out; } - return ret; + total_len += ret; + i++; + } + + ret = gf_store_save_items(fd, buf); +out: + gf_msg_debug("glusterd", 0, "Returning with %d", ret); + return ret; } int32_t -glusterd_store_peer_write (int fd, glusterd_peerinfo_t *peerinfo) +glusterd_store_perform_peer_store(glusterd_peerinfo_t *peerinfo) { - char buf[50] = {0}; - int32_t ret = 0; + int fd = -1; + int32_t ret = -1; - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_PEER_UUID, - uuid_utoa (peerinfo->uuid)); - if (ret) - goto out; + GF_ASSERT(peerinfo); - snprintf (buf, sizeof (buf), "%d", peerinfo->state.state); - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_PEER_STATE, buf); - if (ret) - goto out; + fd = gf_store_mkstemp(peerinfo->shandle); + if (fd <= 0) { + ret = -1; + goto out; + } - ret = glusterd_store_save_value (fd, GLUSTERD_STORE_KEY_PEER_HOSTNAME "1", - peerinfo->hostname); + ret = glusterd_store_peer_write(fd, peerinfo); + if (ret) + goto out; + + ret = gf_store_rename_tmppath(peerinfo->shandle); out: - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); - return ret; + if (ret && (fd > 0)) + gf_store_unlink_tmppath(peerinfo->shandle); + gf_msg_debug("glusterd", 0, "Returning %d", ret); + return ret; } int32_t -glusterd_store_perform_peer_store (glusterd_peerinfo_t *peerinfo) +glusterd_store_peerinfo(glusterd_peerinfo_t *peerinfo) { - int fd = -1; - int32_t ret = -1; + int32_t ret = -1; - GF_ASSERT (peerinfo); + GF_ASSERT(peerinfo); - fd = glusterd_store_mkstemp (peerinfo->shandle); - if (fd <= 0) { - ret = -1; - goto out; - } + ret = glusterd_store_create_peer_dir(); + if (ret) + goto out; - ret = glusterd_store_peer_write (fd, peerinfo); - if (ret) - goto out; + ret = glusterd_store_create_peer_shandle(peerinfo); + if (ret) + goto out; - ret = glusterd_store_rename_tmppath (peerinfo->shandle); + ret = glusterd_store_perform_peer_store(peerinfo); out: - if (ret && (fd > 0)) - glusterd_store_unlink_tmppath (peerinfo->shandle); - if (fd > 0) - close (fd); - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; + gf_msg_debug("glusterd", 0, "Returning with %d", ret); + return ret; } int32_t -glusterd_store_peerinfo (glusterd_peerinfo_t *peerinfo) +glusterd_store_retrieve_peers(xlator_t *this) { - int32_t ret = -1; - - GF_ASSERT (peerinfo); - - ret = glusterd_store_create_peer_dir (); + int32_t ret = 0; + glusterd_conf_t *priv = NULL; + DIR *dir = NULL; + struct dirent *entry = NULL; + struct dirent scratch[2] = { + { + 0, + }, + }; + char path[PATH_MAX] = { + 0, + }; + glusterd_peerinfo_t *peerinfo = NULL; + gf_store_handle_t *shandle = NULL; + char filepath[PATH_MAX] = { + 0, + }; + gf_store_iter_t *iter = NULL; + char *key = NULL; + char *value = NULL; + glusterd_peerctx_args_t args = {0}; + gf_store_op_errno_t op_errno = GD_STORE_SUCCESS; + glusterd_peer_hostname_t *address = NULL; + uuid_t tmp_uuid; + gf_boolean_t is_ok; + int32_t len; + + GF_ASSERT(this); + priv = this->private; + + GF_ASSERT(priv); + + len = snprintf(path, PATH_MAX, "%s/%s", priv->workdir, + GLUSTERD_PEER_DIR_PREFIX); + if ((len < 0) || (len >= PATH_MAX)) { + ret = -1; + goto out; + } + + dir = sys_opendir(path); + + if (!dir) { + gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED, + "Unable to open dir %s", path); + ret = -1; + goto out; + } + + while ((entry = sys_readdir(dir, scratch))) { + if (gf_irrelevant_entry(entry)) + continue; + if (gf_uuid_parse(entry->d_name, tmp_uuid) != 0) { + gf_log(this->name, GF_LOG_WARNING, "skipping non-peer file %s", + entry->d_name); + continue; + } + is_ok = _gf_false; + len = snprintf(filepath, PATH_MAX, "%s/%s", path, entry->d_name); + if ((len < 0) || (len >= PATH_MAX)) { + goto next; + } + ret = gf_store_handle_retrieve(filepath, &shandle); if (ret) - goto out; + goto next; - ret = glusterd_store_create_peer_shandle (peerinfo); + ret = gf_store_iter_new(shandle, &iter); if (ret) - goto out; + goto next; - ret = glusterd_store_perform_peer_store (peerinfo); -out: - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); - return ret; -} + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + if (ret) { + goto next; + } -int32_t -glusterd_store_retrieve_peers (xlator_t *this) -{ - int32_t ret = 0; - glusterd_conf_t *priv = NULL; - DIR *dir = NULL; - struct dirent *entry = NULL; - char path[PATH_MAX] = {0,}; - glusterd_peerinfo_t *peerinfo = NULL; - uuid_t uuid = {0,}; - char *hostname = NULL; - int32_t state = 0; - glusterd_store_handle_t *shandle = NULL; - char filepath[PATH_MAX] = {0,}; - glusterd_store_iter_t *iter = NULL; - char *key = NULL; - char *value = NULL; - glusterd_peerctx_args_t args = {0}; - glusterd_store_op_errno_t op_errno = GD_STORE_SUCCESS; - - GF_ASSERT (this); - priv = this->private; - - GF_ASSERT (priv); - - snprintf (path, PATH_MAX, "%s/%s", priv->workdir, - GLUSTERD_PEER_DIR_PREFIX); - - dir = opendir (path); - - if (!dir) { - gf_log ("", GF_LOG_ERROR, "Unable to open dir %s", path); - ret = -1; - goto out; + /* Create an empty peerinfo object before reading in the + * details + */ + peerinfo = glusterd_peerinfo_new(GD_FRIEND_STATE_DEFAULT, NULL, NULL, + 0); + if (peerinfo == NULL) { + ret = -1; + goto next; } - glusterd_for_each_entry (entry, dir); + while (!ret) { + if (!strncmp(GLUSTERD_STORE_KEY_PEER_UUID, key, + SLEN(GLUSTERD_STORE_KEY_PEER_UUID))) { + if (value) + gf_uuid_parse(value, peerinfo->uuid); + } else if (!strncmp(GLUSTERD_STORE_KEY_PEER_STATE, key, + SLEN(GLUSTERD_STORE_KEY_PEER_STATE))) { + peerinfo->state.state = atoi(value); + } else if (!strncmp(GLUSTERD_STORE_KEY_PEER_HOSTNAME, key, + SLEN(GLUSTERD_STORE_KEY_PEER_HOSTNAME))) { + ret = gd_add_address_to_peer(peerinfo, value); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, + GD_MSG_ADD_ADDRESS_TO_PEER_FAIL, + "Could not add address to peer"); + } + } else { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_UNKNOWN_KEY, + "Unknown key: %s", key); + } - while (entry) { - snprintf (filepath, PATH_MAX, "%s/%s", path, entry->d_name); - ret = glusterd_store_handle_retrieve (filepath, &shandle); - if (ret) - goto out; + GF_FREE(key); + GF_FREE(value); + key = NULL; + value = NULL; - ret = glusterd_store_iter_new (shandle, &iter); - if (ret) - goto out; + ret = gf_store_iter_get_next(iter, &key, &value, &op_errno); + } + if (op_errno != GD_STORE_EOF) { + goto next; + } - ret = glusterd_store_iter_get_next (iter, &key, &value, - &op_errno); - if (ret) - goto out; + if (gf_uuid_is_null(peerinfo->uuid)) { + gf_log("", GF_LOG_ERROR, + "Null UUID while attempting to read peer from '%s'", + filepath); + goto next; + } - while (!ret) { - - if (!strncmp (GLUSTERD_STORE_KEY_PEER_UUID, key, - strlen (GLUSTERD_STORE_KEY_PEER_UUID))) { - if (value) - uuid_parse (value, uuid); - } else if (!strncmp (GLUSTERD_STORE_KEY_PEER_STATE, - key, - strlen (GLUSTERD_STORE_KEY_PEER_STATE))) { - state = atoi (value); - } else if (!strncmp (GLUSTERD_STORE_KEY_PEER_HOSTNAME, - key, - strlen (GLUSTERD_STORE_KEY_PEER_HOSTNAME))) { - hostname = gf_strdup (value); - } else { - gf_log ("", GF_LOG_ERROR, "Unknown key: %s", - key); - } - - GF_FREE (key); - GF_FREE (value); - key = NULL; - value = NULL; - - ret = glusterd_store_iter_get_next (iter, &key, &value, - &op_errno); - } - if (op_errno != GD_STORE_EOF) - goto out; + /* Set first hostname from peerinfo->hostnames to + * peerinfo->hostname + */ + address = cds_list_entry(peerinfo->hostnames.next, + glusterd_peer_hostname_t, hostname_list); + peerinfo->hostname = gf_strdup(address->hostname); - (void) glusterd_store_iter_destroy (iter); + ret = glusterd_friend_add_from_peerinfo(peerinfo, 1, NULL); + if (ret) + goto next; - args.mode = GD_MODE_SWITCH_ON; - ret = glusterd_friend_add (hostname, 0, state, &uuid, - NULL, &peerinfo, 1, &args); + peerinfo->shandle = shandle; + is_ok = _gf_true; - GF_FREE (hostname); - if (ret) - goto out; + next: + (void)gf_store_iter_destroy(&iter); - peerinfo->shandle = shandle; - glusterd_for_each_entry (entry, dir); + if (!is_ok) { + gf_log(this->name, GF_LOG_WARNING, + "skipping malformed peer file %s", entry->d_name); + if (peerinfo) { + glusterd_peerinfo_cleanup(peerinfo); + } } + peerinfo = NULL; + } + + args.mode = GD_MODE_ON; + + RCU_READ_LOCK; + cds_list_for_each_entry_rcu(peerinfo, &priv->peers, uuid_list) + { + ret = glusterd_friend_rpc_create(this, peerinfo, &args); + if (ret) + break; + } + RCU_READ_UNLOCK; + peerinfo = NULL; out: - if (dir) - closedir (dir); - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); - return ret; + if (dir) + sys_closedir(dir); + gf_msg_debug(this->name, 0, "Returning with %d", ret); + + return ret; } +/* Bricks for snap volumes are hosted at /var/run/gluster/snaps + * When a volume is restored, it points to the bricks of the snap + * volume it was restored from. Hence on a node restart these + * paths need to be recreated and re-mounted + */ int32_t -glusterd_resolve_all_bricks (xlator_t *this) -{ - int32_t ret = 0; - glusterd_conf_t *priv = NULL; - glusterd_volinfo_t *volinfo = NULL; - glusterd_brickinfo_t *brickinfo = NULL; - - GF_ASSERT (this); - priv = this->private; - - GF_ASSERT (priv); - - list_for_each_entry (volinfo, &priv->volumes, vol_list) { - list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { - ret = glusterd_resolve_brick (brickinfo); - if (ret) { - gf_log ("glusterd", GF_LOG_ERROR, - "resolve brick failed in restore"); - goto out; - } +glusterd_recreate_all_snap_brick_mounts(xlator_t *this) +{ + int32_t ret = 0; + glusterd_conf_t *priv = NULL; + glusterd_volinfo_t *volinfo = NULL; + glusterd_snap_t *snap = NULL; + + GF_ASSERT(this); + priv = this->private; + GF_ASSERT(priv); + + /* Recreate bricks of volumes restored from snaps */ + cds_list_for_each_entry(volinfo, &priv->volumes, vol_list) + { + /* If the volume is not a restored volume then continue */ + if (gf_uuid_is_null(volinfo->restored_from_snap)) + continue; + + ret = glusterd_recreate_vol_brick_mounts(this, volinfo); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_BRK_MNT_RECREATE_FAIL, + "Failed to recreate brick mounts " + "for %s", + volinfo->volname); + goto out; + } + } + + /* Recreate bricks of snapshot volumes + * We are not creating brick mounts for stopped snaps. + */ + cds_list_for_each_entry(snap, &priv->snapshots, snap_list) + { + cds_list_for_each_entry(volinfo, &snap->volumes, vol_list) + { + if (volinfo->status != GLUSTERD_STATUS_STOPPED) { + ret = glusterd_recreate_vol_brick_mounts(this, volinfo); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, + GD_MSG_BRK_MNT_RECREATE_FAIL, + "Failed to recreate brick " + "mounts for %s", + snap->snapname); + goto out; } + } } + } out: - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + gf_msg_trace(this->name, 0, "Returning with %d", ret); + return ret; +} - return ret; +/* When the snapshot command from cli is received, the on disk and + * in memory structures for the snapshot are created (with the status) + * being marked as GD_SNAP_STATUS_INIT. Once the backend snapshot is + * taken, the status is changed to GD_SNAP_STATUS_IN_USE. If glusterd + * dies after taking the backend snapshot, but before updating the + * status, then when glusterd comes up, it should treat that snapshot + * as a failed snapshot and clean it up. + * + * Restore operation starts by setting the status to + * GD_SNAP_STATUS_RESTORED. If the server goes down before changing + * the status the status back we need to revert the partial snapshot + * taken. + */ +int32_t +glusterd_snap_cleanup(xlator_t *this) +{ + dict_t *dict = NULL; + int32_t ret = 0; + glusterd_conf_t *priv = NULL; + glusterd_snap_t *snap = NULL; + glusterd_snap_t *tmp_snap = NULL; + + GF_ASSERT(this); + priv = this->private; + GF_ASSERT(priv); + + dict = dict_new(); + if (!dict) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_CREATE_FAIL, + "Failed to create dict"); + ret = -1; + goto out; + } + + cds_list_for_each_entry_safe(snap, tmp_snap, &priv->snapshots, snap_list) + { + if (snap->snap_status == GD_SNAP_STATUS_RESTORED) { + ret = glusterd_snapshot_revert_restore_from_snap(snap); + if (ret) { + gf_msg(this->name, GF_LOG_WARNING, 0, + GD_MSG_SNAP_RESTORE_REVERT_FAIL, + "Failed to " + "revert partially restored snapshot " + "(%s)", + snap->snapname); + goto out; + } + } else if (snap->snap_status != GD_SNAP_STATUS_IN_USE) { + ret = glusterd_snap_remove(dict, snap, _gf_true, _gf_true, + _gf_false); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_REMOVE_FAIL, + "Failed to remove the snapshot %s", snap->snapname); + goto out; + } + } + } +out: + if (dict) + dict_unref(dict); + + gf_msg_trace(this->name, 0, "Returning with %d", ret); + return ret; } int32_t -glusterd_restore () +glusterd_resolve_all_bricks(xlator_t *this) { - int32_t ret = -1; - xlator_t *this = NULL; + int32_t ret = 0; + glusterd_conf_t *priv = NULL; + glusterd_volinfo_t *volinfo = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + glusterd_snap_t *snap = NULL; - this = THIS; + GF_ASSERT(this); + priv = this->private; - ret = glusterd_store_retrieve_volumes (this); + GF_ASSERT(priv); - if (ret) + /* Resolve bricks of volumes */ + cds_list_for_each_entry(volinfo, &priv->volumes, vol_list) + { + cds_list_for_each_entry(brickinfo, &volinfo->bricks, brick_list) + { + ret = glusterd_resolve_brick(brickinfo); + if (ret) { + gf_event(EVENT_BRICKPATH_RESOLVE_FAILED, + "peer=%s;volume=%s;brick=%s", brickinfo->hostname, + volinfo->volname, brickinfo->path); + gf_msg("glusterd", GF_LOG_ERROR, 0, GD_MSG_RESOLVE_BRICK_FAIL, + "Failed to resolve brick %s with host %s of volume %s" + " in restore", + brickinfo->path, brickinfo->hostname, volinfo->volname); goto out; + } + } + } - ret = glusterd_store_retrieve_peers (this); - if (ret) - goto out; + /* Resolve bricks of snapshot volumes */ + cds_list_for_each_entry(snap, &priv->snapshots, snap_list) + { + ret = glusterd_resolve_snap_bricks(this, snap); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_RESOLVE_BRICK_FAIL, + "resolving the snap bricks" + " failed for snap: %s", + snap->snapname); + goto out; + } + } - ret = glusterd_resolve_all_bricks (this); - if (ret) - goto out; +out: + gf_msg_trace(this->name, 0, "Returning with %d", ret); + return ret; +} + +int32_t +glusterd_restore() +{ + int32_t ret = -1; + xlator_t *this = NULL; + + this = THIS; + + ret = glusterd_options_init(this); + if (ret < 0) + goto out; + + ret = glusterd_store_retrieve_volumes(this, NULL); + if (ret) + goto out; + + ret = glusterd_store_retrieve_peers(this); + if (ret) + goto out; + + /* While retrieving snapshots, if the snapshot status + is not GD_SNAP_STATUS_IN_USE, then the snapshot is + cleaned up. To do that, the snap volume has to be + stopped by stopping snapshot volume's bricks. And for + that the snapshot bricks should be resolved. But without + retrieving the peers, resolving bricks will fail. So + do retrieving of snapshots after retrieving peers. + */ + ret = glusterd_store_retrieve_snaps(this); + if (ret) + goto out; + + ret = glusterd_resolve_all_bricks(this); + if (ret) + goto out; + + ret = glusterd_snap_cleanup(this); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_CLEANUP_FAIL, + "Failed to perform " + "a cleanup of the snapshots"); + goto out; + } + + ret = glusterd_recreate_all_snap_brick_mounts(this); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_SNAP_BRK_MNT_RECREATE_FAIL, + "Failed to recreate " + "all snap brick mounts"); + goto out; + } + +out: + gf_msg_debug(this->name, 0, "Returning %d", ret); + return ret; +} + +int +glusterd_store_retrieve_quota_version(glusterd_volinfo_t *volinfo) +{ + int ret = -1; + uint32_t version = 0; + char cksum_path[PATH_MAX] = { + 0, + }; + char path[PATH_MAX] = { + 0, + }; + char *version_str = NULL; + char *tmp = NULL; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + gf_store_handle_t *handle = NULL; + int32_t len = 0; + + this = THIS; + GF_ASSERT(this); + conf = this->private; + GF_ASSERT(conf); + + GLUSTERD_GET_VOLUME_DIR(path, volinfo, conf); + len = snprintf(cksum_path, sizeof(cksum_path), "%s/%s", path, + GLUSTERD_VOL_QUOTA_CKSUM_FILE); + if ((len < 0) || (len >= sizeof(cksum_path))) { + goto out; + } + + ret = gf_store_handle_new(cksum_path, &handle); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_HANDLE_GET_FAIL, + "Unable to get store handle " + "for %s", + cksum_path); + goto out; + } + + ret = gf_store_retrieve_value(handle, "version", &version_str); + if (ret) { + gf_msg_debug(this->name, 0, "Version absent"); + ret = 0; + goto out; + } + + version = strtoul(version_str, &tmp, 10); + if ((errno == ERANGE) || (errno == EINVAL)) { + gf_msg_debug(this->name, 0, "Invalid version number"); + goto out; + } + volinfo->quota_conf_version = version; + ret = 0; + +out: + if (version_str) + GF_FREE(version_str); + gf_store_handle_destroy(handle); + return ret; +} + +int +glusterd_store_save_quota_version_and_cksum(glusterd_volinfo_t *volinfo) +{ + gf_store_handle_t *shandle = NULL; + glusterd_conf_t *conf = NULL; + xlator_t *this = NULL; + char path[PATH_MAX] = {0}; + char cksum_path[PATH_MAX + 32] = { + 0, + }; + char buf[64] = {0}; + int fd = -1; + int32_t ret = -1; + int32_t len = 0; + + this = THIS; + conf = this->private; + + GLUSTERD_GET_VOLUME_DIR(path, volinfo, conf); + len = snprintf(cksum_path, sizeof(cksum_path), "%s/%s", path, + GLUSTERD_VOL_QUOTA_CKSUM_FILE); + if ((len < 0) || (len >= sizeof(cksum_path))) { + goto out; + } + + ret = gf_store_handle_new(cksum_path, &shandle); + if (ret) + goto out; + + fd = gf_store_mkstemp(shandle); + if (fd <= 0) { + ret = -1; + goto out; + } + + ret = snprintf(buf, sizeof(buf), "cksum=%u\nversion=%u\n", + volinfo->quota_conf_cksum, volinfo->quota_conf_version); + if (ret < 0 || ret >= sizeof(buf)) { + ret = -1; + goto out; + } + + ret = gf_store_save_items(fd, buf); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_CKSUM_STORE_FAIL, + "Failed to store quota cksum and version"); + goto out; + } + + ret = gf_store_rename_tmppath(shandle); + if (ret) + goto out; out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; + if ((ret < 0) && (fd > 0)) + gf_store_unlink_tmppath(shandle); + gf_store_handle_destroy(shandle); + return ret; +} + +int32_t +glusterd_quota_conf_write_header(int fd) +{ + int header_len = 0; + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + + this = THIS; + GF_VALIDATE_OR_GOTO("quota", this, out); + + conf = this->private; + GF_VALIDATE_OR_GOTO(this->name, conf, out); + + if (conf->op_version < GD_OP_VERSION_3_7_0) { + header_len = SLEN(QUOTA_CONF_HEADER_1_1); + ret = gf_nwrite(fd, QUOTA_CONF_HEADER_1_1, header_len); + } else { + header_len = SLEN(QUOTA_CONF_HEADER); + ret = gf_nwrite(fd, QUOTA_CONF_HEADER, header_len); + } + + if (ret != header_len) { + ret = -1; + goto out; + } + + ret = 0; + +out: + if (ret < 0) + gf_msg_callingfn("quota", GF_LOG_ERROR, 0, GD_MSG_QUOTA_CONF_WRITE_FAIL, + "failed to write " + "header to a quota conf"); + + return ret; +} + +int32_t +glusterd_quota_conf_write_gfid(int fd, void *buf, char type) +{ + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + + this = THIS; + GF_VALIDATE_OR_GOTO("quota", this, out); + + conf = this->private; + GF_VALIDATE_OR_GOTO(this->name, conf, out); + + ret = gf_nwrite(fd, buf, 16); + if (ret != 16) { + ret = -1; + goto out; + } + + if (conf->op_version >= GD_OP_VERSION_3_7_0) { + ret = gf_nwrite(fd, &type, 1); + if (ret != 1) { + ret = -1; + goto out; + } + } + + ret = 0; + +out: + if (ret < 0) + gf_msg_callingfn("quota", GF_LOG_ERROR, 0, GD_MSG_QUOTA_CONF_WRITE_FAIL, + "failed to write " + "gfid %s to a quota conf", + uuid_utoa(buf)); + + return ret; } |
