diff options
Diffstat (limited to 'libglusterfs/src/xlator.c')
| -rw-r--r-- | libglusterfs/src/xlator.c | 2482 |
1 files changed, 1366 insertions, 1116 deletions
diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c index dcdf40f7120..9a2582d45d5 100644 --- a/libglusterfs/src/xlator.c +++ b/libglusterfs/src/xlator.c @@ -1,1343 +1,1593 @@ /* - Copyright (c) 2006-2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.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 Affero General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 "xlator.h" +#include "glusterfs/xlator.h" #include <dlfcn.h> #include <netdb.h> #include <fnmatch.h> -#include "defaults.h" +#include "glusterfs/defaults.h" +#include "glusterfs/libglusterfs-messages.h" +#define SET_DEFAULT_FOP(fn) \ + do { \ + if (!xl->fops->fn) \ + xl->fops->fn = default_##fn; \ + if (!xl->pass_through_fops->fn) \ + xl->pass_through_fops->fn = default_##fn; \ + } while (0) -#define SET_DEFAULT_FOP(fn) do { \ - if (!xl->fops->fn) \ - xl->fops->fn = default_##fn; \ - } while (0) +#define SET_DEFAULT_CBK(fn) \ + do { \ + if (!xl->cbks->fn) \ + xl->cbks->fn = default_##fn; \ + } while (0) -#define SET_DEFAULT_CBK(fn) do { \ - if (!xl->cbks->fn) \ - xl->cbks->fn = default_##fn; \ - } while (0) +pthread_mutex_t xlator_init_mutex = PTHREAD_MUTEX_INITIALIZER; +void +xlator_init_lock(void) +{ + (void)pthread_mutex_lock(&xlator_init_mutex); +} + +void +xlator_init_unlock(void) +{ + (void)pthread_mutex_unlock(&xlator_init_mutex); +} -#define GF_OPTION_LIST_EMPTY(_opt) (_opt->value[0] == NULL) +static struct xlator_cbks default_cbks = {}; +struct volume_options default_options[] = { + { + .key = {"log-level"}, + .type = GF_OPTION_TYPE_STR, + .op_version = {GD_OP_VERSION_6_0}, + .flags = OPT_FLAG_SETTABLE, + .tags = {"generic"}, + .value = {"DEBUG", "WARNING", "ERROR", "INFO", "CRITICAL", "NONE", + "TRACE"}, + .description = "Option to set log-level of given translator", + }, + { + .key = {NULL}, + }, +}; + +/* Handle the common options in each translator */ +void +handle_default_options(xlator_t *xl, dict_t *options) +{ + int ret; + char *value; + + /* log-level */ + ret = dict_get_str(options, "log-level", &value); + if (!ret) { + int log_level = glusterd_check_log_level(value); + if (log_level != -1) { + xl->loglevel = log_level; + } + } +} static void -fill_defaults (xlator_t *xl) +fill_defaults(xlator_t *xl) { - if (xl == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return; - } - - SET_DEFAULT_FOP (create); - SET_DEFAULT_FOP (open); - SET_DEFAULT_FOP (stat); - SET_DEFAULT_FOP (readlink); - SET_DEFAULT_FOP (mknod); - SET_DEFAULT_FOP (mkdir); - SET_DEFAULT_FOP (unlink); - SET_DEFAULT_FOP (rmdir); - SET_DEFAULT_FOP (symlink); - SET_DEFAULT_FOP (rename); - SET_DEFAULT_FOP (link); - SET_DEFAULT_FOP (truncate); - SET_DEFAULT_FOP (readv); - SET_DEFAULT_FOP (writev); - SET_DEFAULT_FOP (statfs); - SET_DEFAULT_FOP (flush); - SET_DEFAULT_FOP (fsync); - SET_DEFAULT_FOP (setxattr); - SET_DEFAULT_FOP (getxattr); - SET_DEFAULT_FOP (fsetxattr); - SET_DEFAULT_FOP (fgetxattr); - SET_DEFAULT_FOP (removexattr); - SET_DEFAULT_FOP (opendir); - SET_DEFAULT_FOP (readdir); - SET_DEFAULT_FOP (readdirp); - SET_DEFAULT_FOP (fsyncdir); - SET_DEFAULT_FOP (access); - SET_DEFAULT_FOP (ftruncate); - SET_DEFAULT_FOP (fstat); - SET_DEFAULT_FOP (lk); - SET_DEFAULT_FOP (inodelk); - SET_DEFAULT_FOP (finodelk); - SET_DEFAULT_FOP (entrylk); - SET_DEFAULT_FOP (fentrylk); - SET_DEFAULT_FOP (lookup); - SET_DEFAULT_FOP (rchecksum); - SET_DEFAULT_FOP (xattrop); - SET_DEFAULT_FOP (fxattrop); - SET_DEFAULT_FOP (setattr); - SET_DEFAULT_FOP (fsetattr); - - SET_DEFAULT_FOP (getspec); - - SET_DEFAULT_CBK (release); - SET_DEFAULT_CBK (releasedir); - SET_DEFAULT_CBK (forget); - - if (!xl->notify) - xl->notify = default_notify; - - if (!xl->mem_acct_init) - xl->mem_acct_init = default_mem_acct_init; - - return; + if (xl == NULL) { + gf_msg_callingfn("xlator", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + return; + } + + if (!xl->pass_through_fops) + xl->pass_through_fops = default_fops; + + SET_DEFAULT_FOP(create); + SET_DEFAULT_FOP(open); + SET_DEFAULT_FOP(stat); + SET_DEFAULT_FOP(readlink); + SET_DEFAULT_FOP(mknod); + SET_DEFAULT_FOP(mkdir); + SET_DEFAULT_FOP(unlink); + SET_DEFAULT_FOP(rmdir); + SET_DEFAULT_FOP(symlink); + SET_DEFAULT_FOP(rename); + SET_DEFAULT_FOP(link); + SET_DEFAULT_FOP(truncate); + SET_DEFAULT_FOP(readv); + SET_DEFAULT_FOP(writev); + SET_DEFAULT_FOP(statfs); + SET_DEFAULT_FOP(flush); + SET_DEFAULT_FOP(fsync); + SET_DEFAULT_FOP(setxattr); + SET_DEFAULT_FOP(getxattr); + SET_DEFAULT_FOP(fsetxattr); + SET_DEFAULT_FOP(fgetxattr); + SET_DEFAULT_FOP(removexattr); + SET_DEFAULT_FOP(fremovexattr); + SET_DEFAULT_FOP(opendir); + SET_DEFAULT_FOP(readdir); + SET_DEFAULT_FOP(readdirp); + SET_DEFAULT_FOP(fsyncdir); + SET_DEFAULT_FOP(access); + SET_DEFAULT_FOP(ftruncate); + SET_DEFAULT_FOP(fstat); + SET_DEFAULT_FOP(lk); + SET_DEFAULT_FOP(inodelk); + SET_DEFAULT_FOP(finodelk); + SET_DEFAULT_FOP(entrylk); + SET_DEFAULT_FOP(fentrylk); + SET_DEFAULT_FOP(lookup); + SET_DEFAULT_FOP(rchecksum); + SET_DEFAULT_FOP(xattrop); + SET_DEFAULT_FOP(fxattrop); + SET_DEFAULT_FOP(setattr); + SET_DEFAULT_FOP(fsetattr); + SET_DEFAULT_FOP(fallocate); + SET_DEFAULT_FOP(discard); + SET_DEFAULT_FOP(zerofill); + SET_DEFAULT_FOP(ipc); + SET_DEFAULT_FOP(seek); + SET_DEFAULT_FOP(lease); + SET_DEFAULT_FOP(getactivelk); + SET_DEFAULT_FOP(setactivelk); + SET_DEFAULT_FOP(put); + + SET_DEFAULT_FOP(getspec); + SET_DEFAULT_FOP(icreate); + SET_DEFAULT_FOP(namelink); + SET_DEFAULT_FOP(copy_file_range); + + if (!xl->cbks) + xl->cbks = &default_cbks; + + SET_DEFAULT_CBK(release); + SET_DEFAULT_CBK(releasedir); + SET_DEFAULT_CBK(forget); + + if (!xl->fini) + xl->fini = default_fini; + + if (!xl->notify) + xl->notify = default_notify; + + if (!xl->mem_acct_init) + xl->mem_acct_init = default_mem_acct_init; + + return; } -/* RFC 1123 & 952 */ -static char -valid_host_name (char *address, int length) +int +xlator_set_type_virtual(xlator_t *xl, const char *type) { - int i = 0; - char ret = 1; - - if ((length > 75) || (length == 1)) { - ret = 0; - goto out; - } + GF_VALIDATE_OR_GOTO("xlator", xl, out); + GF_VALIDATE_OR_GOTO("xlator", type, out); - if (!isalnum (address[length - 1])) { - ret = 0; - goto out; - } + xl->type = gf_strdup(type); - for (i = 0; i < length; i++) { - if (!isalnum (address[i]) && (address[i] != '.') - && (address[i] != '-')) { - ret = 0; - goto out; - } - } + if (xl->type) + return 0; out: - return ret; + return -1; } -static char -valid_ipv4_address (char *address, int length) +int +xlator_volopt_dynload(char *xlator_type, void **dl_handle, + volume_opt_list_t *opt_list) { - int octets = 0; - int value = 0; - char *tmp = NULL, *ptr = NULL, *prev = NULL, *endptr = NULL; - char ret = 1; - - tmp = gf_strdup (address); - prev = tmp; - prev = strtok_r (tmp, ".", &ptr); - - while (prev != NULL) - { - octets++; - value = strtol (prev, &endptr, 10); - if ((value > 255) || (value < 0) || (endptr != NULL)) { - ret = 0; - goto out; - } - - prev = strtok_r (NULL, ".", &ptr); + int ret = -1; + int flag = 0; + char *name = NULL; + void *handle = NULL; + xlator_api_t *xlapi = NULL; + volume_option_t *opt = NULL; + + GF_VALIDATE_OR_GOTO("xlator", xlator_type, out); + + /* socket.so doesn't fall under the default xlator directory, hence we + * need this check */ + if (!strstr(xlator_type, "rpc-transport")) + ret = gf_asprintf(&name, "%s/%s.so", XLATORDIR, xlator_type); + else { + flag = 1; + ret = gf_asprintf(&name, "%s/%s.so", XLATORPARENTDIR, xlator_type); + } + if (-1 == ret) { + goto out; + } + + ret = -1; + + gf_msg_trace("xlator", 0, "attempt to load file %s", name); + + handle = dlopen(name, RTLD_NOW); + if (!handle) { + gf_smsg("xlator", GF_LOG_WARNING, 0, LG_MSG_DLOPEN_FAILED, "error=%s", + dlerror(), NULL); + goto out; + } + + if (flag == 0) { + /* check new struct first, and then check this */ + xlapi = dlsym(handle, "xlator_api"); + if (!xlapi) { + gf_smsg("xlator", GF_LOG_ERROR, 0, LG_MSG_DLSYM_ERROR, "error=%s", + dlerror(), NULL); + goto out; } - if (octets != 4) { - ret = 0; + opt_list->given_opt = xlapi->options; + if (!opt_list->given_opt) { + gf_smsg("xlator", GF_LOG_ERROR, 0, LG_MSG_LOAD_FAILED, NULL); + goto out; + } + } else { + opt = dlsym(handle, "options"); + if (!opt) { + gf_smsg("xlator", GF_LOG_ERROR, 0, LG_MSG_DLSYM_ERROR, "error=%s", + dlerror(), NULL); + goto out; } -out: - GF_FREE (tmp); - return ret; -} + opt_list->given_opt = opt; + } -static char -valid_ipv6_address (char *address, int length) -{ - int hex_numbers = 0; - int value = 0; - char *tmp = NULL, *ptr = NULL, *prev = NULL, *endptr = NULL; - char ret = 1; - - tmp = gf_strdup (address); - prev = strtok_r (tmp, ":", &ptr); - - while (prev != NULL) - { - hex_numbers++; - value = strtol (prev, &endptr, 16); - if ((value > 0xffff) || (value < 0) - || (endptr != NULL && *endptr != '\0')) { - ret = 0; - goto out; - } - - prev = strtok_r (NULL, ":", &ptr); - } - - if (hex_numbers > 8) { - ret = 0; - } + *dl_handle = handle; + handle = NULL; + ret = 0; out: - GF_FREE (tmp); - return ret; + GF_FREE(name); + if (handle) + dlclose(handle); + + gf_msg_debug("xlator", 0, "Returning %d", ret); + return ret; } -static char -valid_internet_address (char *address) +static int +xlator_dynload_apis(xlator_t *xl) { - char ret = 0; - int length = 0; - - if (address == NULL) { - goto out; + int ret = -1; + void *handle = NULL; + volume_opt_list_t *vol_opt = NULL; + xlator_api_t *xlapi = NULL; + int i = 0; + + handle = xl->dlhandle; + + xlapi = dlsym(handle, "xlator_api"); + if (!xlapi) { + gf_smsg("xlator", GF_LOG_ERROR, 0, LG_MSG_DLSYM_ERROR, "dlsym=%s", + dlerror(), NULL); + ret = -1; + goto out; + } + + xl->fops = xlapi->fops; + if (!xl->fops) { + gf_smsg("xlator", GF_LOG_WARNING, 0, LG_MSG_STRUCT_MISS, "name=%s", + xl->name, NULL); + goto out; + } + + xl->cbks = xlapi->cbks; + if (!xl->cbks) { + gf_msg_trace("xlator", 0, "%s: struct missing (cbks)", xl->name); + } + + xl->init = xlapi->init; + if (!xl->init) { + gf_smsg("xlator", GF_LOG_WARNING, 0, LG_MSG_METHOD_MISS, "name=%s", + xl->name, NULL); + goto out; + } + + xl->fini = xlapi->fini; + if (!xl->fini) { + gf_msg_trace("xlator", 0, "%s: method missing (fini)", xl->name); + } + + xl->reconfigure = xlapi->reconfigure; + if (!xl->reconfigure) { + gf_msg_trace("xlator", 0, "%s: method missing (reconfigure)", xl->name); + } + xl->notify = xlapi->notify; + if (!xl->notify) { + gf_msg_trace("xlator", 0, "%s: method missing (notify)", xl->name); + } + xl->dumpops = xlapi->dumpops; + if (!xl->dumpops) { + gf_msg_trace("xlator", 0, "%s: method missing (dumpops)", xl->name); + } + xl->mem_acct_init = xlapi->mem_acct_init; + if (!xl->mem_acct_init) { + gf_msg_trace("xlator", 0, "%s: method missing (mem_acct_init)", + xl->name); + } + + xl->dump_metrics = xlapi->dump_metrics; + if (!xl->dump_metrics) { + gf_msg_trace("xlator", 0, "%s: method missing (dump_metrics)", + xl->name); + } + + xl->pass_through_fops = xlapi->pass_through_fops; + if (!xl->pass_through_fops) { + gf_msg_trace("xlator", 0, + "%s: method missing (pass_through_fops), " + "falling back to default", + xl->name); + } + + vol_opt = GF_CALLOC(1, sizeof(volume_opt_list_t), + gf_common_mt_volume_opt_list_t); + if (!vol_opt) { + goto out; + } + INIT_LIST_HEAD(&vol_opt->list); + + vol_opt->given_opt = default_options; + list_add_tail(&vol_opt->list, &xl->volume_options); + + if (xlapi->options) { + vol_opt = GF_CALLOC(1, sizeof(volume_opt_list_t), + gf_common_mt_volume_opt_list_t); + if (!vol_opt) { + goto out; } + INIT_LIST_HEAD(&vol_opt->list); - length = strlen (address); - if (length == 0) { - goto out; - } + vol_opt->given_opt = xlapi->options; + list_add_tail(&vol_opt->list, &xl->volume_options); + } - if (valid_ipv4_address (address, length) - || valid_ipv6_address (address, length) - || valid_host_name (address, length)) { - ret = 1; - } + xl->id = xlapi->xlator_id; + xl->flags = xlapi->flags; + xl->identifier = xlapi->identifier; + xl->category = xlapi->category; -out: - return ret; -} + memcpy(xl->op_version, xlapi->op_version, + sizeof(uint32_t) * GF_MAX_RELEASES); -int -_volume_option_value_validate (xlator_t *xl, - data_pair_t *pair, - volume_option_t *opt) -{ - int i = 0; - int ret = -1; - uint64_t input_size = 0; - long long inputll = 0; - - /* Key is valid, validate the option */ - switch (opt->type) { - case GF_OPTION_TYPE_PATH: - { - if (strstr (pair->value->data, "../")) { - gf_log (xl->name, GF_LOG_ERROR, - "invalid path given '%s'", - pair->value->data); - ret = -1; - goto out; - } - - /* Make sure the given path is valid */ - if (pair->value->data[0] != '/') { - gf_log (xl->name, GF_LOG_WARNING, - "option %s %s: '%s' is not an " - "absolute path name", - pair->key, pair->value->data, - pair->value->data); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_INT: - { - /* Check the range */ - if (gf_string2longlong (pair->value->data, - &inputll) != 0) { - gf_log (xl->name, GF_LOG_ERROR, - "invalid number format \"%s\" in " - "\"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (xl->name, GF_LOG_DEBUG, - "no range check required for " - "'option %s %s'", - pair->key, pair->value->data); - ret = 0; - break; - } - if ((inputll < opt->min) || - (inputll > opt->max)) { - gf_log (xl->name, GF_LOG_WARNING, - "'%lld' in 'option %s %s' is out of " - "range [%"PRId64" - %"PRId64"]", - inputll, pair->key, - pair->value->data, - opt->min, opt->max); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_SIZET: - { - /* Check the range */ - if (gf_string2bytesize (pair->value->data, - &input_size) != 0) { - gf_log (xl->name, GF_LOG_ERROR, - "invalid size format \"%s\" in " - "\"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (xl->name, GF_LOG_DEBUG, - "no range check required for " - "'option %s %s'", - pair->key, pair->value->data); - ret = 0; - break; - } - if ((input_size < opt->min) || - (input_size > opt->max)) { - gf_log (xl->name, GF_LOG_WARNING, - "'%"PRId64"' in 'option %s %s' is " - "out of range [%"PRId64" - %"PRId64"]", - input_size, pair->key, - pair->value->data, - opt->min, opt->max); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_BOOL: - { - /* Check if the value is one of - '0|1|on|off|no|yes|true|false|enable|disable' */ - gf_boolean_t bool_value; - if (gf_string2boolean (pair->value->data, - &bool_value) != 0) { - gf_log (xl->name, GF_LOG_ERROR, - "option %s %s: '%s' is not a valid " - "boolean value", - pair->key, pair->value->data, - pair->value->data); - goto out; - } - ret = 0; - } - break; - case GF_OPTION_TYPE_XLATOR: - { - /* Check if the value is one of the xlators */ - xlator_t *xlopt = xl; - while (xlopt->prev) - xlopt = xlopt->prev; - - while (xlopt) { - if (strcmp (pair->value->data, - xlopt->name) == 0) { - ret = 0; - break; - } - xlopt = xlopt->next; - } - if (!xlopt) { - gf_log (xl->name, GF_LOG_ERROR, - "option %s %s: '%s' is not a " - "valid volume name", - pair->key, pair->value->data, - pair->value->data); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_STR: - { - /* Check if the '*str' is valid */ - if (GF_OPTION_LIST_EMPTY(opt)) { - ret = 0; - goto out; - } - - for (i = 0; (i < ZR_OPTION_MAX_ARRAY_SIZE) && - opt->value[i]; i++) { -#ifdef GF_DARWIN_HOST_OS - if (fnmatch (opt->value[i], pair->value->data, - 0) == 0) { -#else - if (fnmatch (opt->value[i], pair->value->data, - FNM_EXTMATCH) == 0) { -#endif - ret = 0; - break; - } - } - - if ((i == ZR_OPTION_MAX_ARRAY_SIZE) - || ((i < ZR_OPTION_MAX_ARRAY_SIZE) - && (!opt->value[i]))) { - /* enter here only if - * 1. reached end of opt->value array and haven't - * validated input - * OR - * 2. valid input list is less than - * ZR_OPTION_MAX_ARRAY_SIZE and input has not - * matched all possible input values. - */ - char given_array[4096] = {0,}; - for (i = 0; (i < ZR_OPTION_MAX_ARRAY_SIZE) && - opt->value[i]; i++) { - strcat (given_array, opt->value[i]); - strcat (given_array, ", "); - } - - gf_log (xl->name, GF_LOG_ERROR, - "option %s %s: '%s' is not valid " - "(possible options are %s)", - pair->key, pair->value->data, - pair->value->data, given_array); - - goto out; - } - } - break; - case GF_OPTION_TYPE_PERCENT: - { - uint32_t percent = 0; - - - /* Check if the value is valid percentage */ - if (gf_string2percent (pair->value->data, - &percent) != 0) { - gf_log (xl->name, GF_LOG_ERROR, - "invalid percent format \"%s\" " - "in \"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((percent < 0) || (percent > 100)) { - gf_log (xl->name, GF_LOG_ERROR, - "'%d' in 'option %s %s' is out of " - "range [0 - 100]", - percent, pair->key, - pair->value->data); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_PERCENT_OR_SIZET: - { - uint32_t percent = 0; - uint64_t input_size = 0; - - /* Check if the value is valid percentage */ - if (gf_string2percent (pair->value->data, - &percent) == 0) { - if (percent > 100) { - gf_log (xl->name, GF_LOG_DEBUG, - "value given was greater than 100, " - "assuming this is actually a size"); - if (gf_string2bytesize (pair->value->data, - &input_size) == 0) { - /* Check the range */ - if ((opt->min == 0) && - (opt->max == 0)) { - gf_log (xl->name, GF_LOG_DEBUG, - "no range check " - "required for " - "'option %s %s'", - pair->key, - pair->value->data); - // It is a size - ret = 0; - goto out; - } - if ((input_size < opt->min) || - (input_size > opt->max)) { - gf_log (xl->name, GF_LOG_ERROR, - "'%"PRId64"' in " - "'option %s %s' is out" - " of range [%"PRId64"" - "- %"PRId64"]", - input_size, pair->key, - pair->value->data, - opt->min, opt->max); - } - // It is a size - ret = 0; - goto out; - } else { - // It's not a percent or size - gf_log (xl->name, GF_LOG_ERROR, - "invalid number format \"%s\" " - "in \"option %s\"", - pair->value->data, pair->key); - } - - } - // It is a percent - ret = 0; - goto out; - } else { - if (gf_string2bytesize (pair->value->data, - &input_size) == 0) { - /* Check the range */ - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (xl->name, GF_LOG_DEBUG, - "no range check required for " - "'option %s %s'", - pair->key, pair->value->data); - // It is a size - ret = 0; - goto out; - } - if ((input_size < opt->min) || - (input_size > opt->max)) { - gf_log (xl->name, GF_LOG_ERROR, - "'%"PRId64"' in 'option %s %s'" - " is out of range [%"PRId64" -" - " %"PRId64"]", - input_size, pair->key, - pair->value->data, - opt->min, opt->max); - } - } else { - // It's not a percent or size - gf_log (xl->name, GF_LOG_ERROR, - "invalid number format \"%s\" " - "in \"option %s\"", - pair->value->data, pair->key); - } - //It is a size - ret = 0; - goto out; - } - - } - break; - case GF_OPTION_TYPE_TIME: - { - uint32_t input_time = 0; - - /* Check if the value is valid percentage */ - if (gf_string2time (pair->value->data, - &input_time) != 0) { - gf_log (xl->name, - GF_LOG_ERROR, - "invalid time format \"%s\" in " - "\"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (xl->name, GF_LOG_DEBUG, - "no range check required for " - "'option %s %s'", - pair->key, pair->value->data); - ret = 0; - goto out; - } - if ((input_time < opt->min) || - (input_time > opt->max)) { - gf_log (xl->name, GF_LOG_ERROR, - "'%"PRIu32"' in 'option %s %s' is " - "out of range [%"PRId64" - %"PRId64"]", - input_time, pair->key, - pair->value->data, - opt->min, opt->max); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_DOUBLE: - { - double input_time = 0.0; - - /* Check if the value is valid double */ - if (gf_string2double (pair->value->data, - &input_time) != 0) { - gf_log (xl->name, - GF_LOG_ERROR, - "invalid time format \"%s\" in \"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if (input_time < 0.0) { - gf_log (xl->name, - GF_LOG_ERROR, - "invalid time format \"%s\" in \"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (xl->name, GF_LOG_DEBUG, - "no range check required for 'option %s %s'", - pair->key, pair->value->data); - ret = 0; - goto out; - } - ret = 0; - } - break; - case GF_OPTION_TYPE_INTERNET_ADDRESS: - { - if (valid_internet_address (pair->value->data)) { - ret = 0; - } else { - gf_log (xl->name, GF_LOG_ERROR, "internet address '%s'" - " does not conform to standards.", - pair->value->data); - goto out; - } - } - break; - case GF_OPTION_TYPE_ANY: - /* NO CHECK */ - ret = 0; - break; - } - + for (i = 0; i < GF_FOP_MAXVALUE; i++) { + gf_latency_reset(&xl->stats.interval.latencies[i]); + } + + ret = 0; out: - return ret; + return ret; } int -validate_xlator_volume_options (xlator_t *xl, volume_option_t *opt) +xlator_dynload(xlator_t *xl) { - int i = 0; - int ret = -1; - int index = 0; - volume_option_t *trav = NULL; - data_pair_t *pairs = NULL; - - if (!opt) { - ret = 0; - goto out; - } - - /* First search for not supported options, if any report error */ - pairs = xl->options->members_list; - while (pairs) { - ret = -1; - for (index = 0; - opt[index].key && opt[index].key[0] ; index++) { - trav = &(opt[index]); - for (i = 0 ; - (i < ZR_VOLUME_MAX_NUM_KEY) && - trav->key[i]; i++) { - /* Check if the key is valid */ - if (fnmatch (trav->key[i], - pairs->key, FNM_NOESCAPE) == 0) { - ret = 0; - break; - } - } - if (!ret) { - if (i) { - gf_log (xl->name, GF_LOG_WARNING, - "option '%s' is deprecated, " - "preferred is '%s', continuing" - " with correction", - trav->key[i], trav->key[0]); - /* TODO: some bytes lost */ - pairs->key = gf_strdup (trav->key[0]); - } - break; - } - } - if (!ret) { - ret = _volume_option_value_validate (xl, pairs, trav); - if (-1 == ret) { - goto out; - } - } - - pairs = pairs->next; - } - - ret = 0; - out: - return ret; -} + int ret = -1; + char *name = NULL; + void *handle = NULL; -int32_t -xlator_set_type_virtual (xlator_t *xl, const char *type) -{ - if (xl == NULL || type == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return -1; - } + GF_VALIDATE_OR_GOTO("xlator", xl, out); - xl->type = gf_strdup (type); + INIT_LIST_HEAD(&xl->volume_options); - if (xl->type) - return 0; - else - return -1; -} + ret = gf_asprintf(&name, "%s/%s.so", XLATORDIR, xl->type); + if (-1 == ret) { + goto out; + } + ret = -1; -int32_t -xlator_dynload (xlator_t *xl) -{ - int ret = 0; - char *name = NULL; - void *handle = NULL; - volume_opt_list_t *vol_opt = NULL; - - ret = gf_asprintf (&name, "%s/%s.so", XLATORDIR, xl->type); - if (-1 == ret) { - gf_log ("xlator", GF_LOG_ERROR, "asprintf failed"); - return -1; - } + gf_msg_trace("xlator", 0, "attempt to load file %s", name); - gf_log ("xlator", GF_LOG_TRACE, "attempt to load file %s", name); - - handle = dlopen (name, RTLD_NOW|RTLD_GLOBAL); - if (!handle) { - gf_log ("xlator", GF_LOG_DEBUG, "%s", dlerror ()); - GF_FREE (name); - return -1; - } - xl->dlhandle = handle; - - if (!(xl->fops = dlsym (handle, "fops"))) { - gf_log ("xlator", GF_LOG_DEBUG, "dlsym(fops) on %s", - dlerror ()); - GF_FREE (name); - return -1; - } - - if (!(xl->cbks = dlsym (handle, "cbks"))) { - gf_log ("xlator", GF_LOG_DEBUG, "dlsym(cbks) on %s", - dlerror ()); - GF_FREE (name); - return -1; - } - - if (!(xl->init = dlsym (handle, "init"))) { - gf_log ("xlator", GF_LOG_DEBUG, "dlsym(init) on %s", - dlerror ()); - GF_FREE (name); - return -1; - } - - if (!(xl->fini = dlsym (handle, "fini"))) { - gf_log ("xlator", GF_LOG_DEBUG, "dlsym(fini) on %s", - dlerror ()); - GF_FREE (name); - return -1; - } - - if (!(xl->notify = dlsym (handle, "notify"))) { - gf_log ("xlator", GF_LOG_DEBUG, - "dlsym(notify) on %s -- neglecting", dlerror ()); - } - - if (!(xl->dumpops = dlsym (handle, "dumpops"))) { - gf_log ("xlator", GF_LOG_DEBUG, - "dlsym(dumpops) on %s -- neglecting", dlerror ()); - } - - if (!(xl->mem_acct_init = dlsym (handle, "mem_acct_init"))) { - gf_log (xl->name, GF_LOG_DEBUG, - "dlsym(mem_acct_init) on %s -- neglecting", - dlerror ()); - } + handle = dlopen(name, RTLD_NOW); + if (!handle) { + gf_smsg("xlator", GF_LOG_WARNING, 0, LG_MSG_DLOPEN_FAILED, "error=%s", + dlerror(), NULL); + goto out; + } + xl->dlhandle = handle; - if (!(xl->reconfigure = dlsym (handle, "reconfigure"))) { - gf_log ("xlator", GF_LOG_DEBUG, - "dlsym(reconfigure) on %s -- neglecting", - dlerror()); - } - - if (!(xl->validate_options = dlsym (handle, "validate_options"))) { - gf_log ("xlator", GF_LOG_DEBUG, - "dlsym(validate_options) on %s -- neglecting", - dlerror()); - } + ret = xlator_dynload_apis(xl); + if (-1 == ret) + goto out; + + fill_defaults(xl); + + ret = 0; + +out: + GF_FREE(name); + return ret; +} +int +xlator_set_type(xlator_t *xl, const char *type) +{ + int ret = 0; - INIT_LIST_HEAD (&xl->volume_options); + /* Handle 'global' translator differently */ + if (!strncmp(GF_GLOBAL_XLATOR_NAME, type, SLEN(GF_GLOBAL_XLATOR_NAME))) { + volume_opt_list_t *vol_opt = NULL; - vol_opt = GF_CALLOC (1, sizeof (volume_opt_list_t), - gf_common_mt_volume_opt_list_t); + /* set the required values from Global xlator */ + xl->type = gf_strdup(GF_GLOBAL_XLATOR_NAME); + xl->cbks = global_xlator.cbks; + xl->fops = global_xlator.fops; + xl->init = global_xlator.init; + xl->fini = global_xlator.fini; + xl->reconfigure = global_xlator.reconfigure; + vol_opt = GF_CALLOC(1, sizeof(volume_opt_list_t), + gf_common_mt_volume_opt_list_t); if (!vol_opt) { - GF_FREE (name); - return -1; + ret = -1; + goto out; } - if (!(vol_opt->given_opt = dlsym (handle, "options"))) { - dlerror (); - gf_log (xl->name, GF_LOG_DEBUG, - "Strict option validation not enforced -- neglecting"); - } - list_add_tail (&vol_opt->list, &xl->volume_options); + vol_opt->given_opt = global_xl_options; - fill_defaults (xl); + INIT_LIST_HEAD(&xl->volume_options); + INIT_LIST_HEAD(&vol_opt->list); + list_add_tail(&vol_opt->list, &xl->volume_options); - GF_FREE (name); - return 0; -} + fill_defaults(xl); + ret = 0; + goto out; + } + ret = xlator_set_type_virtual(xl, type); + if (!ret) + ret = xlator_dynload(xl); +out: + return ret; +} -int32_t -xlator_set_type (xlator_t *xl, const char *type) +void +xlator_set_inode_lru_limit(xlator_t *this, void *data) { - int ret = 0; + int inode_lru_limit = 0; - ret = xlator_set_type_virtual (xl, type); - if (!ret) - ret = xlator_dynload (xl); + if (this->itable) { + if (!data) { + gf_smsg(this->name, GF_LOG_WARNING, 0, LG_MSG_INPUT_DATA_NULL, + NULL); + goto out; + } + inode_lru_limit = *(int *)data; + inode_table_set_lru_limit(this->itable, inode_lru_limit); + } - return ret; +out: + return; } - void -xlator_foreach (xlator_t *this, - void (*fn)(xlator_t *each, - void *data), - void *data) +xlator_foreach(xlator_t *this, void (*fn)(xlator_t *each, void *data), + void *data) { - xlator_t *first = NULL; + xlator_t *first = NULL; + xlator_t *old_THIS = NULL; + + GF_VALIDATE_OR_GOTO("xlator", this, out); + GF_VALIDATE_OR_GOTO("xlator", fn, out); - if (this == NULL || fn == NULL || data == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return; - } + first = this; - first = this; + while (first->prev) + first = first->prev; - while (first->prev) - first = first->prev; + while (first) { + old_THIS = THIS; + THIS = first; + + fn(first, data); + + THIS = old_THIS; + first = first->next; + } - while (first) { - fn (first, data); - first = first->next; - } +out: + return; } +void +xlator_foreach_depth_first(xlator_t *this, + void (*fn)(xlator_t *each, void *data), void *data) +{ + xlator_list_t *subv = NULL; + + subv = this->children; + + while (subv) { + xlator_foreach_depth_first(subv->xlator, fn, data); + subv = subv->next; + } + + fn(this, data); +} xlator_t * -xlator_search_by_name (xlator_t *any, const char *name) +xlator_search_by_name(xlator_t *any, const char *name) { - xlator_t *search = NULL; + xlator_t *search = NULL; + + GF_VALIDATE_OR_GOTO("xlator", any, out); + GF_VALIDATE_OR_GOTO("xlator", name, out); + + search = any; - if (any == NULL || name == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return NULL; - } + while (search->prev) + search = search->prev; - search = any; + while (search) { + if (!strcmp(search->name, name)) + break; + search = search->next; + } - while (search->prev) - search = search->prev; +out: + return search; +} - while (search) { - if (!strcmp (search->name, name)) - break; - search = search->next; - } +/* + * With brick multiplexing, we sort of have multiple graphs, so + * xlator_search_by_name might not find what we want. Also, the translator + * we're looking for might not be a direct child if something else was put in + * between (as already happened with decompounder before that was fixed) and + * it's hard to debug why our translator wasn't found. Using a recursive tree + * search instead of a linear search works around both problems. + */ +static xlator_t * +get_xlator_by_name_or_type(xlator_t *this, char *target, int is_name) +{ + xlator_list_t *trav; + xlator_t *child_xl; + char *value; + + for (trav = this->children; trav; trav = trav->next) { + value = is_name ? trav->xlator->name : trav->xlator->type; + if (!strcmp(value, target) && !trav->xlator->cleanup_starting) { + return trav->xlator; + } + child_xl = get_xlator_by_name_or_type(trav->xlator, target, is_name); + if (child_xl) { + /* + * If the xlator we're looking for is somewhere down + * the stack, get_xlator_by_name expects to get a + * pointer to the top of its subtree (child of "this") + * while get_xlator_by_type expects a pointer to what + * we actually found. Handle both cases here. + * + * TBD: rename the functions and fix callers to better + * reflect the difference in semantics. + */ + return is_name ? trav->xlator : child_xl; + } + } + + return NULL; +} - return search; +xlator_t * +get_xlator_by_name(xlator_t *this, char *target) +{ + return get_xlator_by_name_or_type(this, target, 1); } +xlator_t * +get_xlator_by_type(xlator_t *this, char *target) +{ + return get_xlator_by_name_or_type(this, target, 0); +} static int __xlator_init(xlator_t *xl) { - xlator_t *old_THIS = NULL; - int ret = 0; + xlator_t *old_THIS = NULL; + int ret = 0; + int fop_idx = 0; - old_THIS = THIS; - THIS = xl; + old_THIS = THIS; + THIS = xl; - ret = xl->init (xl); + /* initialize the metrics related locks */ + for (fop_idx = 0; fop_idx < GF_FOP_MAXVALUE; fop_idx++) { + GF_ATOMIC_INIT(xl->stats.total.metrics[fop_idx].fop, 0); + GF_ATOMIC_INIT(xl->stats.total.metrics[fop_idx].cbk, 0); - THIS = old_THIS; + GF_ATOMIC_INIT(xl->stats.interval.metrics[fop_idx].fop, 0); + GF_ATOMIC_INIT(xl->stats.interval.metrics[fop_idx].cbk, 0); + } + GF_ATOMIC_INIT(xl->stats.total.count, 0); + GF_ATOMIC_INIT(xl->stats.interval.count, 0); - return ret; -} + xlator_init_lock(); + handle_default_options(xl, xl->options); + ret = xl->init(xl); + xlator_init_unlock(); + THIS = old_THIS; + + return ret; +} int -xlator_init (xlator_t *xl) +xlator_init(xlator_t *xl) { - int32_t ret = 0; + int32_t ret = -1; - if (xl == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return 0; - } + GF_VALIDATE_OR_GOTO("xlator", xl, out); - ret = -1; + if (xl->mem_acct_init) + xl->mem_acct_init(xl); - if (xl->mem_acct_init) - xl->mem_acct_init (xl); + xl->instance_name = NULL; + GF_ATOMIC_INIT(xl->xprtrefcnt, 0); + if (!xl->init) { + gf_smsg(xl->name, GF_LOG_WARNING, 0, LG_MSG_INIT_FAILED, NULL); + goto out; + } - if (!xl->init) { - gf_log (xl->name, GF_LOG_DEBUG, "No init() found"); - goto out; - } + ret = __xlator_init(xl); - ret = __xlator_init (xl); + if (ret) { + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_VOLUME_ERROR, "name=%s", + xl->name, NULL); + goto out; + } - if (ret) { - gf_log (xl->name, GF_LOG_ERROR, - "Initialization of volume '%s' failed," - " review your volfile again", - xl->name); - goto out; + xl->init_succeeded = 1; + /*xl->cleanup_starting = 0; + xl->call_cleanup = 0; + */ + ret = 0; +out: + return ret; +} + +static void +xlator_fini_rec(xlator_t *xl) +{ + xlator_list_t *trav = NULL; + xlator_t *old_THIS = NULL; + + GF_VALIDATE_OR_GOTO("xlator", xl, out); + + trav = xl->children; + + while (trav) { + if (!trav->xlator->init_succeeded) { + break; } - xl->init_succeeded = 1; + xlator_fini_rec(trav->xlator); + gf_msg_debug(trav->xlator->name, 0, "fini done"); + trav = trav->next; + } + + xl->cleanup_starting = 1; + if (xl->init_succeeded) { + if (xl->fini) { + old_THIS = THIS; + THIS = xl; + + xl->fini(xl); + + if (xl->local_pool) { + mem_pool_destroy(xl->local_pool); + xl->local_pool = NULL; + } + if (xl->itable) { + inode_table_destroy(xl->itable); + xl->itable = NULL; + } + + THIS = old_THIS; + } else { + gf_msg_debug(xl->name, 0, "No fini() found"); + } + xl->init_succeeded = 0; + } - ret = 0; out: - return ret; + return; } - -static void -xlator_fini_rec (xlator_t *xl) +int +xlator_notify(xlator_t *xl, int event, void *data, ...) { - xlator_list_t *trav = NULL; - - if (xl == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return; - } - - trav = xl->children; - - while (trav) { - if (!trav->xlator->init_succeeded) { - break; - } - - xlator_fini_rec (trav->xlator); - gf_log (trav->xlator->name, GF_LOG_DEBUG, "fini done"); - trav = trav->next; - } - - if (xl->init_succeeded) { - if (xl->fini) { - xl->fini (xl); - } else { - gf_log (xl->name, GF_LOG_DEBUG, "No fini() found"); - } - xl->init_succeeded = 0; - } + xlator_t *old_THIS = NULL; + int ret = 0; + + old_THIS = THIS; + THIS = xl; + + ret = xl->notify(xl, event, data); + + THIS = old_THIS; + + return ret; } -static int -xlator_reconfigure_rec (xlator_t *old_xl, xlator_t *new_xl) +int +xlator_mem_acct_init(xlator_t *xl, int num_types) { - xlator_list_t *trav1 = NULL; - xlator_list_t *trav2 = NULL; - int32_t ret = 0; + int i = 0; + int ret = 0; - if (old_xl == NULL || new_xl == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return -1; - } + if (!xl) + return -1; - trav1 = old_xl->children; - trav2 = new_xl->children; + if (!xl->ctx) + return -1; - while (trav1 && trav2) { - ret = xlator_reconfigure_rec (trav1->xlator, trav2->xlator); + if (!xl->ctx->mem_acct_enable) + return 0; - if (ret) - goto out; + xl->mem_acct = MALLOC(sizeof(struct mem_acct) + + sizeof(struct mem_acct_rec) * num_types); - gf_log (trav1->xlator->name, GF_LOG_DEBUG, "reconfigured"); + if (!xl->mem_acct) { + return -1; + } - trav1 = trav1->next; - trav2 = trav2->next; - } + xl->mem_acct->num_types = num_types; + GF_ATOMIC_INIT(xl->mem_acct->refcnt, 1); - if (old_xl->reconfigure) { - ret = old_xl->reconfigure (old_xl, new_xl->options); - if (ret) - goto out; + for (i = 0; i < num_types; i++) { + memset(&xl->mem_acct->rec[i], 0, sizeof(struct mem_acct_rec)); + ret = LOCK_INIT(&(xl->mem_acct->rec[i].lock)); + if (ret) { + fprintf(stderr, "Unable to lock..errno : %d", errno); } - else - gf_log (old_xl->name, GF_LOG_DEBUG, "No reconfigure() found"); +#ifdef DEBUG + INIT_LIST_HEAD(&(xl->mem_acct->rec[i].obj_list)); +#endif + } -out: - return ret; + return 0; } -int -xlator_validate_rec (xlator_t *xlator, char **op_errstr) +void +xlator_mem_acct_unref(struct mem_acct *mem_acct) { - xlator_list_t *trav = NULL; - - if (xlator == NULL ) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return -1; + uint32_t i; + + if (GF_ATOMIC_DEC(mem_acct->refcnt) == 0) { + for (i = 0; i < mem_acct->num_types; i++) { + LOCK_DESTROY(&(mem_acct->rec[i].lock)); } + FREE(mem_acct); + } +} - trav = xlator->children; +void +xlator_tree_fini(xlator_t *xl) +{ + xlator_t *top = NULL; - while (trav) { - if (xlator_validate_rec (trav->xlator, op_errstr) ) - return -1; + GF_VALIDATE_OR_GOTO("xlator", xl, out); - trav = trav->next; - } - - if (xlator_dynload (xlator)) - gf_log ("", GF_LOG_DEBUG, "Did not load the symbols"); - - if (xlator->validate_options) { - if (xlator->validate_options (xlator, xlator->options, - op_errstr)) { - gf_log ("", GF_LOG_DEBUG, *op_errstr); - return -1; - } - gf_log (xlator->name, GF_LOG_DEBUG, "Validated option"); - - } - - gf_log (xlator->name, GF_LOG_DEBUG, "No validate_options() found"); + top = xl; + xlator_fini_rec(top); - return 0; +out: + return; } int -graph_reconf_validateopt (glusterfs_graph_t *graph, - char **op_errstr) +xlator_list_destroy(xlator_list_t *list) { - xlator_t *xlator = NULL; - int ret = -1; + xlator_list_t *next = NULL; + + while (list) { + next = list->next; + GF_FREE(list); + list = next; + } + + return 0; +} - GF_ASSERT (graph); +int +xlator_memrec_free(xlator_t *xl) +{ + struct mem_acct *mem_acct = NULL; - xlator = graph->first; + if (!xl) { + return 0; + } + mem_acct = xl->mem_acct; - ret = xlator_validate_rec (xlator, op_errstr); + if (mem_acct) { + xlator_mem_acct_unref(mem_acct); + xl->mem_acct = NULL; + } - return ret; + return 0; } -int -xlator_notify (xlator_t *xl, int event, void *data, ...) + +static int +xlator_members_free(xlator_t *xl) { - xlator_t *old_THIS = NULL; - int ret = 0; + volume_opt_list_t *vol_opt = NULL; + volume_opt_list_t *tmp = NULL; - old_THIS = THIS; - THIS = xl; + if (!xl) + return 0; - ret = xl->notify (xl, event, data); + GF_FREE(xl->name); + GF_FREE(xl->type); + if (!(xl->ctx && xl->ctx->cmd_args.vgtool != _gf_none) && xl->dlhandle) + dlclose(xl->dlhandle); + if (xl->options) + dict_unref(xl->options); - THIS = old_THIS; + xlator_list_destroy(xl->children); - return ret; + xlator_list_destroy(xl->parents); + + list_for_each_entry_safe(vol_opt, tmp, &xl->volume_options, list) + { + list_del_init(&vol_opt->list); + GF_FREE(vol_opt); + } + + return 0; } +/* This function destroys all the xlator members except for the + * xlator strcuture and its mem accounting field. + * + * If otherwise, it would destroy the master xlator object as well + * its mem accounting, which would mean after calling glusterfs_graph_destroy() + * there cannot be any reference to GF_FREE() from the master xlator, this is + * not possible because of the following dependencies: + * - glusterfs_ctx_t will have mem pools allocated by the master xlators + * - xlator objects will have references to those mem pools(g: dict) + * + * Ordering the freeing in any of the order will also not solve the dependency: + * - Freeing xlator objects(including memory accounting) before mem pools + * destruction will mean not use GF_FREE while destroying mem pools. + * - Freeing mem pools and then destroying xlator objects would lead to crashes + * when xlator tries to unref dict or other mem pool objects. + * + * Hence the way chosen out of this interdependency is to split xlator object + * free into two stages: + * - Free all the xlator members excpet for its mem accounting structure + * - Free all the mem accouting structures of xlator along with the xlator + * object itself. + * + * This two stages of destruction, is mainly required for glfs_fini(). + */ int -xlator_mem_acct_init (xlator_t *xl, int num_types) +xlator_tree_free_members(xlator_t *tree) { - int i = 0; - int ret = 0; + xlator_t *trav = tree; + xlator_t *prev = tree; - if (!gf_mem_acct_is_enabled()) - return 0; + if (!tree) { + gf_smsg("parser", GF_LOG_ERROR, 0, LG_MSG_TREE_NOT_FOUND, NULL); + return -1; + } - if (!xl) - return -1; + while (prev) { + trav = prev->next; + xlator_members_free(prev); + prev = trav; + } + + return 0; +} - xl->mem_acct.num_types = num_types; +int +xlator_tree_free_memacct(xlator_t *tree) +{ + xlator_t *trav = tree; + xlator_t *prev = tree; + + if (!tree) { + gf_smsg("parser", GF_LOG_ERROR, 0, LG_MSG_TREE_NOT_FOUND, NULL); + return -1; + } + + while (prev) { + trav = prev->next; + xlator_memrec_free(prev); + GF_FREE(prev); + prev = trav; + } + + return 0; +} - xl->mem_acct.rec = calloc(num_types, sizeof(struct mem_acct_rec)); +static int +xlator_mem_free(xlator_t *xl) +{ + volume_opt_list_t *vol_opt = NULL; + volume_opt_list_t *tmp = NULL; - if (!xl->mem_acct.rec) { - gf_log("xlator", GF_LOG_ERROR, "Out of Memory"); - return -1; - } + if (!xl) + return 0; - for (i = 0; i < num_types; i++) { - ret = LOCK_INIT(&(xl->mem_acct.rec[i].lock)); - if (ret) { - fprintf(stderr, "Unable to lock..errno : %d",errno); - } - } + if (xl->options) { + dict_unref(xl->options); + xl->options = NULL; + } - gf_log(xl->name, GF_LOG_DEBUG, "Allocated mem_acct_rec for %d types", - num_types); + list_for_each_entry_safe(vol_opt, tmp, &xl->volume_options, list) + { + list_del_init(&vol_opt->list); + GF_FREE(vol_opt); + } - return 0; + xlator_memrec_free(xl); + + return 0; } -void -xlator_tree_fini (xlator_t *xl) +static void +xlator_call_fini(xlator_t *this) { - xlator_t *top = NULL; + if (!this || this->call_cleanup) + return; + this->cleanup_starting = 1; + this->call_cleanup = 1; + xlator_call_fini(this->next); + this->fini(this); +} - if (xl == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return; - } +void +xlator_mem_cleanup(xlator_t *this) +{ + xlator_list_t *list = this->children; + xlator_t *trav = list->xlator; + inode_table_t *inode_table = NULL; + xlator_t *prev = trav; + glusterfs_ctx_t *ctx = NULL; + xlator_list_t **trav_p = NULL; + xlator_t *top = NULL; + xlator_t *victim = NULL; + glusterfs_graph_t *graph = NULL; + gf_boolean_t graph_cleanup = _gf_false; + + if (this->call_cleanup || !this->ctx) + return; + + this->call_cleanup = 1; + ctx = this->ctx; + + inode_table = this->itable; + if (inode_table) { + inode_table_destroy(inode_table); + this->itable = NULL; + } + + xlator_call_fini(trav); + + while (prev) { + trav = prev->next; + xlator_mem_free(prev); + prev = trav; + } + + if (this->fini) { + this->fini(this); + } + + xlator_mem_free(this); + + if (ctx->active) { + top = ctx->active->first; + LOCK(&ctx->volfile_lock); + for (trav_p = &top->children; *trav_p; trav_p = &(*trav_p)->next) { + victim = (*trav_p)->xlator; + if (victim->call_cleanup && !strcmp(victim->name, this->name)) { + graph_cleanup = _gf_true; + (*trav_p) = (*trav_p)->next; + break; + } + } + UNLOCK(&ctx->volfile_lock); + } + + if (graph_cleanup) { + prev = this; + graph = ctx->active; + pthread_mutex_lock(&graph->mutex); + while (prev) { + trav = prev->next; + GF_FREE(prev); + prev = trav; + } + pthread_mutex_unlock(&graph->mutex); + } +} - top = xl; - xlator_fini_rec (top); +void +loc_wipe(loc_t *loc) +{ + if (loc->inode) { + inode_unref(loc->inode); + loc->inode = NULL; + } + if (loc->path) { + GF_FREE((char *)loc->path); + loc->path = NULL; + } + + if (loc->parent) { + inode_unref(loc->parent); + loc->parent = NULL; + } + + memset(loc, 0, sizeof(*loc)); } int -xlator_tree_reconfigure (xlator_t *old_xl, xlator_t *new_xl) +loc_path(loc_t *loc, const char *bname) { - xlator_t *new_top = NULL; - xlator_t *old_top = NULL; + int ret = 0; - GF_ASSERT (old_xl); - GF_ASSERT (new_xl); + if (loc->path) + goto out; - old_top = old_xl; - new_top = new_xl; + ret = -1; - return xlator_reconfigure_rec (old_top, new_top); -} + if (bname && !strlen(bname)) + bname = NULL; + if (!bname) + goto inode_path; -int -xlator_tree_free (xlator_t *tree) -{ - xlator_t *trav = tree, *prev = tree; + if (loc->parent && !gf_uuid_is_null(loc->parent->gfid)) { + ret = inode_path(loc->parent, bname, (char **)&loc->path); + } else if (!gf_uuid_is_null(loc->pargfid)) { + ret = gf_asprintf((char **)&loc->path, INODE_PATH_FMT "/%s", + uuid_utoa(loc->pargfid), bname); + } - if (!tree) { - gf_log ("parser", GF_LOG_ERROR, "Translator tree not found"); - return -1; - } - - while (prev) { - trav = prev->next; - dict_destroy (prev->options); - GF_FREE (prev->name); - GF_FREE (prev->type); - GF_FREE (prev); - prev = trav; - } - - return 0; + if (loc->path) + goto out; + +inode_path: + if (loc->inode && !gf_uuid_is_null(loc->inode->gfid)) { + ret = inode_path(loc->inode, NULL, (char **)&loc->path); + } else if (!gf_uuid_is_null(loc->gfid)) { + ret = gf_asprintf((char **)&loc->path, INODE_PATH_FMT, + uuid_utoa(loc->gfid)); + } +out: + return ret; } +void +loc_gfid(loc_t *loc, uuid_t gfid) +{ + if (!gfid) + goto out; + gf_uuid_clear(gfid); + + if (!loc) + goto out; + else if (!gf_uuid_is_null(loc->gfid)) + gf_uuid_copy(gfid, loc->gfid); + else if (loc->inode && (!gf_uuid_is_null(loc->inode->gfid))) + gf_uuid_copy(gfid, loc->inode->gfid); +out: + return; +} void -loc_wipe (loc_t *loc) +loc_pargfid(loc_t *loc, uuid_t gfid) { - if (loc->inode) { - inode_unref (loc->inode); - loc->inode = NULL; - } - if (loc->path) { - GF_FREE ((char *)loc->path); - loc->path = NULL; - } - - if (loc->parent) { - inode_unref (loc->parent); - loc->parent = NULL; - } + if (!gfid) + goto out; + gf_uuid_clear(gfid); + + if (!loc) + goto out; + else if (!gf_uuid_is_null(loc->pargfid)) + gf_uuid_copy(gfid, loc->pargfid); + else if (loc->parent && (!gf_uuid_is_null(loc->parent->gfid))) + gf_uuid_copy(gfid, loc->parent->gfid); +out: + return; +} + +char * +loc_gfid_utoa(loc_t *loc) +{ + uuid_t gfid = { + 0, + }; + loc_gfid(loc, gfid); + return uuid_utoa(gfid); } +int +loc_touchup(loc_t *loc, const char *name) +{ + char *path = NULL; + int ret = 0; + + if (loc->path) + goto out; + + if (loc->parent && name && strlen(name)) { + ret = inode_path(loc->parent, name, &path); + if (path) /*Guaranteed to have trailing '/' */ + loc->name = strrchr(path, '/') + 1; + + if (gf_uuid_is_null(loc->pargfid)) + gf_uuid_copy(loc->pargfid, loc->parent->gfid); + } else if (loc->inode) { + ret = inode_path(loc->inode, 0, &path); + if (gf_uuid_is_null(loc->gfid)) + gf_uuid_copy(loc->gfid, loc->inode->gfid); + } + + if (ret < 0 || !path) { + ret = -ENOMEM; + goto out; + } + + loc->path = path; + ret = 0; +out: + return ret; +} int -loc_copy (loc_t *dst, loc_t *src) +loc_copy_overload_parent(loc_t *dst, loc_t *src, inode_t *parent) { - int ret = -1; + int ret = -1; - dst->ino = src->ino; + GF_VALIDATE_OR_GOTO("xlator", dst, err); + GF_VALIDATE_OR_GOTO("xlator", src, err); + GF_VALIDATE_OR_GOTO("xlator", parent, err); - if (src->inode) - dst->inode = inode_ref (src->inode); + gf_uuid_copy(dst->gfid, src->gfid); + gf_uuid_copy(dst->pargfid, parent->gfid); - if (src->parent) - dst->parent = inode_ref (src->parent); + if (src->inode) + dst->inode = inode_ref(src->inode); - dst->path = gf_strdup (src->path); + if (parent) + dst->parent = inode_ref(parent); - if (!dst->path) - goto out; + if (src->path) { + dst->path = gf_strdup(src->path); - dst->name = strrchr (dst->path, '/'); - if (dst->name) - dst->name++; + if (!dst->path) + goto out; - ret = 0; + if (src->name) + dst->name = strrchr(dst->path, '/'); + if (dst->name) + dst->name++; + } else if (src->name) { + dst->name = src->name; + } + + ret = 0; out: - return ret; -} + if (ret == -1) + loc_wipe(dst); +err: + return ret; +} int -xlator_list_destroy (xlator_list_t *list) +loc_copy(loc_t *dst, loc_t *src) { - xlator_list_t *next = NULL; + int ret = -1; - while (list) { - next = list->next; - GF_FREE (list); - list = next; - } + GF_VALIDATE_OR_GOTO("xlator", dst, err); + GF_VALIDATE_OR_GOTO("xlator", src, err); - return 0; + if (!gf_uuid_is_null(src->gfid)) + gf_uuid_copy(dst->gfid, src->gfid); + else if (src->inode && !gf_uuid_is_null(src->inode->gfid)) + gf_uuid_copy(dst->gfid, src->inode->gfid); + + gf_uuid_copy(dst->pargfid, src->pargfid); + + if (src->inode) + dst->inode = inode_ref(src->inode); + + if (src->parent) + dst->parent = inode_ref(src->parent); + + if (src->path) { + dst->path = gf_strdup(src->path); + + if (!dst->path) + goto out; + + if (src->name) + dst->name = strrchr(dst->path, '/'); + if (dst->name) + dst->name++; + } else if (src->name) { + dst->name = src->name; + } + + ret = 0; +out: + if (ret == -1) + loc_wipe(dst); + +err: + return ret; } +gf_boolean_t +loc_is_root(loc_t *loc) +{ + if (loc && __is_root_gfid(loc->gfid)) { + return _gf_true; + } else if (loc && loc->inode && __is_root_gfid(loc->inode->gfid)) { + return _gf_true; + } -int -xlator_destroy (xlator_t *xl) + return _gf_false; +} + +int32_t +loc_build_child(loc_t *child, loc_t *parent, char *name) { - volume_opt_list_t *vol_opt = NULL; - volume_opt_list_t *tmp = NULL; + int32_t ret = -1; - if (!xl) - return 0; + GF_VALIDATE_OR_GOTO("xlator", child, out); + GF_VALIDATE_OR_GOTO("xlator", parent, out); + GF_VALIDATE_OR_GOTO("xlator", name, out); - if (xl->name) - GF_FREE (xl->name); - if (xl->type) - GF_FREE (xl->type); - if (xl->dlhandle) - dlclose (xl->dlhandle); - if (xl->options) - dict_destroy (xl->options); + loc_gfid(parent, child->pargfid); - xlator_list_destroy (xl->children); + if (strcmp(parent->path, "/") == 0) + ret = gf_asprintf((char **)&child->path, "/%s", name); + else + ret = gf_asprintf((char **)&child->path, "%s/%s", parent->path, name); - xlator_list_destroy (xl->parents); + if (ret < 0 || !child->path) { + ret = -1; + goto out; + } - list_for_each_entry_safe (vol_opt, tmp, &xl->volume_options, list) { - list_del_init (&vol_opt->list); - GF_FREE (vol_opt); - } + child->name = strrchr(child->path, '/') + 1; - GF_FREE (xl); + child->parent = inode_ref(parent->inode); + child->inode = inode_new(parent->inode->table); - return 0; + if (!child->inode) { + ret = -1; + goto out; + } + + ret = 0; + +out: + if ((ret < 0) && child) + loc_wipe(child); + + return ret; +} + +gf_boolean_t +loc_is_nameless(loc_t *loc) +{ + gf_boolean_t ret = _gf_false; + + GF_VALIDATE_OR_GOTO("xlator", loc, out); + + if ((!loc->parent && gf_uuid_is_null(loc->pargfid)) || !loc->name) + ret = _gf_true; +out: + return ret; } + int -is_gf_log_command (xlator_t *this, const char *name, char *value) +xlator_destroy(xlator_t *xl) { - xlator_t *trav = NULL; - char key[1024] = {0,}; - int ret = -1; - int log_level = -1; - gf_boolean_t syslog_flag = 0; - glusterfs_ctx_t *ctx = NULL; - - if (!strcmp ("trusted.glusterfs.syslog", name)) { - ret = gf_string2boolean (value, &syslog_flag); - if (ret) { - ret = EOPNOTSUPP; - goto out; - } - if (syslog_flag) - gf_log_enable_syslog (); - else - gf_log_disable_syslog (); - - goto out; - } + if (!xl) + return 0; - if (fnmatch ("trusted.glusterfs*set-log-level", name, FNM_NOESCAPE)) - goto out; + xlator_members_free(xl); + xlator_memrec_free(xl); + GF_FREE(xl); - log_level = glusterd_check_log_level (value); - if (log_level == -1) { - ret = EOPNOTSUPP; - goto out; - } + return 0; +} + +static int32_t +gf_bin_to_string(char *dst, size_t size, void *src, size_t len) +{ + if (len >= size) { + return EINVAL; + } + + memcpy(dst, src, len); + dst[len] = 0; - /* Some crude way to change the log-level of process */ - if (!strcmp (name, "trusted.glusterfs.set-log-level")) { - /* */ - gf_log ("glusterfs", gf_log_get_loglevel(), - "setting log level to %d (old-value=%d)", - log_level, gf_log_get_loglevel()); - gf_log_set_loglevel (log_level); - ret = 0; - goto out; + return 0; +} + +int +is_gf_log_command(xlator_t *this, const char *name, char *value, size_t size) +{ + xlator_t *trav = NULL; + char key[1024] = { + 0, + }; + int ret = -1; + int log_level = -1; + gf_boolean_t syslog_flag = 0; + glusterfs_ctx_t *ctx = NULL; + + if (!strcmp("trusted.glusterfs.syslog", name)) { + ret = gf_bin_to_string(key, sizeof(key), value, size); + if (ret != 0) { + goto out; } - if (!strcmp (name, "trusted.glusterfs.fuse.set-log-level")) { - /* */ - gf_log (this->name, gf_log_get_xl_loglevel (this), - "setting log level to %d (old-value=%d)", - log_level, gf_log_get_xl_loglevel (this)); - gf_log_set_xl_loglevel (this, log_level); - ret = 0; - goto out; + ret = gf_string2boolean(key, &syslog_flag); + if (ret) { + ret = EOPNOTSUPP; + goto out; } - - ctx = glusterfs_ctx_get(); - if (!ctx) - goto out; - if (!ctx->active) - goto out; - trav = ctx->active->top; - - while (trav) { - snprintf (key, 1024, "trusted.glusterfs.%s.set-log-level", - trav->name); - if (fnmatch (name, key, FNM_NOESCAPE) == 0) { - gf_log (trav->name, gf_log_get_xl_loglevel (trav), - "setting log level to %d (old-value=%d)", - log_level, gf_log_get_xl_loglevel (trav)); - gf_log_set_xl_loglevel (trav, log_level); - ret = 0; - } - trav = trav->next; + if (syslog_flag) + gf_log_enable_syslog(); + else + gf_log_disable_syslog(); + + goto out; + } + + if (fnmatch("trusted.glusterfs*set-log-level", name, FNM_NOESCAPE)) + goto out; + + ret = gf_bin_to_string(key, sizeof(key), value, size); + if (ret != 0) { + goto out; + } + + log_level = glusterd_check_log_level(key); + if (log_level == -1) { + ret = EOPNOTSUPP; + goto out; + } + + /* Some crude way to change the log-level of process */ + if (!strcmp(name, "trusted.glusterfs.set-log-level")) { + gf_smsg("glusterfs", gf_log_get_loglevel(), 0, LG_MSG_SET_LOG_LEVEL, + "new-value=%d", log_level, "old-value=%d", + gf_log_get_loglevel(), NULL); + gf_log_set_loglevel(this->ctx, log_level); + ret = 0; + goto out; + } + + if (!strcmp(name, "trusted.glusterfs.fuse.set-log-level")) { + /* */ + gf_smsg(this->name, gf_log_get_xl_loglevel(this), 0, + LG_MSG_SET_LOG_LEVEL, "new-value=%d", log_level, "old-value=%d", + gf_log_get_xl_loglevel(this), NULL); + gf_log_set_xl_loglevel(this, log_level); + ret = 0; + goto out; + } + + ctx = this->ctx; + if (!ctx) + goto out; + if (!ctx->active) + goto out; + trav = ctx->active->top; + + while (trav) { + snprintf(key, 1024, "trusted.glusterfs.%s.set-log-level", trav->name); + if (fnmatch(name, key, FNM_NOESCAPE) == 0) { + gf_smsg(trav->name, gf_log_get_xl_loglevel(trav), 0, + LG_MSG_SET_LOG_LEVEL, "new-value%d", log_level, + "old-value=%d", gf_log_get_xl_loglevel(trav), NULL); + gf_log_set_xl_loglevel(trav, log_level); + ret = 0; } + trav = trav->next; + } out: - return ret; + return ret; } int -glusterd_check_log_level (const char *value) +glusterd_check_log_level(const char *value) { - int log_level = -1; - - if (!strcasecmp (value, "CRITICAL")) { - log_level = GF_LOG_CRITICAL; - } else if (!strcasecmp (value, "ERROR")) { - log_level = GF_LOG_ERROR; - } else if (!strcasecmp (value, "WARNING")) { - log_level = GF_LOG_WARNING; - } else if (!strcasecmp (value, "INFO")) { - log_level = GF_LOG_INFO; - } else if (!strcasecmp (value, "DEBUG")) { - log_level = GF_LOG_DEBUG; - } else if (!strcasecmp (value, "TRACE")) { - log_level = GF_LOG_TRACE; - } else if (!strcasecmp (value, "NONE")) { - log_level = GF_LOG_NONE; + int log_level = -1; + + if (!strcasecmp(value, "CRITICAL")) { + log_level = GF_LOG_CRITICAL; + } else if (!strcasecmp(value, "ERROR")) { + log_level = GF_LOG_ERROR; + } else if (!strcasecmp(value, "WARNING")) { + log_level = GF_LOG_WARNING; + } else if (!strcasecmp(value, "INFO")) { + log_level = GF_LOG_INFO; + } else if (!strcasecmp(value, "DEBUG")) { + log_level = GF_LOG_DEBUG; + } else if (!strcasecmp(value, "TRACE")) { + log_level = GF_LOG_TRACE; + } else if (!strcasecmp(value, "NONE")) { + log_level = GF_LOG_NONE; + } + + if (log_level == -1) + gf_smsg(THIS->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_INIT, NULL); + + return log_level; +} + +int +xlator_subvolume_count(xlator_t *this) +{ + int i = 0; + xlator_list_t *list = NULL; + + for (list = this->children; list; list = list->next) + i++; + return i; +} + +static int +_copy_opt_to_child(dict_t *options, char *key, data_t *value, void *data) +{ + xlator_t *child = data; + + gf_log(__func__, GF_LOG_DEBUG, "copying %s to child %s", key, child->name); + dict_set(child->options, key, value); + + return 0; +} + +int +copy_opts_to_child(xlator_t *src, xlator_t *dst, char *glob) +{ + return dict_foreach_fnmatch(src->options, glob, _copy_opt_to_child, dst); +} + +int +glusterfs_delete_volfile_checksum(glusterfs_ctx_t *ctx, const char *volfile_id) +{ + gf_volfile_t *volfile_tmp = NULL; + gf_volfile_t *volfile_obj = NULL; + + list_for_each_entry(volfile_tmp, &ctx->volfile_list, volfile_list) + { + if (!strcmp(volfile_id, volfile_tmp->vol_id)) { + list_del_init(&volfile_tmp->volfile_list); + volfile_obj = volfile_tmp; + break; } + } + + if (volfile_obj) { + GF_FREE(volfile_obj); + } else { + gf_log(THIS->name, GF_LOG_ERROR, + "failed to get volfile " + "checksum for volfile id %s.", + volfile_id); + } + + return 0; +} - if (log_level == -1) - gf_log ("", GF_LOG_ERROR, "Invalid log-level. possible values " - "are DEBUG|WARNING|ERROR|CRITICAL|NONE|TRACE"); +/* + The function is required to take dict ref for every xlator at graph. + At the time of compare graph topology create a graph and populate + key values in the dictionary, after finished graph comparison we do destroy + the new graph.At the time of construct graph we don't take any reference + so to avoid dict leak at the of destroying graph due to ref counter underflow + we need to call dict_ref here. - return log_level; +*/ + +void +gluster_graph_take_reference(xlator_t *tree) +{ + xlator_t *trav = tree; + xlator_t *prev = tree; + + if (!tree) { + gf_smsg("parser", GF_LOG_ERROR, 0, LG_MSG_TREE_NOT_FOUND, NULL); + return; + } + + while (prev) { + trav = prev->next; + if (prev->options) + dict_ref(prev->options); + prev = trav; + } + return; +} + +gf_boolean_t +mgmt_is_multiplexed_daemon(char *name) +{ + const char *mux_daemons[] = {"glustershd", NULL}; + int i; + + if (!name) + return _gf_false; + + for (i = 0; mux_daemons[i]; i++) { + if (!strcmp(name, mux_daemons[i])) + return _gf_true; + } + return _gf_false; +} + +gf_boolean_t +xlator_is_cleanup_starting(xlator_t *this) +{ + gf_boolean_t cleanup = _gf_false; + glusterfs_graph_t *graph = NULL; + xlator_t *xl = NULL; + + if (!this) { + gf_smsg("xlator", GF_LOG_WARNING, EINVAL, LG_MSG_OBJECT_NULL, "xlator", + NULL); + goto out; + } + + graph = this->graph; + if (!graph) { + gf_smsg("xlator", GF_LOG_WARNING, EINVAL, LG_MSG_GRAPH_NOT_SET, + "name=%s", this->name, NULL); + goto out; + } + + xl = graph->first; + if (xl && xl->cleanup_starting) + cleanup = _gf_true; +out: + return cleanup; +} + +int +graph_total_client_xlator(glusterfs_graph_t *graph) +{ + xlator_t *xl = NULL; + int count = 0; + + if (!graph) { + gf_smsg("xlator", GF_LOG_WARNING, EINVAL, LG_MSG_OBJECT_NULL, "graph", + NULL); + goto out; + } + + xl = graph->first; + if (!strcmp(xl->type, "protocol/server")) { + gf_msg_debug(xl->name, 0, "Return because it is a server graph"); + return 0; + } + + while (xl) { + if (strcmp(xl->type, "protocol/client") == 0) { + count++; + } + xl = xl->next; + } +out: + return count; } |
