/* 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" #if USE_GFDB /* no GFDB means tiering is disabled */ static int get_tier_freq_threshold (glusterd_volinfo_t *volinfo, char *threshold_key) { int threshold = 0; char *str_thresold = NULL; int ret = -1; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); glusterd_volinfo_get (volinfo, threshold_key, &str_thresold); if (str_thresold) { ret = gf_string2int (str_thresold, &threshold); if (ret == -1) { threshold = ret; gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INCOMPATIBLE_VALUE, "Failed to convert " "string to integer"); } } return threshold; } /* * Validation function for record-counters * if write-freq-threshold and read-freq-threshold both have non-zero values * record-counters cannot be set to off * if record-counters is set to on * check if both the frequency thresholds are zero, then pop * a note, but volume set is not failed. * */ static int validate_tier_counters (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { char errstr[2048] = ""; int ret = -1; xlator_t *this = NULL; gf_boolean_t origin_val = -1; int current_wt = 0; int current_rt = 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); goto out; } ret = gf_string2boolean (value, &origin_val); if (ret) { snprintf (errstr, sizeof (errstr), "%s is not a compatible " "value. %s expects an boolean value", value, key); goto out; } current_rt = get_tier_freq_threshold (volinfo, "cluster.read-freq-threshold"); if (current_rt == -1) { snprintf (errstr, sizeof (errstr), " Failed to retrieve value" " of cluster.read-freq-threshold"); goto out; } current_wt = get_tier_freq_threshold (volinfo, "cluster.write-freq-threshold"); if (current_wt == -1) { snprintf (errstr, sizeof (errstr), " Failed to retrieve value " "of cluster.write-freq-threshold"); goto out; } /* If record-counters is set to off */ if (!origin_val) { /* Both the thresholds should be zero to set * record-counters to off*/ if (current_rt || current_wt) { snprintf (errstr, sizeof (errstr), "Cannot set features.record-counters to \"%s\"" " as cluster.write-freq-threshold is %d" " and cluster.read-freq-threshold is %d. Please" " set both cluster.write-freq-threshold and " " cluster.read-freq-threshold to 0, to set " " features.record-counters to \"%s\".", value, current_wt, current_rt, value); ret = -1; goto out; } } /* TODO give a warning message to the user. errstr without re = -1 will * not result in a warning on cli for now. else { if (!current_rt && !current_wt) { snprintf (errstr, sizeof (errstr), " Note : cluster.write-freq-threshold is %d" " and cluster.read-freq-threshold is %d. Please" " set both cluster.write-freq-threshold and " " cluster.read-freq-threshold to" " appropriate positive values.", current_wt, current_rt); } }*/ ret = 0; out: if (ret) { gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INCOMPATIBLE_VALUE, "%s", errstr); *op_errstr = gf_strdup (errstr); } return ret; } /* * Validation function for ctr sql params * features.ctr-sql-db-cachesize (Range: 1000 to 262144 pages) * features.ctr-sql-db-wal-autocheckpoint (Range: 1000 to 262144 pages) * */ static int validate_ctr_sql_params (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { int ret = -1; xlator_t *this = NULL; char errstr[2048] = ""; int origin_val = -1; this = THIS; GF_ASSERT (this); 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); ret = -1; goto out; } if (origin_val < 0) { snprintf (errstr, sizeof (errstr), "%s is not a " "compatible value. %s expects a positive" "integer value.", value, key); ret = -1; goto out; } if (strstr (key, "sql-db-cachesize") || strstr (key, "sql-db-wal-autocheckpoint")) { if ((origin_val < 1000) || (origin_val > 262144)) { snprintf (errstr, sizeof (errstr), "%s is not a " "compatible value. %s " "expects a value between : " "1000 to 262144.", value, key); ret = -1; goto out; } } ret = 0; out: if (ret) { gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INCOMPATIBLE_VALUE, "%s", errstr); *op_errstr = gf_strdup (errstr); } return ret; } /* Validation for tiering frequency thresholds * If any of the frequency thresholds are set to a non-zero value, * switch record-counters on, if not already on * If both the frequency thresholds are set to zero, * switch record-counters off, if not already off * */ static int validate_tier_thresholds (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { char errstr[2048] = ""; int ret = -1; xlator_t *this = NULL; int origin_val = -1; gf_boolean_t current_rc = _gf_false; int current_wt = 0; int current_rt = 0; gf_boolean_t is_set_rc = _gf_false; char *proposed_rc = NULL; 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); goto out; } 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); ret = -1; goto out; } if (origin_val < 0) { snprintf (errstr, sizeof (errstr), "%s is not a " "compatible value. %s expects a positive" "integer value.", value, key); ret = -1; goto out; } /* Get the record-counters value */ ret = glusterd_volinfo_get_boolean (volinfo, "features.record-counters"); if (ret == -1) { snprintf (errstr, sizeof (errstr), "Failed to retrieve value of" "features.record-counters from volume info"); goto out; } current_rc = ret; /* if any of the thresholds are set to a non-zero value * switch record-counters on, if not already on*/ if (origin_val > 0) { if (!current_rc) { is_set_rc = _gf_true; current_rc = _gf_true; } } else { /* if the set is for write-freq-threshold */ if (strstr (key, "write-freq-threshold")) { current_rt = get_tier_freq_threshold (volinfo, "cluster.read-freq-threshold"); if (current_rt == -1) { snprintf (errstr, sizeof (errstr), " Failed to retrieve value of" "cluster.read-freq-threshold"); goto out; } current_wt = origin_val; } /* else it should be read-freq-threshold */ else { current_wt = get_tier_freq_threshold (volinfo, "cluster.write-freq-threshold"); if (current_wt == -1) { snprintf (errstr, sizeof (errstr), " Failed to retrieve value of" "cluster.write-freq-threshold"); goto out; } current_rt = origin_val; } /* Since both the thresholds are zero, set record-counters * to off, if not already off */ if (current_rt == 0 && current_wt == 0) { if (current_rc) { is_set_rc = _gf_true; current_rc = _gf_false; } } } /* if record-counter has to be set to proposed value */ if (is_set_rc) { if (current_rc) { ret = gf_asprintf (&proposed_rc, "on"); } else { ret = gf_asprintf (&proposed_rc, "off"); } if (ret < 0) { gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INCOMPATIBLE_VALUE, "Failed to allocate memory to dict_value"); goto error; } ret = dict_set_str (volinfo->dict, "features.record-counters", proposed_rc); error: if (ret) { snprintf (errstr, sizeof (errstr), "Failed to set features.record-counters" "to \"%s\" automatically." "Please try to set features.record-counters " "\"%s\" manually. The options " "cluster.write-freq-threshold and " "cluster.read-freq-threshold can only " "be set to a non zero value, if " "features.record-counters is " "set to \"on\".", proposed_rc, proposed_rc); goto out; } } ret = 0; out: if (ret) { gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INCOMPATIBLE_VALUE, "%s", errstr); *op_errstr = gf_strdup (errstr); if (proposed_rc) GF_FREE (proposed_rc); } return ret; } 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; } else if (strstr (key, "tier-compact")) { if (strcmp (value, "on") && strcmp (value, "off")) { 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 be equal or 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-promote-file-size") || strstr (key, "tier-max-files") || strstr (key, "tier-demote-frequency") || strstr (key, "tier-hot-compact-frequency") || strstr (key, "tier-cold-compact-frequency") || strstr (key, "tier-query-limit")) { 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; } } out: gf_msg_debug (this->name, 0, "Returning %d", ret); return ret; } #endif /* End for USE_GFDB */ 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] = ""; int ret = 0; xlator_t *this = NULL; int thread_count = 0; long int cores_available = 0; this = THIS; GF_ASSERT (this); cores_available = sysconf(_SC_NPROCESSORS_ONLN); /* Throttle option should be one of lazy|normal|aggressive or a number * configured by user max up to the number of cores in the machine */ if (!strcasecmp (value, "lazy") || !strcasecmp (value, "normal") || !strcasecmp (value, "aggressive")) { ret = 0; } else if ((gf_string2int (value, &thread_count) == 0)) { if ((thread_count > 0) && (thread_count <= cores_available)) { ret = 0; } else { ret = -1; snprintf (errstr, sizeof (errstr), "%s should be within" " range of 0 and maximum number of cores " "available (cores available - %ld)", key, cores_available); gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY, "%s", errstr); *op_errstr = gf_strdup (errstr); } } else { ret = -1; snprintf (errstr, sizeof (errstr), "%s should be " "{lazy|normal|aggressive} or a number up to number of" " cores available (cores available - %ld)", key, cores_available); 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_uss_dir (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { char errstr[2048] = ""; int ret = -1; int i = 0; xlator_t *this = NULL; this = THIS; GF_ASSERT (this); i = strlen (value); if (i > NAME_MAX) { snprintf (errstr, sizeof (errstr), "value of %s exceedes %d " "characters", key, NAME_MAX); goto out; } else if (i < 2) { snprintf (errstr, sizeof (errstr), "value of %s too short, " "expects atleast two characters", key); goto out; } if (value[0] != '.') { snprintf (errstr, sizeof (errstr), "%s expects value starting " "with '.' ", key); goto out; } for (i = 1; value[i]; i++) { if (isalnum (value[i]) || value[i] == '_' || value[i] == '-') continue; snprintf (errstr, sizeof (errstr), "%s expects value to" " contain only '0-9a-z-_'", key); goto out; } ret = 0; out: if (ret) { 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_server_options (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { char errstr[2048] = ""; xlator_t *this = NULL; int ret = -1; int origin_val = 0; this = THIS; GF_ASSERT (this); if (volinfo->status == GLUSTERD_STATUS_STARTED) { gf_msg (this->name, GF_LOG_INFO, 0, GD_MSG_VOL_SET_VALIDATION_INFO, "Please note that " "volume %s is started. This option will only get " "effected after a brick restart.", volinfo->volname); } 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); ret = -1; goto out; } if (origin_val < 0) { snprintf (errstr, sizeof (errstr), "%s is not a " "compatible value. %s expects a positive" "integer value.", value, key); ret = -1; goto out; } ret = 0; out: if (ret) { gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INCOMPATIBLE_VALUE, "%s", errstr); *op_errstr = gf_strdup (errstr); } 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_disperse (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { char errstr[2048] = ""; int ret = -1; xlator_t *this = NULL; this = THIS; GF_VALIDATE_OR_GOTO ("glusterd", this, out); if (volinfo->type != GF_CLUSTER_TYPE_DISPERSE) { snprintf (errstr, sizeof (errstr), "Cannot set %s for a non-disperse volume.", key); gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_VOL_NOT_DISPERSE, "%s", errstr); *op_errstr = gf_strdup (errstr); ret = -1; goto out; } ret = 0; out: gf_msg_debug (ret == 0 ? THIS->name : "glusterd", 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_mandatory_locking (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 (strcmp (value, "off") != 0 && strcmp (value, "file") != 0 && strcmp(value, "forced") != 0 && strcmp(value, "optimal") != 0) { snprintf (errstr, sizeof(errstr), "Invalid option value '%s':" " Available options are 'off', 'file', " "'forced' or 'optimal'", value); gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY, "%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_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; } static int validate_lock_migration_option (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); if (volinfo->replica_count > 1 || volinfo->disperse_count || volinfo->type == GF_CLUSTER_TYPE_TIER) { snprintf (errstr, sizeof (errstr), "Lock migration is " "a experimental feature. Currently works with" " pure distribute volume only"); ret = -1; gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY, "%s", errstr); *op_errstr = gf_strdup (errstr); goto out; } ret = gf_string2boolean (value, &b); if (ret) { snprintf (errstr, sizeof (errstr), "Invalid value" " for volume set command. Use on/off only."); ret = -1; gf_msg (this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY, "%s", errstr); *op_errstr = gf_strdup (errstr); goto out; } gf_msg_debug (this->name, 0, "Returning %d", ret); out: return ret; } static int validate_mux_limit (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { xlator_t *this = NULL; uint val = 0; int ret = -1; this = THIS; GF_VALIDATE_OR_GOTO ("glusterd", this, out); if (!is_brick_mx_enabled()) { gf_asprintf (op_errstr, "Brick-multiplexing is not enabled. " "Please enable brick multiplexing before trying " "to set this option."); gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_WRONG_OPTS_SETTING, "%s", *op_errstr); goto out; } ret = gf_string2uint (value, &val); if (ret) { gf_asprintf (op_errstr, "%s is not a valid count. " "%s expects an unsigned integer.", value, key); gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY, "%s", *op_errstr); } if (val == 1) { gf_asprintf (op_errstr, "Brick-multiplexing is enabled. " "Please set this option to a value other than 1 " "to make use of the brick-multiplexing feature."); ret = -1; goto out; } out: gf_msg_debug ("glusterd", 0, "Returning %d", ret); return ret; } static int validate_boolean (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { xlator_t *this = NULL; gf_boolean_t b = _gf_false; int ret = -1; this = THIS; GF_VALIDATE_OR_GOTO ("glusterd", this, out); ret = gf_string2boolean (value, &b); if (ret) { gf_asprintf (op_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", *op_errstr); } out: gf_msg_debug ("glusterd", 0, "Returning %d", ret); return ret; } static int validate_parallel_readdir (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { int ret = -1; ret = validate_boolean (volinfo, dict, key, value, op_errstr); if (ret) goto out; ret = glusterd_is_defrag_on (volinfo); if (ret) { gf_asprintf (op_errstr, "%s option should be set " "after rebalance is complete", key); gf_msg ("glusterd", GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY, "%s", *op_errstr); } out: gf_msg_debug ("glusterd", 0, "Returning %d", ret); return ret; } static int validate_rda_cache_limit (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { int ret = 0; uint64_t rda_cache_size = 0; ret = gf_string2bytesize_uint64 (value, &rda_cache_size); if (ret < 0) goto out; if (rda_cache_size <= (1 * GF_UNIT_GB)) goto out; /* With release 3.11 the max value of rda_cache_limit is changed from * 1GB to INFINITY. If there are clients older than 3.11 and the value * of rda-cache-limit is set to > 1GB, the older clients will stop * working. Hence if a user is setting rda-cache-limit to > 1GB * ensure that all the clients are 3.11 or greater. */ ret = glusterd_check_client_op_version_support (volinfo->volname, GD_OP_VERSION_3_11_0, op_errstr); out: gf_msg_debug ("glusterd", 0, "Returning %d", ret); return ret; } static int validate_worm_period (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { xlator_t *this = NULL; uint64_t period = -1; int ret = -1; this = THIS; GF_VALIDATE_OR_GOTO ("glusterd", this, out); ret = gf_string2uint64 (value, &period); if (ret) { gf_asprintf (op_errstr, "%s is not a valid uint64_t value." " %s expects a valid uint64_t value.", value, key); gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY, "%s", *op_errstr); } out: gf_msg_debug ("glusterd", 0, "Returning %d", ret); return ret; } static int validate_reten_mode (glusterd_volinfo_t *volinfo, dict_t *dict, char *key, char *value, char **op_errstr) { xlator_t *this = NULL; int ret = -1; this = THIS; GF_VALIDATE_OR_GOTO ("glusterd", this, out); if ((strcmp (value, "relax") && strcmp (value, "enterprise"))) { gf_asprintf (op_errstr, "The value of retention mode should be " "either relax or enterprise. But the value" " of %s is %s", key, value); gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_INVALID_ENTRY, "%s", *op_errstr); ret = -1; goto out; } ret = 0; out: gf_msg_debug ("glusterd", 0, "Returning %d", ret); 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