/* Copyright (c) 2013 Red Hat, Inc. 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. */ #include "glusterd-volgen.h" #include "glusterd-utils.h" static int validate_tier (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { char errstr[2048] = ""; int ret = 0; xlator_t *this = NULL; int origin_val = -1; char *current_wm_hi = NULL; char *current_wm_low = NULL; uint64_t wm_hi = 0; uint64_t wm_low = 0; this = THIS; GF_ASSERT (this); if (volinfo->type != GF_CLUSTER_TYPE_TIER) { snprintf (errstr, sizeof (errstr), "Volume %s is not a tier " "volume. Option %s is only valid for tier volume.", volinfo->volname, key); gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INCOMPATIBLE_VALUE, "%s", errstr); *op_errstr = gf_strdup (errstr); ret = -1; goto out; } if (strstr (key, "cluster.tier-mode")) { if (strcmp(value, "test") && strcmp(value, "cache")) { ret = -1; goto out; } goto out; } else if (strstr (key, "tier-pause")) { if (strcmp(value, "off") && strcmp(value, "on")) { ret = -1; goto out; } goto out; } /* * Rest of the volume set options for tier are expecting a positive * Integer. Change the function accordingly if this constraint is * changed. */ ret = gf_string2int (value, &origin_val); if (ret) { snprintf (errstr, sizeof (errstr), "%s is not a compatible " "value. %s expects an integer value.", value, key); gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INCOMPATIBLE_VALUE, "%s", errstr); *op_errstr = gf_strdup (errstr); ret = -1; goto out; } if (strstr (key, "watermark-hi") || strstr (key, "watermark-low")) { if ((origin_val < 1) || (origin_val > 99)) { snprintf (errstr, sizeof (errstr), "%s is not a " "compatible value. %s expects a " "percentage from 1-99.", value, key); gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INCOMPATIBLE_VALUE, "%s", errstr); *op_errstr = gf_strdup (errstr); ret = -1; goto out; } if (strstr (key, "watermark-hi")) { wm_hi = origin_val; } else { glusterd_volinfo_get (volinfo, "cluster.watermark-hi", ¤t_wm_hi); gf_string2bytesize_uint64 (current_wm_hi, &wm_hi); } if (strstr (key, "watermark-low")) { wm_low = origin_val; } else { glusterd_volinfo_get (volinfo, "cluster.watermark-low", ¤t_wm_low); gf_string2bytesize_uint64 (current_wm_low, &wm_low); } if (wm_low > wm_hi) { snprintf (errstr, sizeof (errstr), "lower watermark" " cannot exceed upper watermark."); gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INCOMPATIBLE_VALUE, "%s", errstr); *op_errstr = gf_strdup (errstr); ret = -1; goto out; } } else if (strstr (key, "tier-promote-frequency") || strstr (key, "tier-max-mb") || strstr (key, "tier-max-files") || strstr (key, "tier-demote-frequency")) { if (origin_val < 1) { snprintf (errstr, sizeof (errstr), "%s is not a " " compatible value. %s expects a positive " "integer value greater than 0.", value, key); gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INCOMPATIBLE_VALUE, "%s", errstr); *op_errstr = gf_strdup (errstr); ret = -1; goto out; } } else { /* check write-freq-threshold and read-freq-threshold. */ if (origin_val < 0) { snprintf (errstr, sizeof (errstr), "%s is not a " "compatible value. %s expects a positive" " integer value.", value, key); gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INCOMPATIBLE_VALUE, "%s", errstr); *op_errstr = gf_strdup (errstr); ret = -1; goto out; } } out: gf_msg_debug (this->name, 0, "Returning %d", ret); return ret; } static int validate_cache_max_min_size (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { char *current_max_value = NULL; char *current_min_value = NULL; char errstr[2048] = ""; glusterd_conf_t *priv = NULL; int ret = 0; uint64_t max_value = 0; uint64_t min_value = 0; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); if ((!strcmp (key, "performance.cache-min-file-size")) || (!strcmp (key, "cache-min-file-size"))) { glusterd_volinfo_get (volinfo, "performance.cache-max-file-size", ¤t_max_value); if (current_max_value) { gf_string2bytesize_uint64 (current_max_value, &max_value); gf_string2bytesize_uint64 (value, &min_value); current_min_value = value; } } else if ((!strcmp (key, "performance.cache-max-file-size")) || (!strcmp (key, "cache-max-file-size"))) { glusterd_volinfo_get (volinfo, "performance.cache-min-file-size", ¤t_min_value); if (current_min_value) { gf_string2bytesize_uint64 (current_min_value, &min_value); gf_string2bytesize_uint64 (value, &max_value); current_max_value = value; } } if (min_value > max_value) { snprintf (errstr, sizeof (errstr), "cache-min-file-size (%s) is greater than " "cache-max-file-size (%s)", current_min_value, current_max_value); gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_CACHE_MINMAX_SIZE_INVALID, "%s", errstr); *op_errstr = gf_strdup (errstr); ret = -1; goto out; } out: gf_msg_debug (this->name, 0, "Returning %d", ret); return ret; } static int validate_defrag_throttle_option (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { char errstr[2048] = ""; glusterd_conf_t *priv = NULL; int ret = 0; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); if (!strcasecmp (value, "lazy") || !strcasecmp (value, "normal") || !strcasecmp (value, "aggressive")) { ret = 0; } else { ret = -1; snprintf (errstr, sizeof (errstr), "%s should be " "{lazy|normal|aggressive}", key); gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY, "%s", errstr); *op_errstr = gf_strdup (errstr); } gf_msg_debug (this->name, 0, "Returning %d", ret); return ret; } static int validate_quota (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { char errstr[2048] = ""; glusterd_conf_t *priv = NULL; int ret = 0; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); ret = glusterd_volinfo_get_boolean (volinfo, VKEY_FEATURES_QUOTA); if (ret == -1) { gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_QUOTA_GET_STAT_FAIL, "failed to get the quota status"); goto out; } if (ret == _gf_false) { snprintf (errstr, sizeof (errstr), "Cannot set %s. Enable quota first.", key); gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_QUOTA_DISABLED, "%s", errstr); *op_errstr = gf_strdup (errstr); ret = -1; goto out; } ret = 0; out: gf_msg_debug (this->name, 0, "Returning %d", ret); return ret; } static int validate_uss (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { char errstr[2048] = ""; int ret = 0; xlator_t *this = NULL; gf_boolean_t b = _gf_false; this = THIS; GF_ASSERT (this); ret = gf_string2boolean (value, &b); if (ret) { snprintf (errstr, sizeof (errstr), "%s is not a valid boolean " "value. %s expects a valid boolean value.", value, key); gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY, "%s", errstr); *op_errstr = gf_strdup (errstr); goto out; } out: gf_msg_debug (this->name, 0, "Returning %d", ret); return ret; } static int validate_stripe (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { char errstr[2048] = ""; glusterd_conf_t *priv = NULL; int ret = 0; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); if (volinfo->stripe_count == 1) { snprintf (errstr, sizeof (errstr), "Cannot set %s for a non-stripe volume.", key); gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_NON_STRIPE_VOL, "%s", errstr); *op_errstr = gf_strdup (errstr); ret = -1; goto out; } out: gf_msg_debug (this->name, 0, "Returning %d", ret); return ret; } static int validate_replica (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { char errstr[2048] = ""; int ret = 0; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); if (volinfo->replica_count == 1) { snprintf (errstr, sizeof (errstr), "Cannot set %s for a non-replicate volume.", key); gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_NOT_REPLICA, "%s", errstr); *op_errstr = gf_strdup (errstr); ret = -1; goto out; } out: gf_msg_debug (this->name, 0, "Returning %d", ret); return ret; } static int validate_subvols_per_directory (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { char errstr[2048] = ""; glusterd_conf_t *priv = NULL; int ret = 0; int subvols = 0; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); subvols = atoi(value); /* Checking if the subvols-per-directory exceed the total number of subvolumes. */ if (subvols > volinfo->subvol_count) { snprintf (errstr, sizeof(errstr), "subvols-per-directory(%d) is greater " "than the number of subvolumes(%d).", subvols, volinfo->subvol_count); gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_SUBVOLUMES_EXCEED, "%s.", errstr); *op_errstr = gf_strdup (errstr); ret = -1; goto out; } out: gf_msg_debug (this->name, 0, "Returning %d", ret); return ret; } static int validate_replica_heal_enable_disable (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { int ret = 0; if (!glusterd_is_volume_replicate (volinfo)) { gf_asprintf (op_errstr, "Volume %s is not of replicate type", volinfo->volname); ret = -1; } return ret; } static int validate_disperse_heal_enable_disable (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { int ret = 0; if (volinfo->type == GF_CLUSTER_TYPE_TIER) { if (volinfo->tier_info.cold_type != GF_CLUSTER_TYPE_DISPERSE && volinfo->tier_info.hot_type != GF_CLUSTER_TYPE_DISPERSE) { gf_asprintf (op_errstr, "Volume %s is not containing " "disperse type", volinfo->volname); return -1; } else return 0; } if (volinfo->type != GF_CLUSTER_TYPE_DISPERSE) { gf_asprintf (op_errstr, "Volume %s is not of disperse type", volinfo->volname); ret = -1; } return ret; } /* dispatch table for VOLUME SET * ----------------------------- * * Format of entries: * * First field is the , for the purpose of looking it up * in volume dictionary. Each is of the format ".". * * Second field is . * * Third field is